Create and simple listing of all tasks

This commit is contained in:
Sebastian 2023-10-02 10:35:02 +02:00
parent 5082fbcb49
commit a7229d1d9d
7 changed files with 376 additions and 26 deletions

View File

@ -4,17 +4,34 @@
<option name="autoReloadType" value="SELECTIVE" /> <option name="autoReloadType" value="SELECTIVE" />
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="3a869f59-290a-4ab2-b036-a878ce801bc4" name="Changes" comment="Structure Taskgroups in Hierarchies"> <list default="true" id="3a869f59-290a-4ab2-b036-a878ce801bc4" name="Changes" comment="Datastructure for Tasks">
<change afterPath="$PROJECT_DIR$/src/main/java/core/api/controller/TaskController.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../frontend/src/app/taskgroups/taskgroup-creation/taskgroup-creation.component.ts" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/app/taskgroups/taskgroup-creation/taskgroup-creation.component.ts" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/main/java/core/api/models/timemanager/tasks/TaskEntityInfo.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/core/api/models/timemanager/tasks/TaskEntityInfo.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.ts" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.ts" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/main/java/core/entities/timemanager/Task.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/core/entities/timemanager/Task.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/core/entities/timemanager/Taskgroup.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/core/entities/timemanager/Taskgroup.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" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" /> <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" /> <option name="LAST_RESOLUTION" value="IGNORE" />
</component> </component>
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="Interface" />
<option value="Class" />
</list>
</option>
</component>
<component name="Git.Settings"> <component name="Git.Settings">
<option name="RECENT_BRANCH_BY_REPOSITORY">
<map>
<entry key="$PROJECT_DIR$/.." value="master" />
</map>
</option>
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/.." /> <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/.." />
</component> </component>
<component name="ProjectColorInfo">{ <component name="ProjectColorInfo">{
@ -26,28 +43,29 @@
<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-7&quot;, "git-widget-placeholder": "issue-10",
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;, "last_directory_selection": "D:/Programmierprojekte/TimeManager/backend/src/main/java/core/api/models/timemanager",
&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;vue.rearranger.settings.migration&quot;: &quot;true&quot; "node.js.selected.package.tslint": "(autodetect)",
"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" />
@ -76,7 +94,15 @@
<option name="project" value="LOCAL" /> <option name="project" value="LOCAL" />
<updated>1696188127467</updated> <updated>1696188127467</updated>
</task> </task>
<option name="localTasksCounter" value="2" /> <task id="LOCAL-00002" summary="Datastructure for Tasks">
<option name="closed" value="true" />
<created>1696233406235</created>
<option name="number" value="00002" />
<option name="presentableId" value="LOCAL-00002" />
<option name="project" value="LOCAL" />
<updated>1696233406235</updated>
</task>
<option name="localTasksCounter" value="3" />
<servers /> <servers />
</component> </component>
<component name="TypeScriptGeneratedFilesManager"> <component name="TypeScriptGeneratedFilesManager">
@ -84,7 +110,9 @@
</component> </component>
<component name="VcsManagerConfiguration"> <component name="VcsManagerConfiguration">
<MESSAGE value="Structure Taskgroups in Hierarchies" /> <MESSAGE value="Structure Taskgroups in Hierarchies" />
<option name="LAST_COMMIT_MESSAGE" value="Structure Taskgroups in Hierarchies" /> <MESSAGE value="Update gitignore for idea folder" />
<MESSAGE value="Datastructure for Tasks" />
<option name="LAST_COMMIT_MESSAGE" value="Datastructure for Tasks" />
</component> </component>
<component name="XDebuggerManager"> <component name="XDebuggerManager">
<breakpoint-manager> <breakpoint-manager>

View File

@ -0,0 +1,72 @@
package core.api.controller;
import core.api.models.auth.SimpleStatusResponse;
import core.api.models.timemanager.tasks.TaskEntityInfo;
import core.api.models.timemanager.tasks.TaskFieldInfo;
import core.entities.timemanager.Task;
import core.entities.timemanager.Taskgroup;
import core.services.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping("/api")
public class TaskController {
private final TaskService taskService;
private final TaskgroupService taskgroupService;
public TaskController(@Autowired TaskService taskService, @Autowired TaskgroupService taskgroupService) {
this.taskService = taskService;
this.taskgroupService = taskgroupService;
}
@GetMapping("/tasks/{taskgroupID}/{status}")
public ResponseEntity<?> listTasksOfTaskgroup(@PathVariable long taskgroupID, @PathVariable String status) {
PermissionResult<Taskgroup> taskgroupPermissionResult = taskgroupService.getTaskgroupByIDAndUsername(taskgroupID, SecurityContextHolder.getContext().getAuthentication().getName());
if(!taskgroupPermissionResult.isHasPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
}
if(taskgroupPermissionResult.getExitCode() == ServiceExitCode.MISSING_ENTITY) {
return ResponseEntity.status(404).body(new SimpleStatusResponse("failed"));
}
if(status.equalsIgnoreCase("all")) {
return ResponseEntity.ok(taskgroupPermissionResult.getResult().getTasks().stream().map(TaskEntityInfo::new));
} else if(status.equalsIgnoreCase("overdue")) {
//List overdue tasks
return ResponseEntity.ok(new SimpleStatusResponse("success"));
} else if(status.equalsIgnoreCase("upcoming")) {
//List upcoming tasks
return ResponseEntity.ok(new SimpleStatusResponse("success"));
} else {
return ResponseEntity.status(404).body(new SimpleStatusResponse("failed"));
}
}
@PostMapping("/tasks/{taskgroupID}")
public ResponseEntity<?> createTask(@PathVariable long taskgroupID, @RequestBody @Valid TaskFieldInfo taskFieldInfo) {
PermissionResult<Taskgroup> taskgroupPermissionResult = taskgroupService.getTaskgroupByIDAndUsername(taskgroupID, SecurityContextHolder.getContext().getAuthentication().getName());
if(!taskgroupPermissionResult.isHasPermissions()) {
return ResponseEntity.status(403).body(new SimpleStatusResponse("failed"));
}
if(taskgroupPermissionResult.getExitCode() == ServiceExitCode.MISSING_ENTITY) {
return ResponseEntity.status(404).body(new SimpleStatusResponse("failed"));
}
ServiceResult<Task> creationResult = taskService.createTask(taskgroupPermissionResult.getResult(), taskFieldInfo);
if(creationResult.getExitCode() == ServiceExitCode.ENTITY_ALREADY_EXIST) {
return ResponseEntity.status(409).body(new SimpleStatusResponse("failed"));
} else {
return ResponseEntity.ok(new TaskEntityInfo(creationResult.getResult()));
}
}
}

View File

@ -16,12 +16,15 @@ public class TaskEntityInfo {
private LocalDate deadline; private LocalDate deadline;
private boolean overdue;
public TaskEntityInfo(Task task) { public TaskEntityInfo(Task task) {
this.taskID = task.getTaskID(); this.taskID = task.getTaskID();
this.taskName = task.getTaskName(); this.taskName = task.getTaskName();
this.eta = task.getEta(); this.eta = task.getEta();
this.startDate = task.getStartDate(); this.startDate = task.getStartDate();
this.deadline = task.getDeadline(); this.deadline = task.getDeadline();
this.overdue = LocalDate.now().isAfter(task.getDeadline());
} }
public long getTaskID() { public long getTaskID() {
@ -63,4 +66,12 @@ public class TaskEntityInfo {
public void setDeadline(LocalDate deadline) { public void setDeadline(LocalDate deadline) {
this.deadline = deadline; this.deadline = deadline;
} }
public boolean isOverdue() {
return overdue;
}
public void setOverdue(boolean overdue) {
this.overdue = overdue;
}
} }

View File

@ -22,9 +22,12 @@ public class Task {
private int eta; private int eta;
public Task(Taskgroup taskgroup, String taskName) { public Task(Taskgroup taskgroup, String taskName, LocalDate startDate, LocalDate deadline, int eta) {
this.taskgroup = taskgroup; this.taskgroup = taskgroup;
this.taskName = taskName; this.taskName = taskName;
this.startDate = startDate;
this.deadline = deadline;
this.eta = eta;
} }
public Task() { public Task() {

View File

@ -79,4 +79,12 @@ public class Taskgroup {
public void setParent(Taskgroup parent) { public void setParent(Taskgroup parent) {
this.parent = parent; this.parent = parent;
} }
public Set<Task> getTasks() {
return tasks;
}
public void setTasks(Set<Task> tasks) {
this.tasks = tasks;
}
} }

View File

@ -1,9 +1,15 @@
package core.services; package core.services;
import core.api.models.timemanager.tasks.TaskFieldInfo;
import core.entities.timemanager.Task;
import core.entities.timemanager.Taskgroup;
import core.repositories.timemanager.TaskRepository; import core.repositories.timemanager.TaskRepository;
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.util.Collection;
import java.util.List;
@Service @Service
public class TaskService { public class TaskService {
@ -12,4 +18,26 @@ public class TaskService {
public TaskService(@Autowired TaskRepository taskRepository) { public TaskService(@Autowired TaskRepository taskRepository) {
this.taskRepository = taskRepository; this.taskRepository = taskRepository;
} }
public ServiceResult<Task> createTask(Taskgroup taskgroup, TaskFieldInfo taskFieldInfo) {
if(existTaskByName(taskgroup.getTasks(), taskFieldInfo.getTaskName())) {
return new ServiceResult<>(ServiceExitCode.ENTITY_ALREADY_EXIST);
}
Task task = new Task(taskgroup, taskFieldInfo.getTaskName(), taskFieldInfo.getStartDate(), taskFieldInfo.getDeadline(), taskFieldInfo.getEta());
taskgroup.getTasks().add(task);
taskRepository.save(task);
return new ServiceResult<>(task);
}
private boolean existTaskByName(Collection<Task> tasks, String name) {
for(Task task : tasks) {
if(task.getTaskName().equals(name)) {
return true;
}
}
return false;
}
} }

View File

@ -829,6 +829,147 @@ paths:
example: "failed" example: "failed"
enum: enum:
- "failed" - "failed"
/tasks/{taskgroupID}/{status}:
get:
security:
- API_TOKEN: []
tags:
- task
summary: list tasks
description: list tasks
parameters:
- name: taskgroupID
in: path
description: internal id of taskgroup
required: true
schema:
type: number
example: 1
- name: status
in: path
description: scope of listed tasks
required: true
schema:
type: string
enum:
- all
- overdue
- upcoming
example: all
responses:
200:
description: Anfrage erfolgreich
content:
'application/json':
schema:
type: array
items:
$ref: '#/components/schemas/TaskEntityInfo'
403:
description: No permission
content:
'application/json':
schema:
type: object
required:
- status
properties:
status:
type: string
description: Status
example: "failed"
enum:
- "failed"
404:
description: Taskgroup does not exist
content:
'application/json':
schema:
type: object
required:
- status
properties:
status:
type: string
description: Status
example: "failed"
enum:
- "failed"
/tasks/{taskgroupID}:
put:
security:
- API_TOKEN: []
tags:
- task
summary: creates a new task
description: creates tasks
parameters:
- name: taskgroupID
in: path
description: internal id of taskgroup
required: true
schema:
type: number
example: 1
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/TaskFieldInfo'
responses:
200:
description: Anfrage erfolgreich
content:
'application/json':
schema:
type: object
$ref: '#/components/schemas/TaskEntityInfo'
403:
description: No permission
content:
'application/json':
schema:
type: object
required:
- status
properties:
status:
type: string
description: Status
example: "failed"
enum:
- "failed"
404:
description: Taskgroup does not exist
content:
'application/json':
schema:
type: object
required:
- status
properties:
status:
type: string
description: Status
example: "failed"
enum:
- "failed"
409:
description: Task already exist
content:
'application/json':
schema:
type: object
required:
- status
properties:
status:
type: string
description: Status
example: "failed"
enum:
- "failed"
components: components:
securitySchemes: securitySchemes:
API_TOKEN: API_TOKEN:
@ -1051,4 +1192,63 @@ components:
type: number type: number
description: internal id of parent Taskgroup description: internal id of parent Taskgroup
example: 1 example: 1
TaskEntityInfo:
required:
- taskID
- taskName
- eta
- startDate
- deadline
- overdue
additionalProperties: false
properties:
taskID:
type: number
description: internal id of task
example: 1
taskName:
type: string
description: name of task
example: Vorlesung schauen
eta:
type: number
description: expected time to finish task
example: 10
minimum: 0
startDate:
type: string
format: date
description: date from which the task can be started
deadline:
type: string
format: date
description: date until the task has to be finished
overdue:
type: boolean
description: determines whether the task is overdue
example: True
TaskFieldInfo:
required:
- taskName
- eta
- startDate
- deadline
additionalProperties: false
properties:
taskName:
type: string
description: name of task
example: Vorlesung schauen
eta:
type: number
description: expected time to finish task
example: 10
minimum: 0
startDate:
type: string
format: date
description: date from which the task can be started
deadline:
type: string
format: date
description: date until the task has to be finished