From 2d32625d2cbc7a972314bcbdb516145906057576 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 25 Sep 2023 11:02:04 +0200 Subject: [PATCH 01/12] Taskgroup Datamodel --- README.md | 10 +++++ backend/configuration.properties | 0 .../core/entities/timemanager/Taskgroup.java | 40 +++++++++++++++++ .../timemanager/TaskgroupRepository.java | 9 ++++ .../InvalidConfigurationException.java | 2 - .../java/core/services/PropertyService.java | 44 ++++++++++++++++++- .../java/core/services/TaskgroupService.java | 15 +++++++ 7 files changed, 116 insertions(+), 4 deletions(-) delete mode 100644 backend/configuration.properties create mode 100644 backend/src/main/java/core/entities/timemanager/Taskgroup.java create mode 100644 backend/src/main/java/core/repositories/timemanager/TaskgroupRepository.java delete mode 100644 backend/src/main/java/core/services/InvalidConfigurationException.java create mode 100644 backend/src/main/java/core/services/TaskgroupService.java diff --git a/README.md b/README.md index b3b10b8..062ad25 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,12 @@ # TimeManager +Template für einen Spring-Angular-Service +## Generate Angular Client Code with OpenAPI Generator +1. Install the latest version of "openapi-generator-cli" +```bash +npm install @openapitools/openapi-generator-cli -g +``` +2. Generate Code +```bash +npx @openapitools/openapi-generator-cli generate -i openapi.yaml -g typescript-angular -o frontend/src/api/ +``` \ No newline at end of file diff --git a/backend/configuration.properties b/backend/configuration.properties deleted file mode 100644 index e69de29..0000000 diff --git a/backend/src/main/java/core/entities/timemanager/Taskgroup.java b/backend/src/main/java/core/entities/timemanager/Taskgroup.java new file mode 100644 index 0000000..1738a2c --- /dev/null +++ b/backend/src/main/java/core/entities/timemanager/Taskgroup.java @@ -0,0 +1,40 @@ +package core.entities.timemanager; + +import javax.persistence.*; +import javax.validation.constraints.NotBlank; + +@Entity +@Table(name= "taskgroups") +public class Taskgroup { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private long taskgroupID; + + @NotBlank + @Column(name = "name", length = 255) + private String taskgroupName; + + public Taskgroup(String taskgroupName) { + this.taskgroupName = taskgroupName; + } + + public Taskgroup() { + } + + public long getTaskgroupID() { + return taskgroupID; + } + + public void setTaskgroupID(long taskgroupID) { + this.taskgroupID = taskgroupID; + } + + public String getTaskgroupName() { + return taskgroupName; + } + + public void setTaskgroupName(String taskgroupName) { + this.taskgroupName = taskgroupName; + } +} diff --git a/backend/src/main/java/core/repositories/timemanager/TaskgroupRepository.java b/backend/src/main/java/core/repositories/timemanager/TaskgroupRepository.java new file mode 100644 index 0000000..0199806 --- /dev/null +++ b/backend/src/main/java/core/repositories/timemanager/TaskgroupRepository.java @@ -0,0 +1,9 @@ +package core.repositories.timemanager; + +import core.entities.timemanager.Taskgroup; +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface TaskgroupRepository extends CrudRepository { +} diff --git a/backend/src/main/java/core/services/InvalidConfigurationException.java b/backend/src/main/java/core/services/InvalidConfigurationException.java deleted file mode 100644 index 501c4c7..0000000 --- a/backend/src/main/java/core/services/InvalidConfigurationException.java +++ /dev/null @@ -1,2 +0,0 @@ -package core.services;public class InvalidConfigurationException { -} diff --git a/backend/src/main/java/core/services/PropertyService.java b/backend/src/main/java/core/services/PropertyService.java index 7f9dfa3..fda0d25 100644 --- a/backend/src/main/java/core/services/PropertyService.java +++ b/backend/src/main/java/core/services/PropertyService.java @@ -1,14 +1,54 @@ package core.services; import core.api.models.properties.PropertyInfo; +import core.entities.PropertiesEntity; import core.repositories.PropertyRepository; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.parsing.PropertyEntry; import org.springframework.stereotype.Service; import java.util.Optional; - +@Service public class PropertyService { - + @Autowired + private PropertyRepository propertyRepository; + + + + public void init() { + PropertiesEntity registrationEntity = new PropertiesEntity(PropertyName.REGISTRATION_PROPERTY_NAME.name(), true); + if(!propertyRepository.existsByName(registrationEntity.getName())) { + propertyRepository.save(registrationEntity); + } + } + + public Optional getProperty(PropertyName propertyName) { + Optional property = propertyRepository.findByName(propertyName.name()); + return property.map(PropertyInfo::new); + } + + public Optional getPropertyEntityByName(String name) { + return propertyRepository.findByName(name); + } + + public boolean isPropertyEnabled(PropertyName propertyName) { + Optional property = propertyRepository.findByName(propertyName.name()); + return property.map(PropertiesEntity::isStatus).orElseGet(() -> getDefaultBehaivior(propertyName)); + } + + public boolean getDefaultBehaivior(PropertyName propertyName) { + return switch (propertyName) { + case REGISTRATION_PROPERTY_NAME -> true; + }; + } + + public void savePropertyEntity(PropertiesEntity property) { + propertyRepository.save(property); + } + + public enum PropertyName { + REGISTRATION_PROPERTY_NAME + } } diff --git a/backend/src/main/java/core/services/TaskgroupService.java b/backend/src/main/java/core/services/TaskgroupService.java new file mode 100644 index 0000000..aa3f180 --- /dev/null +++ b/backend/src/main/java/core/services/TaskgroupService.java @@ -0,0 +1,15 @@ +package core.services; + +import core.repositories.timemanager.TaskgroupRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class TaskgroupService { + + private final TaskgroupRepository taskgroupRepository; + + public TaskgroupService(@Autowired TaskgroupRepository taskgroupRepository) { + this.taskgroupRepository = taskgroupRepository; + } +} -- 2.34.1 From 3adebd1670326312dab7a01a7cd2c88e6581fdbe Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 25 Sep 2023 11:15:56 +0200 Subject: [PATCH 02/12] Add new Taskgroup (Backend) --- .../api/controller/TaskgroupController.java | 36 ++++++++++++++++++ .../taskgroup/TaskgroupEntityInfo.java | 30 +++++++++++++++ .../taskgroup/TaskgroupFieldInfo.java | 23 ++++++++++++ .../core/entities/timemanager/Taskgroup.java | 2 + .../timemanager/TaskgroupRepository.java | 2 + .../java/core/services/ServiceExitCode.java | 8 ++++ .../java/core/services/ServiceResult.java | 37 +++++++++++++++++++ .../java/core/services/TaskgroupService.java | 15 +++++++- 8 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 backend/src/main/java/core/api/controller/TaskgroupController.java create mode 100644 backend/src/main/java/core/api/models/timemanager/taskgroup/TaskgroupEntityInfo.java create mode 100644 backend/src/main/java/core/api/models/timemanager/taskgroup/TaskgroupFieldInfo.java create mode 100644 backend/src/main/java/core/services/ServiceExitCode.java create mode 100644 backend/src/main/java/core/services/ServiceResult.java diff --git a/backend/src/main/java/core/api/controller/TaskgroupController.java b/backend/src/main/java/core/api/controller/TaskgroupController.java new file mode 100644 index 0000000..3d415f1 --- /dev/null +++ b/backend/src/main/java/core/api/controller/TaskgroupController.java @@ -0,0 +1,36 @@ +package core.api.controller; + +import core.api.models.auth.SimpleStatusResponse; +import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo; +import core.api.models.timemanager.taskgroup.TaskgroupFieldInfo; +import core.entities.timemanager.Taskgroup; +import core.services.ServiceExitCode; +import core.services.ServiceResult; +import core.services.TaskgroupService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +@CrossOrigin(origins = "*", maxAge = 3600) +@RestController +@RequestMapping("/api/settings") +public class TaskgroupController { + + private final TaskgroupService taskgroupService; + + public TaskgroupController(@Autowired TaskgroupService taskgroupService) { + this.taskgroupService = taskgroupService; + } + + @PutMapping("/taskgroups") + public ResponseEntity createTaskgroup(@Valid @RequestBody TaskgroupFieldInfo fieldInfo) { + ServiceResult creationResult = taskgroupService.addTaskgroup(fieldInfo); + if(creationResult.getExitCode() == ServiceExitCode.OK) { + return ResponseEntity.ok(new TaskgroupEntityInfo(creationResult.getResult())); + } else { + return ResponseEntity.status(409).body(new SimpleStatusResponse("failed")); + } + } +} diff --git a/backend/src/main/java/core/api/models/timemanager/taskgroup/TaskgroupEntityInfo.java b/backend/src/main/java/core/api/models/timemanager/taskgroup/TaskgroupEntityInfo.java new file mode 100644 index 0000000..99fd360 --- /dev/null +++ b/backend/src/main/java/core/api/models/timemanager/taskgroup/TaskgroupEntityInfo.java @@ -0,0 +1,30 @@ +package core.api.models.timemanager.taskgroup; + +import core.entities.timemanager.Taskgroup; + +public class TaskgroupEntityInfo { + + private long taskgroupID; + private String taskgroupName; + + public TaskgroupEntityInfo(Taskgroup taskgroup) { + this.taskgroupID = taskgroup.getTaskgroupID(); + this.taskgroupName = taskgroup.getTaskgroupName(); + } + + public long getTaskgroupID() { + return taskgroupID; + } + + public void setTaskgroupID(long taskgroupID) { + this.taskgroupID = taskgroupID; + } + + public String getTaskgroupName() { + return taskgroupName; + } + + public void setTaskgroupName(String taskgroupName) { + this.taskgroupName = taskgroupName; + } +} diff --git a/backend/src/main/java/core/api/models/timemanager/taskgroup/TaskgroupFieldInfo.java b/backend/src/main/java/core/api/models/timemanager/taskgroup/TaskgroupFieldInfo.java new file mode 100644 index 0000000..0c3116d --- /dev/null +++ b/backend/src/main/java/core/api/models/timemanager/taskgroup/TaskgroupFieldInfo.java @@ -0,0 +1,23 @@ +package core.api.models.timemanager.taskgroup; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.Max; +import javax.validation.constraints.NotBlank; + +public class TaskgroupFieldInfo { + + @JsonProperty + @NotBlank + @Length(max = 255) + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/backend/src/main/java/core/entities/timemanager/Taskgroup.java b/backend/src/main/java/core/entities/timemanager/Taskgroup.java index 1738a2c..8be5426 100644 --- a/backend/src/main/java/core/entities/timemanager/Taskgroup.java +++ b/backend/src/main/java/core/entities/timemanager/Taskgroup.java @@ -37,4 +37,6 @@ public class Taskgroup { public void setTaskgroupName(String taskgroupName) { this.taskgroupName = taskgroupName; } + + } diff --git a/backend/src/main/java/core/repositories/timemanager/TaskgroupRepository.java b/backend/src/main/java/core/repositories/timemanager/TaskgroupRepository.java index 0199806..edb84a3 100644 --- a/backend/src/main/java/core/repositories/timemanager/TaskgroupRepository.java +++ b/backend/src/main/java/core/repositories/timemanager/TaskgroupRepository.java @@ -6,4 +6,6 @@ import org.springframework.stereotype.Repository; @Repository public interface TaskgroupRepository extends CrudRepository { + + boolean existsByTaskgroupName(String name); } diff --git a/backend/src/main/java/core/services/ServiceExitCode.java b/backend/src/main/java/core/services/ServiceExitCode.java new file mode 100644 index 0000000..6105f94 --- /dev/null +++ b/backend/src/main/java/core/services/ServiceExitCode.java @@ -0,0 +1,8 @@ +package core.services; + +public enum ServiceExitCode { + + OK, + ENTITY_ALREADY_EXIST, + MISSING_ENTITY; +} diff --git a/backend/src/main/java/core/services/ServiceResult.java b/backend/src/main/java/core/services/ServiceResult.java new file mode 100644 index 0000000..da9e03d --- /dev/null +++ b/backend/src/main/java/core/services/ServiceResult.java @@ -0,0 +1,37 @@ +package core.services; + +public class ServiceResult { + + private ServiceExitCode exitCode; + private T result; + + public ServiceResult(ServiceExitCode exitCode, T result) { + this.exitCode = exitCode; + this.result = result; + } + + public ServiceResult(T result) { + this.result = result; + this.exitCode = ServiceExitCode.OK; + } + + public ServiceResult(ServiceExitCode exitCode) { + this.exitCode = exitCode; + } + + public ServiceExitCode getExitCode() { + return exitCode; + } + + public void setExitCode(ServiceExitCode exitCode) { + this.exitCode = exitCode; + } + + public T getResult() { + return result; + } + + public void setResult(T result) { + this.result = result; + } +} diff --git a/backend/src/main/java/core/services/TaskgroupService.java b/backend/src/main/java/core/services/TaskgroupService.java index aa3f180..516a4d1 100644 --- a/backend/src/main/java/core/services/TaskgroupService.java +++ b/backend/src/main/java/core/services/TaskgroupService.java @@ -1,15 +1,28 @@ package core.services; +import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo; +import core.api.models.timemanager.taskgroup.TaskgroupFieldInfo; +import core.entities.timemanager.Taskgroup; import core.repositories.timemanager.TaskgroupRepository; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.config.Task; import org.springframework.stereotype.Service; @Service public class TaskgroupService { private final TaskgroupRepository taskgroupRepository; - public TaskgroupService(@Autowired TaskgroupRepository taskgroupRepository) { this.taskgroupRepository = taskgroupRepository; } + + public ServiceResult addTaskgroup(TaskgroupFieldInfo taskData) { + if(!taskgroupRepository.existsByTaskgroupName(taskData.getName())) { + Taskgroup taskgroup = new Taskgroup(taskData.getName()); + taskgroupRepository.save(taskgroup); + return new ServiceResult<>(taskgroup); + } else { + return new ServiceResult<>(ServiceExitCode.ENTITY_ALREADY_EXIST); + } + } } -- 2.34.1 From 712f7937365c2563a7904777f3ae55afaeafabd9 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 25 Sep 2023 11:21:09 +0200 Subject: [PATCH 03/12] Include Owner of Taskgroup in Datamodel --- .../api/controller/TaskgroupController.java | 4 +++- .../core/entities/timemanager/Taskgroup.java | 15 ++++++++++++- .../java/core/services/TaskgroupService.java | 21 ++++++++++++++++--- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/backend/src/main/java/core/api/controller/TaskgroupController.java b/backend/src/main/java/core/api/controller/TaskgroupController.java index 3d415f1..856edda 100644 --- a/backend/src/main/java/core/api/controller/TaskgroupController.java +++ b/backend/src/main/java/core/api/controller/TaskgroupController.java @@ -9,6 +9,7 @@ import core.services.ServiceResult; import core.services.TaskgroupService; 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; @@ -26,7 +27,8 @@ public class TaskgroupController { @PutMapping("/taskgroups") public ResponseEntity createTaskgroup(@Valid @RequestBody TaskgroupFieldInfo fieldInfo) { - ServiceResult creationResult = taskgroupService.addTaskgroup(fieldInfo); + String username = SecurityContextHolder.getContext().getAuthentication().getName(); + ServiceResult creationResult = taskgroupService.addTaskgroup(fieldInfo, username); if(creationResult.getExitCode() == ServiceExitCode.OK) { return ResponseEntity.ok(new TaskgroupEntityInfo(creationResult.getResult())); } else { diff --git a/backend/src/main/java/core/entities/timemanager/Taskgroup.java b/backend/src/main/java/core/entities/timemanager/Taskgroup.java index 8be5426..4043f4d 100644 --- a/backend/src/main/java/core/entities/timemanager/Taskgroup.java +++ b/backend/src/main/java/core/entities/timemanager/Taskgroup.java @@ -1,5 +1,7 @@ package core.entities.timemanager; +import core.entities.User; + import javax.persistence.*; import javax.validation.constraints.NotBlank; @@ -15,8 +17,13 @@ public class Taskgroup { @Column(name = "name", length = 255) private String taskgroupName; - public Taskgroup(String taskgroupName) { + @OneToOne + @JoinColumn(name = "taskgroupuser", nullable = false) + private User user; + + public Taskgroup(String taskgroupName, User user) { this.taskgroupName = taskgroupName; + this.user = user; } public Taskgroup() { @@ -38,5 +45,11 @@ public class Taskgroup { this.taskgroupName = taskgroupName; } + public User getUser() { + return user; + } + public void setUser(User user) { + this.user = user; + } } diff --git a/backend/src/main/java/core/services/TaskgroupService.java b/backend/src/main/java/core/services/TaskgroupService.java index 516a4d1..2eae025 100644 --- a/backend/src/main/java/core/services/TaskgroupService.java +++ b/backend/src/main/java/core/services/TaskgroupService.java @@ -2,23 +2,38 @@ package core.services; import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo; import core.api.models.timemanager.taskgroup.TaskgroupFieldInfo; +import core.entities.User; +import core.entities.UserRole; import core.entities.timemanager.Taskgroup; +import core.repositories.UserRepository; import core.repositories.timemanager.TaskgroupRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.config.Task; import org.springframework.stereotype.Service; +import java.util.NoSuchElementException; +import java.util.Optional; + @Service public class TaskgroupService { private final TaskgroupRepository taskgroupRepository; - public TaskgroupService(@Autowired TaskgroupRepository taskgroupRepository) { + private final UserRepository userRepository; + public TaskgroupService(@Autowired TaskgroupRepository taskgroupRepository, + @Autowired UserRepository userRepository) { this.taskgroupRepository = taskgroupRepository; + this.userRepository = userRepository; } - public ServiceResult addTaskgroup(TaskgroupFieldInfo taskData) { + public ServiceResult addTaskgroup(TaskgroupFieldInfo taskData, String username) { + Optional user = userRepository.findByUsername(username); + if(user.isEmpty()) { + throw new NoSuchElementException(); + } + if(!taskgroupRepository.existsByTaskgroupName(taskData.getName())) { - Taskgroup taskgroup = new Taskgroup(taskData.getName()); + + Taskgroup taskgroup = new Taskgroup(taskData.getName(), user.get()); taskgroupRepository.save(taskgroup); return new ServiceResult<>(taskgroup); } else { -- 2.34.1 From 99ae430d2b4db0912ff8f85b6cf3fdadceaa98dc Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 25 Sep 2023 11:36:21 +0200 Subject: [PATCH 04/12] Edit Taskgroup --- .../api/controller/TaskgroupController.java | 20 ++++++++++ .../timemanager/TaskgroupRepository.java | 3 +- .../java/core/services/PermissionResult.java | 40 +++++++++++++++++++ .../java/core/services/TaskgroupService.java | 24 ++++++++++- 4 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 backend/src/main/java/core/services/PermissionResult.java diff --git a/backend/src/main/java/core/api/controller/TaskgroupController.java b/backend/src/main/java/core/api/controller/TaskgroupController.java index 856edda..0448065 100644 --- a/backend/src/main/java/core/api/controller/TaskgroupController.java +++ b/backend/src/main/java/core/api/controller/TaskgroupController.java @@ -4,6 +4,7 @@ import core.api.models.auth.SimpleStatusResponse; import core.api.models.timemanager.taskgroup.TaskgroupEntityInfo; import core.api.models.timemanager.taskgroup.TaskgroupFieldInfo; import core.entities.timemanager.Taskgroup; +import core.services.PermissionResult; import core.services.ServiceExitCode; import core.services.ServiceResult; import core.services.TaskgroupService; @@ -35,4 +36,23 @@ public class TaskgroupController { return ResponseEntity.status(409).body(new SimpleStatusResponse("failed")); } } + + @PostMapping("/taskgroups/{taskgroupID}") + public ResponseEntity editTaskgroup(@PathVariable long taskgroupID, @Valid @RequestBody TaskgroupFieldInfo taskgroupFieldInfo) { + PermissionResult 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")); + } + + ServiceExitCode serviceExitCode = taskgroupService.editTaskgroup(taskgroupPermissionResult.getResult(), taskgroupFieldInfo); + if(serviceExitCode == ServiceExitCode.OK) { + return ResponseEntity.ok(new SimpleStatusResponse("success")); + } else { + return ResponseEntity.status(409).body(new SimpleStatusResponse("failed")); + } + } } diff --git a/backend/src/main/java/core/repositories/timemanager/TaskgroupRepository.java b/backend/src/main/java/core/repositories/timemanager/TaskgroupRepository.java index edb84a3..ddcd272 100644 --- a/backend/src/main/java/core/repositories/timemanager/TaskgroupRepository.java +++ b/backend/src/main/java/core/repositories/timemanager/TaskgroupRepository.java @@ -1,5 +1,6 @@ package core.repositories.timemanager; +import core.entities.User; import core.entities.timemanager.Taskgroup; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; @@ -7,5 +8,5 @@ import org.springframework.stereotype.Repository; @Repository public interface TaskgroupRepository extends CrudRepository { - boolean existsByTaskgroupName(String name); + boolean existsByTaskgroupNameAndUser(String name, User user); } diff --git a/backend/src/main/java/core/services/PermissionResult.java b/backend/src/main/java/core/services/PermissionResult.java new file mode 100644 index 0000000..aafe4ef --- /dev/null +++ b/backend/src/main/java/core/services/PermissionResult.java @@ -0,0 +1,40 @@ +package core.services; + +public class PermissionResult extends ServiceResult { + + private boolean hasPermissions; + public PermissionResult(ServiceExitCode exitCode, T result) { + super(exitCode, result); + } + + public PermissionResult(T result) { + super(result); + } + + public PermissionResult(ServiceExitCode exitCode) { + super(exitCode); + } + + public PermissionResult(ServiceExitCode exitCode, T result, boolean hasPermissions) { + super(exitCode, result); + this.hasPermissions = hasPermissions; + } + + public PermissionResult(T result, boolean hasPermissions) { + super(result); + this.hasPermissions = hasPermissions; + } + + public PermissionResult(ServiceExitCode exitCode, boolean hasPermissions) { + super(exitCode); + this.hasPermissions = hasPermissions; + } + + public boolean isHasPermissions() { + return hasPermissions; + } + + public void setHasPermissions(boolean hasPermissions) { + this.hasPermissions = hasPermissions; + } +} diff --git a/backend/src/main/java/core/services/TaskgroupService.java b/backend/src/main/java/core/services/TaskgroupService.java index 2eae025..20c3579 100644 --- a/backend/src/main/java/core/services/TaskgroupService.java +++ b/backend/src/main/java/core/services/TaskgroupService.java @@ -9,6 +9,7 @@ import core.repositories.UserRepository; import core.repositories.timemanager.TaskgroupRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.config.Task; +import org.springframework.security.core.parameters.P; import org.springframework.stereotype.Service; import java.util.NoSuchElementException; @@ -25,13 +26,19 @@ public class TaskgroupService { this.userRepository = userRepository; } + public PermissionResult getTaskgroupByIDAndUsername(long taskgroupID, String username) { + Optional taskgroup = taskgroupRepository.findById(taskgroupID); + return taskgroup.map(value -> new PermissionResult<>(value, value.getUser().getUsername().equals(username))).orElseGet(() -> + new PermissionResult<>(ServiceExitCode.MISSING_ENTITY)); + } + public ServiceResult addTaskgroup(TaskgroupFieldInfo taskData, String username) { Optional user = userRepository.findByUsername(username); if(user.isEmpty()) { throw new NoSuchElementException(); } - if(!taskgroupRepository.existsByTaskgroupName(taskData.getName())) { + if(!taskgroupRepository.existsByTaskgroupNameAndUser(taskData.getName(), user.get())) { Taskgroup taskgroup = new Taskgroup(taskData.getName(), user.get()); taskgroupRepository.save(taskgroup); @@ -40,4 +47,19 @@ public class TaskgroupService { return new ServiceResult<>(ServiceExitCode.ENTITY_ALREADY_EXIST); } } + + public ServiceExitCode editTaskgroup(Taskgroup taskgroup, TaskgroupFieldInfo taskgroupFieldInfo) { + if(!taskgroup.getTaskgroupName().equals(taskgroupFieldInfo.getName())) { + //Check if another taskgroup with the new name is already existent for the user of the taskgroup + if(!taskgroupRepository.existsByTaskgroupNameAndUser(taskgroupFieldInfo.getName(), taskgroup.getUser())) { + taskgroup.setTaskgroupName(taskgroupFieldInfo.getName()); + taskgroupRepository.save(taskgroup); + return ServiceExitCode.OK; + } else { + return ServiceExitCode.ENTITY_ALREADY_EXIST; + } + } else { + return ServiceExitCode.OK; + } + } } -- 2.34.1 From ad407fb525e778d08cd8e6df8c38e34e7e6e67b5 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 25 Sep 2023 11:39:57 +0200 Subject: [PATCH 05/12] Delete Taskgroup --- .../core/api/controller/TaskgroupController.java | 15 +++++++++++++++ .../main/java/core/services/TaskgroupService.java | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/backend/src/main/java/core/api/controller/TaskgroupController.java b/backend/src/main/java/core/api/controller/TaskgroupController.java index 0448065..bd53a1e 100644 --- a/backend/src/main/java/core/api/controller/TaskgroupController.java +++ b/backend/src/main/java/core/api/controller/TaskgroupController.java @@ -55,4 +55,19 @@ public class TaskgroupController { return ResponseEntity.status(409).body(new SimpleStatusResponse("failed")); } } + + @DeleteMapping("/taskgroups/{taskgroupID}") + public ResponseEntity deleteTaskgroup(@PathVariable long taskgroupID) { + PermissionResult 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")); + } + + taskgroupService.deleteTaskgroup(taskgroupPermissionResult.getResult()); + return ResponseEntity.ok(new SimpleStatusResponse("success")); + } } diff --git a/backend/src/main/java/core/services/TaskgroupService.java b/backend/src/main/java/core/services/TaskgroupService.java index 20c3579..5a224cd 100644 --- a/backend/src/main/java/core/services/TaskgroupService.java +++ b/backend/src/main/java/core/services/TaskgroupService.java @@ -62,4 +62,8 @@ public class TaskgroupService { return ServiceExitCode.OK; } } + + public void deleteTaskgroup(Taskgroup taskgroup) { + taskgroupRepository.delete(taskgroup); + } } -- 2.34.1 From e1b44cb92c0ad7b5cc888e5c0dc0d95d92706e98 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 25 Sep 2023 11:45:33 +0200 Subject: [PATCH 06/12] List all Taskgroups of a User --- .../java/core/api/controller/TaskgroupController.java | 8 ++++++++ .../repositories/timemanager/TaskgroupRepository.java | 6 ++++++ backend/src/main/java/core/services/TaskgroupService.java | 5 +++++ 3 files changed, 19 insertions(+) diff --git a/backend/src/main/java/core/api/controller/TaskgroupController.java b/backend/src/main/java/core/api/controller/TaskgroupController.java index bd53a1e..8841c8b 100644 --- a/backend/src/main/java/core/api/controller/TaskgroupController.java +++ b/backend/src/main/java/core/api/controller/TaskgroupController.java @@ -14,6 +14,7 @@ import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; +import java.util.List; @CrossOrigin(origins = "*", maxAge = 3600) @RestController @@ -70,4 +71,11 @@ public class TaskgroupController { taskgroupService.deleteTaskgroup(taskgroupPermissionResult.getResult()); return ResponseEntity.ok(new SimpleStatusResponse("success")); } + + @GetMapping("/taskgroups") + public ResponseEntity> listTaskgroupsOfUser() { + List taskgroups = taskgroupService.getTaskgroupsByUser(SecurityContextHolder.getContext().getAuthentication().getName()); + List taskgroupEntityInfos = taskgroups.stream().map(TaskgroupEntityInfo::new).toList(); + return ResponseEntity.ok(taskgroupEntityInfos); + } } diff --git a/backend/src/main/java/core/repositories/timemanager/TaskgroupRepository.java b/backend/src/main/java/core/repositories/timemanager/TaskgroupRepository.java index ddcd272..6441145 100644 --- a/backend/src/main/java/core/repositories/timemanager/TaskgroupRepository.java +++ b/backend/src/main/java/core/repositories/timemanager/TaskgroupRepository.java @@ -2,11 +2,17 @@ package core.repositories.timemanager; import core.entities.User; import core.entities.timemanager.Taskgroup; +import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface TaskgroupRepository extends CrudRepository { boolean existsByTaskgroupNameAndUser(String name, User user); + + @Query("SELECT tg FROM Taskgroup tg WHERE tg.user.username = ?1") + List findAllByUser(String username); } diff --git a/backend/src/main/java/core/services/TaskgroupService.java b/backend/src/main/java/core/services/TaskgroupService.java index 5a224cd..07cd12e 100644 --- a/backend/src/main/java/core/services/TaskgroupService.java +++ b/backend/src/main/java/core/services/TaskgroupService.java @@ -12,6 +12,7 @@ import org.springframework.scheduling.config.Task; import org.springframework.security.core.parameters.P; import org.springframework.stereotype.Service; +import java.util.List; import java.util.NoSuchElementException; import java.util.Optional; @@ -66,4 +67,8 @@ public class TaskgroupService { public void deleteTaskgroup(Taskgroup taskgroup) { taskgroupRepository.delete(taskgroup); } + + public List getTaskgroupsByUser(String username) { + return taskgroupRepository.findAllByUser(username); + } } -- 2.34.1 From 9a67dfb875bb2c1daaf7b7b4000a91b2c55834fb Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 25 Sep 2023 11:49:28 +0200 Subject: [PATCH 07/12] Delete Taskgroups when deleting corresponding user --- .../core/repositories/timemanager/TaskgroupRepository.java | 6 ++++++ backend/src/main/java/core/services/TaskgroupService.java | 4 ++++ backend/src/main/java/core/services/UserService.java | 3 +++ 3 files changed, 13 insertions(+) diff --git a/backend/src/main/java/core/repositories/timemanager/TaskgroupRepository.java b/backend/src/main/java/core/repositories/timemanager/TaskgroupRepository.java index 6441145..4c17014 100644 --- a/backend/src/main/java/core/repositories/timemanager/TaskgroupRepository.java +++ b/backend/src/main/java/core/repositories/timemanager/TaskgroupRepository.java @@ -2,10 +2,12 @@ package core.repositories.timemanager; import core.entities.User; import core.entities.timemanager.Taskgroup; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; +import javax.transaction.Transactional; import java.util.List; @Repository @@ -15,4 +17,8 @@ public interface TaskgroupRepository extends CrudRepository { @Query("SELECT tg FROM Taskgroup tg WHERE tg.user.username = ?1") List findAllByUser(String username); + + @Modifying + @Transactional + void deleteAllByUser(User user); } diff --git a/backend/src/main/java/core/services/TaskgroupService.java b/backend/src/main/java/core/services/TaskgroupService.java index 07cd12e..d5031c8 100644 --- a/backend/src/main/java/core/services/TaskgroupService.java +++ b/backend/src/main/java/core/services/TaskgroupService.java @@ -71,4 +71,8 @@ public class TaskgroupService { public List getTaskgroupsByUser(String username) { return taskgroupRepository.findAllByUser(username); } + + public void deleteTaskgroupByUser(User user) { + taskgroupRepository.deleteAllByUser(user); + } } diff --git a/backend/src/main/java/core/services/UserService.java b/backend/src/main/java/core/services/UserService.java index 2ed47f9..e149fbe 100644 --- a/backend/src/main/java/core/services/UserService.java +++ b/backend/src/main/java/core/services/UserService.java @@ -9,6 +9,7 @@ import core.api.models.users.UserUpdateInfo; import core.entities.RoleEntity; import core.entities.User; import core.entities.UserRole; +import core.entities.timemanager.Taskgroup; import core.repositories.RoleRepository; import core.repositories.UserRepository; import org.springframework.beans.factory.annotation.Autowired; @@ -29,6 +30,7 @@ public class UserService { @Autowired private RoleRepository roleRepository; + @Autowired private TaskgroupService taskgroupService; public List getAllUserInfos() { Iterable users = userRepository.findAll(); @@ -146,6 +148,7 @@ public class UserService { return 2; } + taskgroupService.deleteTaskgroupByUser(requestedUser.get()); userRepository.deleteByUsername(username); return 0; } -- 2.34.1 From c2a95a1d1339f2b83125a6b2877dd6dc7ace6a74 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 25 Sep 2023 12:01:24 +0200 Subject: [PATCH 08/12] Document API --- .../api/controller/TaskgroupController.java | 2 +- openapi.yaml | 213 +++++++++++++++++- 2 files changed, 213 insertions(+), 2 deletions(-) diff --git a/backend/src/main/java/core/api/controller/TaskgroupController.java b/backend/src/main/java/core/api/controller/TaskgroupController.java index 8841c8b..d6fedf4 100644 --- a/backend/src/main/java/core/api/controller/TaskgroupController.java +++ b/backend/src/main/java/core/api/controller/TaskgroupController.java @@ -18,7 +18,7 @@ import java.util.List; @CrossOrigin(origins = "*", maxAge = 3600) @RestController -@RequestMapping("/api/settings") +@RequestMapping("/api") public class TaskgroupController { private final TaskgroupService taskgroupService; diff --git a/openapi.yaml b/openapi.yaml index fd9e9a6..ec92816 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -564,6 +564,190 @@ paths: example: "failed" enum: - "failed" + /taskgroups: + get: + security: + - API_TOKEN: [] + tags: + - taskgroup + summary: list all taskgroups of authorized user + description: list all taskgroups of authorized user + responses: + 200: + description: Anfrage erfolgreich + content: + 'application/json': + schema: + type: array + items: + $ref: '#/components/schemas/TaskgroupEntityInfo' + put: + security: + - API_TOKEN: [] + tags: + - taskgroup + summary: creates taskgroup + description: creates taskgroup + responses: + 200: + description: Anfrage erfolgreich + content: + 'application/json': + schema: + $ref: '#/components/schemas/TaskgroupEntityInfo' + 409: + description: Taskgroup already exists + content: + application/json: + schema: + type: object + required: + - status + properties: + status: + type: string + description: Status + example: "failed" + enum: + - "failed" + /taskgroups/{taskgroupID}: + post: + security: + - API_TOKEN: [] + tags: + - taskgroup + summary: edits taskgroup + description: edits taskgroup + parameters: + - name: taskgroupID + in: path + description: internal id of taskgroup + required: true + schema: + type: number + example: 1 + responses: + 200: + description: Anfrage erfolgreich + content: + 'application/json': + schema: + type: object + required: + - status + properties: + status: + type: string + description: Status + example: "success" + enum: + - "success" + 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: Taskgroup with that new name already exists + content: + 'application/json': + schema: + type: object + required: + - status + properties: + status: + type: string + description: Status + example: "failed" + enum: + - "failed" + delete: + security: + - API_TOKEN: [] + tags: + - taskgroup + summary: deletes taskgroup + description: deletes taskgroup + parameters: + - name: taskgroupID + in: path + description: internal id of taskgroup + required: true + schema: + type: number + example: 1 + responses: + 200: + description: Anfrage erfolgreich + content: + 'application/json': + schema: + type: object + required: + - status + properties: + status: + type: string + description: Status + example: "success" + enum: + - "success" + 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" components: securitySchemes: API_TOKEN: @@ -749,4 +933,31 @@ components: settings: type: array items: - $ref: '#/components/schemas/PropertyInfo' \ No newline at end of file + $ref: '#/components/schemas/PropertyInfo' + TaskgroupEntityInfo: + required: + - taskgroupID + - taskgroupName + additionalProperties: false + properties: + taskgroupID: + type: number + description: internal id of taskgroup + example: 1 + taskgroupName: + type: string + description: name of taskgroup + example: Taskgroup 1 + maxLength: 255 + minLength: 1 + TaskgroupFieldInfo: + required: + - name + additionalProperties: false + properties: + name: + type: string + description: name of taskgroup + example: Taskgroup 1 + maxLength: 255 + minLength: 1 \ No newline at end of file -- 2.34.1 From e062ddd26620b12996004c554473801ff4ab0d80 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 25 Sep 2023 12:15:47 +0200 Subject: [PATCH 09/12] Create TaskgroupDashboard Component and routing to it --- frontend/src/app/app-routing.module.ts | 4 ++- frontend/src/app/app.component.html | 7 +++++- frontend/src/app/app.module.ts | 4 ++- .../taskgroup-dashboard.component.css | 0 .../taskgroup-dashboard.component.html | 1 + .../taskgroup-dashboard.component.spec.ts | 25 +++++++++++++++++++ .../taskgroup-dashboard.component.ts | 15 +++++++++++ 7 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.css create mode 100644 frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.html create mode 100644 frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.spec.ts create mode 100644 frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.ts diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index b03ec72..47103b6 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -4,11 +4,13 @@ import {AppComponent} from "./app.component"; import {AdminDashboardComponent} from "./admin-dashboard/admin-dashboard.component"; import {MainComponent} from "./main/main.component"; import {UserSettingsComponent} from "./user-settings/user-settings.component"; +import {TaskgroupDashboardComponent} from "./taskgroups/taskgroup-dashboard/taskgroup-dashboard.component"; const routes: Routes = [ {path: '', component: MainComponent}, {path: 'admin', component: AdminDashboardComponent}, - {path: 'user/settings', component: UserSettingsComponent} + {path: 'user/settings', component: UserSettingsComponent}, + {path: 'taskgroups', component: TaskgroupDashboardComponent} ]; @NgModule({ diff --git a/frontend/src/app/app.component.html b/frontend/src/app/app.component.html index f32869d..b4f5177 100644 --- a/frontend/src/app/app.component.html +++ b/frontend/src/app/app.component.html @@ -1,5 +1,10 @@ - Spring Angular Demo + TimeManager + + + + + diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index a2b3d4e..3bd5527 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -36,6 +36,7 @@ import { DeleteAccountComponent } from './user-settings/account-settings/delete- import { RegistrationComponent } from './auth/registration/registration.component'; import { SettingsComponent } from './admin-dashboard/settings/settings.component'; import {MatListModule} from "@angular/material/list"; +import { TaskgroupDashboardComponent } from './taskgroups/taskgroup-dashboard/taskgroup-dashboard.component'; @NgModule({ declarations: [ @@ -52,7 +53,8 @@ import {MatListModule} from "@angular/material/list"; ManageEmailComponent, DeleteAccountComponent, RegistrationComponent, - SettingsComponent + SettingsComponent, + TaskgroupDashboardComponent ], imports: [ BrowserModule, diff --git a/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.css b/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.css new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.html b/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.html new file mode 100644 index 0000000..1aae99a --- /dev/null +++ b/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.html @@ -0,0 +1 @@ +

taskgroup-dashboard works!

diff --git a/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.spec.ts b/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.spec.ts new file mode 100644 index 0000000..4ec2ce3 --- /dev/null +++ b/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TaskgroupDashboardComponent } from './taskgroup-dashboard.component'; + +describe('TaskgroupDashboardComponent', () => { + let component: TaskgroupDashboardComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ TaskgroupDashboardComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(TaskgroupDashboardComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.ts b/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.ts new file mode 100644 index 0000000..c8f32eb --- /dev/null +++ b/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-taskgroup-dashboard', + templateUrl: './taskgroup-dashboard.component.html', + styleUrls: ['./taskgroup-dashboard.component.css'] +}) +export class TaskgroupDashboardComponent implements OnInit { + + constructor() { } + + ngOnInit(): void { + } + +} -- 2.34.1 From fa7d7d503a84a937dfa4fe8c5643e9273b93fe1f Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 25 Sep 2023 12:46:45 +0200 Subject: [PATCH 10/12] Component for adding Taskgroups --- frontend/src/api/.openapi-generator/FILES | 3 + frontend/src/api/api.module.ts | 1 + frontend/src/api/api/api.ts | 4 +- frontend/src/api/api/taskgroup.service.ts | 341 ++++++++++++++++++ frontend/src/api/model/models.ts | 2 + frontend/src/api/model/taskgroupEntityInfo.ts | 24 ++ frontend/src/api/model/taskgroupFieldInfo.ts | 20 + frontend/src/app/app.module.ts | 4 +- .../taskgroup-creation.component.css | 3 + .../taskgroup-creation.component.html | 13 + .../taskgroup-creation.component.spec.ts | 25 ++ .../taskgroup-creation.component.ts | 49 +++ .../taskgroup-dashboard.component.css | 28 ++ .../taskgroup-dashboard.component.html | 11 +- .../taskgroup-dashboard.component.ts | 7 +- openapi.yaml | 10 + 16 files changed, 541 insertions(+), 4 deletions(-) create mode 100644 frontend/src/api/api/taskgroup.service.ts create mode 100644 frontend/src/api/model/taskgroupEntityInfo.ts create mode 100644 frontend/src/api/model/taskgroupFieldInfo.ts create mode 100644 frontend/src/app/taskgroups/taskgroup-creation/taskgroup-creation.component.css create mode 100644 frontend/src/app/taskgroups/taskgroup-creation/taskgroup-creation.component.html create mode 100644 frontend/src/app/taskgroups/taskgroup-creation/taskgroup-creation.component.spec.ts create mode 100644 frontend/src/app/taskgroups/taskgroup-creation/taskgroup-creation.component.ts diff --git a/frontend/src/api/.openapi-generator/FILES b/frontend/src/api/.openapi-generator/FILES index 25f6fa7..8f617f7 100644 --- a/frontend/src/api/.openapi-generator/FILES +++ b/frontend/src/api/.openapi-generator/FILES @@ -5,6 +5,7 @@ api/account.service.ts api/api.ts api/login.service.ts api/properties.service.ts +api/taskgroup.service.ts api/users.service.ts configuration.ts encoder.ts @@ -24,6 +25,8 @@ model/propertiesInfo.ts model/propertyInfo.ts model/propertyUpdateRequest.ts model/signUpRequest.ts +model/taskgroupEntityInfo.ts +model/taskgroupFieldInfo.ts model/userAddInfo.ts model/userInfo.ts model/userUpdateInfo.ts diff --git a/frontend/src/api/api.module.ts b/frontend/src/api/api.module.ts index 187ee74..a695643 100644 --- a/frontend/src/api/api.module.ts +++ b/frontend/src/api/api.module.ts @@ -5,6 +5,7 @@ import { HttpClient } from '@angular/common/http'; import { AccountService } from './api/account.service'; import { LoginService } from './api/login.service'; import { PropertiesService } from './api/properties.service'; +import { TaskgroupService } from './api/taskgroup.service'; import { UsersService } from './api/users.service'; @NgModule({ diff --git a/frontend/src/api/api/api.ts b/frontend/src/api/api/api.ts index af6d936..e3102eb 100644 --- a/frontend/src/api/api/api.ts +++ b/frontend/src/api/api/api.ts @@ -4,6 +4,8 @@ export * from './login.service'; import { LoginService } from './login.service'; export * from './properties.service'; import { PropertiesService } from './properties.service'; +export * from './taskgroup.service'; +import { TaskgroupService } from './taskgroup.service'; export * from './users.service'; import { UsersService } from './users.service'; -export const APIS = [AccountService, LoginService, PropertiesService, UsersService]; +export const APIS = [AccountService, LoginService, PropertiesService, TaskgroupService, UsersService]; diff --git a/frontend/src/api/api/taskgroup.service.ts b/frontend/src/api/api/taskgroup.service.ts new file mode 100644 index 0000000..2d00598 --- /dev/null +++ b/frontend/src/api/api/taskgroup.service.ts @@ -0,0 +1,341 @@ +/** + * 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 { InlineResponse200 } from '../model/models'; +import { InlineResponse403 } from '../model/models'; +import { TaskgroupEntityInfo } from '../model/models'; +import { TaskgroupFieldInfo } from '../model/models'; + +import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; +import { Configuration } from '../configuration'; + + + +@Injectable({ + providedIn: 'root' +}) +export class TaskgroupService { + + 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; + } + + /** + * list all taskgroups of authorized user + * list all taskgroups of authorized user + * @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 taskgroupsGet(observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; + public taskgroupsGet(observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>>; + public taskgroupsGet(observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>>; + public taskgroupsGet(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}/taskgroups`, + { + context: localVarHttpContext, + responseType: responseType_, + withCredentials: this.configuration.withCredentials, + headers: localVarHeaders, + observe: observe, + reportProgress: reportProgress + } + ); + } + + /** + * creates taskgroup + * creates taskgroup + * @param taskgroupFieldInfo + * @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 taskgroupsPut(taskgroupFieldInfo?: TaskgroupFieldInfo, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable; + public taskgroupsPut(taskgroupFieldInfo?: TaskgroupFieldInfo, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; + public taskgroupsPut(taskgroupFieldInfo?: TaskgroupFieldInfo, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; + public taskgroupsPut(taskgroupFieldInfo?: TaskgroupFieldInfo, 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(); + } + + + // to determine the Content-Type header + const consumes: string[] = [ + 'application/json' + ]; + const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected !== undefined) { + localVarHeaders = localVarHeaders.set('Content-Type', httpContentTypeSelected); + } + + let responseType_: 'text' | 'json' = 'json'; + if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) { + responseType_ = 'text'; + } + + return this.httpClient.put(`${this.configuration.basePath}/taskgroups`, + taskgroupFieldInfo, + { + context: localVarHttpContext, + responseType: responseType_, + withCredentials: this.configuration.withCredentials, + headers: localVarHeaders, + observe: observe, + reportProgress: reportProgress + } + ); + } + + /** + * deletes taskgroup + * deletes taskgroup + * @param taskgroupID internal id of taskgroup + * @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 taskgroupsTaskgroupIDDelete(taskgroupID: number, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable; + public taskgroupsTaskgroupIDDelete(taskgroupID: number, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; + public taskgroupsTaskgroupIDDelete(taskgroupID: number, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; + public taskgroupsTaskgroupIDDelete(taskgroupID: number, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable { + if (taskgroupID === null || taskgroupID === undefined) { + throw new Error('Required parameter taskgroupID was null or undefined when calling taskgroupsTaskgroupIDDelete.'); + } + + 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.delete(`${this.configuration.basePath}/taskgroups/${encodeURIComponent(String(taskgroupID))}`, + { + context: localVarHttpContext, + responseType: responseType_, + withCredentials: this.configuration.withCredentials, + headers: localVarHeaders, + observe: observe, + reportProgress: reportProgress + } + ); + } + + /** + * edits taskgroup + * edits taskgroup + * @param taskgroupID internal id of taskgroup + * @param taskgroupFieldInfo + * @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 taskgroupsTaskgroupIDPost(taskgroupID: number, taskgroupFieldInfo?: TaskgroupFieldInfo, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable; + public taskgroupsTaskgroupIDPost(taskgroupID: number, taskgroupFieldInfo?: TaskgroupFieldInfo, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; + public taskgroupsTaskgroupIDPost(taskgroupID: number, taskgroupFieldInfo?: TaskgroupFieldInfo, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; + public taskgroupsTaskgroupIDPost(taskgroupID: number, taskgroupFieldInfo?: TaskgroupFieldInfo, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable { + if (taskgroupID === null || taskgroupID === undefined) { + throw new Error('Required parameter taskgroupID was null or undefined when calling taskgroupsTaskgroupIDPost.'); + } + + 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(); + } + + + // to determine the Content-Type header + const consumes: string[] = [ + 'application/json' + ]; + const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected !== undefined) { + localVarHeaders = localVarHeaders.set('Content-Type', httpContentTypeSelected); + } + + let responseType_: 'text' | 'json' = 'json'; + if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) { + responseType_ = 'text'; + } + + return this.httpClient.post(`${this.configuration.basePath}/taskgroups/${encodeURIComponent(String(taskgroupID))}`, + taskgroupFieldInfo, + { + context: localVarHttpContext, + responseType: responseType_, + withCredentials: this.configuration.withCredentials, + headers: localVarHeaders, + observe: observe, + reportProgress: reportProgress + } + ); + } + +} diff --git a/frontend/src/api/model/models.ts b/frontend/src/api/model/models.ts index 653f5dc..adcbb18 100644 --- a/frontend/src/api/model/models.ts +++ b/frontend/src/api/model/models.ts @@ -11,6 +11,8 @@ export * from './propertiesInfo'; export * from './propertyInfo'; export * from './propertyUpdateRequest'; export * from './signUpRequest'; +export * from './taskgroupEntityInfo'; +export * from './taskgroupFieldInfo'; export * from './userAddInfo'; export * from './userInfo'; export * from './userUpdateInfo'; diff --git a/frontend/src/api/model/taskgroupEntityInfo.ts b/frontend/src/api/model/taskgroupEntityInfo.ts new file mode 100644 index 0000000..bbec6ed --- /dev/null +++ b/frontend/src/api/model/taskgroupEntityInfo.ts @@ -0,0 +1,24 @@ +/** + * 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 TaskgroupEntityInfo { + /** + * internal id of taskgroup + */ + taskgroupID: number; + /** + * name of taskgroup + */ + taskgroupName: string; +} + diff --git a/frontend/src/api/model/taskgroupFieldInfo.ts b/frontend/src/api/model/taskgroupFieldInfo.ts new file mode 100644 index 0000000..66c2b15 --- /dev/null +++ b/frontend/src/api/model/taskgroupFieldInfo.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 TaskgroupFieldInfo { + /** + * name of taskgroup + */ + name: string; +} + diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 3bd5527..1a9d282 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -37,6 +37,7 @@ import { RegistrationComponent } from './auth/registration/registration.componen import { SettingsComponent } from './admin-dashboard/settings/settings.component'; import {MatListModule} from "@angular/material/list"; import { TaskgroupDashboardComponent } from './taskgroups/taskgroup-dashboard/taskgroup-dashboard.component'; +import { TaskgroupCreationComponent } from './taskgroups/taskgroup-creation/taskgroup-creation.component'; @NgModule({ declarations: [ @@ -54,7 +55,8 @@ import { TaskgroupDashboardComponent } from './taskgroups/taskgroup-dashboard/ta DeleteAccountComponent, RegistrationComponent, SettingsComponent, - TaskgroupDashboardComponent + TaskgroupDashboardComponent, + TaskgroupCreationComponent ], imports: [ BrowserModule, diff --git a/frontend/src/app/taskgroups/taskgroup-creation/taskgroup-creation.component.css b/frontend/src/app/taskgroups/taskgroup-creation/taskgroup-creation.component.css new file mode 100644 index 0000000..820cdcf --- /dev/null +++ b/frontend/src/app/taskgroups/taskgroup-creation/taskgroup-creation.component.css @@ -0,0 +1,3 @@ +.mat-form-field { + width: 100%; +} diff --git a/frontend/src/app/taskgroups/taskgroup-creation/taskgroup-creation.component.html b/frontend/src/app/taskgroups/taskgroup-creation/taskgroup-creation.component.html new file mode 100644 index 0000000..266d467 --- /dev/null +++ b/frontend/src/app/taskgroups/taskgroup-creation/taskgroup-creation.component.html @@ -0,0 +1,13 @@ +

Create New Taskgroup

+
+ + Name + + {{nameCtrl.value.length}} / 255 + +
+ +
+ + +
diff --git a/frontend/src/app/taskgroups/taskgroup-creation/taskgroup-creation.component.spec.ts b/frontend/src/app/taskgroups/taskgroup-creation/taskgroup-creation.component.spec.ts new file mode 100644 index 0000000..52708f0 --- /dev/null +++ b/frontend/src/app/taskgroups/taskgroup-creation/taskgroup-creation.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TaskgroupCreationComponent } from './taskgroup-creation.component'; + +describe('TaskgroupCreationComponent', () => { + let component: TaskgroupCreationComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ TaskgroupCreationComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(TaskgroupCreationComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/taskgroups/taskgroup-creation/taskgroup-creation.component.ts b/frontend/src/app/taskgroups/taskgroup-creation/taskgroup-creation.component.ts new file mode 100644 index 0000000..45bc353 --- /dev/null +++ b/frontend/src/app/taskgroups/taskgroup-creation/taskgroup-creation.component.ts @@ -0,0 +1,49 @@ +import { Component, OnInit } from '@angular/core'; +import {FormControl, Validators} from "@angular/forms"; +import {MatDialogRef} from "@angular/material/dialog"; +import {TaskgroupService} from "../../../api"; +import {error} from "@angular/compiler/src/util"; +import {MatSnackBar} from "@angular/material/snack-bar"; + +@Component({ + selector: 'app-taskgroup-creation', + templateUrl: './taskgroup-creation.component.html', + styleUrls: ['./taskgroup-creation.component.css'] +}) +export class TaskgroupCreationComponent implements OnInit { + + nameCtrl = new FormControl('', [Validators.required, Validators.maxLength(255)]) + pending: boolean = false + + constructor(private dialogRef: MatDialogRef, + private taskgroupService: TaskgroupService, + private snackbar: MatSnackBar) { } + + ngOnInit(): void { + } + + cancel() { + this.dialogRef.close(); + } + + save() { + this.pending = true; + this.taskgroupService.taskgroupsPut({ + name: this.nameCtrl.value + }).subscribe({ + next: resp => { + this.pending = false; + this.dialogRef.close(resp); + }, + error: err => { + this.pending = false; + if(err.status == 409) { + this.snackbar.open("Taskgroup already exists", "", {duration: 2000}); + } else { + this.snackbar.open("An unexpected error occured", ""); + } + } + }) + + } +} diff --git a/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.css b/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.css index e69de29..01e110f 100644 --- a/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.css +++ b/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.css @@ -0,0 +1,28 @@ +.container { + margin: 20px auto; + width: 60%; +} + +.spacer { + margin-bottom: 2.5%; +} + + +@media screen and (max-width: 600px) { + .container { + width: 100%; + margin: 20px 10px; + } +} + +.navLink { + text-decoration: underline; + color: black; + margin-right: 5px; +} + +.navLink-disabled { + text-decoration: none; + color: grey; + +} diff --git a/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.html b/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.html index 1aae99a..f98e1c7 100644 --- a/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.html +++ b/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.html @@ -1 +1,10 @@ -

taskgroup-dashboard works!

+
+ + + Dashboard + / Taskgroups + + + + +
diff --git a/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.ts b/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.ts index c8f32eb..8b46a98 100644 --- a/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.ts +++ b/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.ts @@ -1,4 +1,6 @@ import { Component, OnInit } from '@angular/core'; +import {MatDialog} from "@angular/material/dialog"; +import {TaskgroupCreationComponent} from "../taskgroup-creation/taskgroup-creation.component"; @Component({ selector: 'app-taskgroup-dashboard', @@ -7,9 +9,12 @@ import { Component, OnInit } from '@angular/core'; }) export class TaskgroupDashboardComponent implements OnInit { - constructor() { } + constructor(private dialog: MatDialog) { } ngOnInit(): void { } + openTaskgroupCreation() { + const dialogRef = this.dialog.open(TaskgroupCreationComponent, {minWidth: "400px"}) + } } diff --git a/openapi.yaml b/openapi.yaml index ec92816..67f719f 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -588,6 +588,11 @@ paths: - taskgroup summary: creates taskgroup description: creates taskgroup + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/TaskgroupFieldInfo' responses: 200: description: Anfrage erfolgreich @@ -626,6 +631,11 @@ paths: schema: type: number example: 1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/TaskgroupFieldInfo' responses: 200: description: Anfrage erfolgreich -- 2.34.1 From efcab999f23288fa04fd8707f370ea13dc2eb37b Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 25 Sep 2023 13:06:49 +0200 Subject: [PATCH 11/12] List and Edit Taskgroups --- .../taskgroup-creation.component.ts | 67 +++++++++++++------ .../taskgroup-dashboard.component.css | 13 ++++ .../taskgroup-dashboard.component.html | 13 +++- .../taskgroup-dashboard.component.ts | 25 ++++++- 4 files changed, 96 insertions(+), 22 deletions(-) diff --git a/frontend/src/app/taskgroups/taskgroup-creation/taskgroup-creation.component.ts b/frontend/src/app/taskgroups/taskgroup-creation/taskgroup-creation.component.ts index 45bc353..5cefc1d 100644 --- a/frontend/src/app/taskgroups/taskgroup-creation/taskgroup-creation.component.ts +++ b/frontend/src/app/taskgroups/taskgroup-creation/taskgroup-creation.component.ts @@ -1,7 +1,7 @@ -import { Component, OnInit } from '@angular/core'; +import {Component, Inject, OnInit} from '@angular/core'; import {FormControl, Validators} from "@angular/forms"; -import {MatDialogRef} from "@angular/material/dialog"; -import {TaskgroupService} from "../../../api"; +import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; +import {TaskgroupEntityInfo, TaskgroupService} from "../../../api"; import {error} from "@angular/compiler/src/util"; import {MatSnackBar} from "@angular/material/snack-bar"; @@ -17,9 +17,13 @@ export class TaskgroupCreationComponent implements OnInit { constructor(private dialogRef: MatDialogRef, private taskgroupService: TaskgroupService, - private snackbar: MatSnackBar) { } + private snackbar: MatSnackBar, + @Inject(MAT_DIALOG_DATA) public data: TaskgroupEntityInfo | undefined) { } ngOnInit(): void { + if(this.data != undefined) { + this.nameCtrl.setValue(this.data!.taskgroupName) + } } cancel() { @@ -28,22 +32,47 @@ export class TaskgroupCreationComponent implements OnInit { save() { this.pending = true; - this.taskgroupService.taskgroupsPut({ - name: this.nameCtrl.value - }).subscribe({ - next: resp => { - this.pending = false; - this.dialogRef.close(resp); - }, - error: err => { - this.pending = false; - if(err.status == 409) { - this.snackbar.open("Taskgroup already exists", "", {duration: 2000}); - } else { - this.snackbar.open("An unexpected error occured", ""); + if(this.data == undefined) { + this.taskgroupService.taskgroupsPut({ + name: this.nameCtrl.value + }).subscribe({ + next: resp => { + this.pending = false; + this.dialogRef.close(resp); + }, + error: err => { + this.pending = false; + if(err.status == 409) { + this.snackbar.open("Taskgroup already exists", "", {duration: 2000}); + } else { + this.snackbar.open("An unexpected error occured", ""); + } } - } - }) + }) + } else { + this.taskgroupService.taskgroupsTaskgroupIDPost(this.data.taskgroupID, { + name: this.nameCtrl.value + }).subscribe({ + next: resp => { + this.pending = false; + this.data!.taskgroupName = this.nameCtrl.value + this.dialogRef.close(true); + }, + error: err => { + this.pending = false; + if(err.status == 409) { + this.snackbar.open("Taskgroup already exists", "", {duration: 2000}); + } else if(err.status == 403) { + this.snackbar.open("No permission", "", {duration: 2000}) + } else if(err.status == 404) { + this.snackbar.open("Not found", "", {duration: 2000}); + } else { + this.snackbar.open("An unexpected error occured", ""); + } + } + }) + } + } } diff --git a/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.css b/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.css index 01e110f..a1970b1 100644 --- a/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.css +++ b/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.css @@ -26,3 +26,16 @@ color: grey; } + +.navLink-bar { + margin-bottom: 20px; +} + +#addTaskgroupBtn { + margin-top: 20px; +} + +.edit-btn { + background-color: #6e6e6e; + color: white; +} diff --git a/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.html b/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.html index f98e1c7..03ec6d5 100644 --- a/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.html +++ b/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.html @@ -1,10 +1,19 @@
- + Dashboard / Taskgroups - + + +

{{taskgroup.taskgroupName}}

+ + + +
+ +
+
diff --git a/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.ts b/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.ts index 8b46a98..005ea39 100644 --- a/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.ts +++ b/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.ts @@ -1,6 +1,7 @@ import { Component, OnInit } from '@angular/core'; import {MatDialog} from "@angular/material/dialog"; import {TaskgroupCreationComponent} from "../taskgroup-creation/taskgroup-creation.component"; +import {TaskgroupEntityInfo, TaskgroupService} from "../../../api"; @Component({ selector: 'app-taskgroup-dashboard', @@ -9,12 +10,34 @@ import {TaskgroupCreationComponent} from "../taskgroup-creation/taskgroup-creati }) export class TaskgroupDashboardComponent implements OnInit { - constructor(private dialog: MatDialog) { } + constructor(private dialog: MatDialog, + private taskgroupService: TaskgroupService) { } + + taskgroups: TaskgroupEntityInfo[] = [] ngOnInit(): void { + this.taskgroupService.taskgroupsGet().subscribe({ + next: resp => { + this.taskgroups = resp; + } + }) } openTaskgroupCreation() { const dialogRef = this.dialog.open(TaskgroupCreationComponent, {minWidth: "400px"}) + dialogRef.afterClosed().subscribe(res => { + if(res != undefined) { + this.taskgroups.push(res); + } + }) + } + + openTaskgroupEditor(taskgroup: TaskgroupEntityInfo) { + const dialogRef = this.dialog.open(TaskgroupCreationComponent, {data: taskgroup, minWidth: "400px"}); + dialogRef.afterClosed().subscribe(res => { + if(res) { + const data = this.taskgroups + } + }) } } -- 2.34.1 From 0fb25e394aa1cd4b634a11a236bf790d759f27ad Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 25 Sep 2023 13:16:46 +0200 Subject: [PATCH 12/12] Delete Taskgroup (Frontend) --- frontend/src/app/app.module.ts | 4 +- .../taskgroup-creation.component.ts | 2 - .../taskgroup-dashboard.component.html | 2 +- .../taskgroup-dashboard.component.ts | 10 ++++ .../taskgroup-deletion.component.css | 0 .../taskgroup-deletion.component.html | 8 ++++ .../taskgroup-deletion.component.spec.ts | 25 ++++++++++ .../taskgroup-deletion.component.ts | 46 +++++++++++++++++++ 8 files changed, 93 insertions(+), 4 deletions(-) create mode 100644 frontend/src/app/taskgroups/taskgroup-deletion/taskgroup-deletion.component.css create mode 100644 frontend/src/app/taskgroups/taskgroup-deletion/taskgroup-deletion.component.html create mode 100644 frontend/src/app/taskgroups/taskgroup-deletion/taskgroup-deletion.component.spec.ts create mode 100644 frontend/src/app/taskgroups/taskgroup-deletion/taskgroup-deletion.component.ts diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 1a9d282..0b23766 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -38,6 +38,7 @@ import { SettingsComponent } from './admin-dashboard/settings/settings.component import {MatListModule} from "@angular/material/list"; import { TaskgroupDashboardComponent } from './taskgroups/taskgroup-dashboard/taskgroup-dashboard.component'; import { TaskgroupCreationComponent } from './taskgroups/taskgroup-creation/taskgroup-creation.component'; +import { TaskgroupDeletionComponent } from './taskgroups/taskgroup-deletion/taskgroup-deletion.component'; @NgModule({ declarations: [ @@ -56,7 +57,8 @@ import { TaskgroupCreationComponent } from './taskgroups/taskgroup-creation/task RegistrationComponent, SettingsComponent, TaskgroupDashboardComponent, - TaskgroupCreationComponent + TaskgroupCreationComponent, + TaskgroupDeletionComponent ], imports: [ BrowserModule, diff --git a/frontend/src/app/taskgroups/taskgroup-creation/taskgroup-creation.component.ts b/frontend/src/app/taskgroups/taskgroup-creation/taskgroup-creation.component.ts index 5cefc1d..8b299b7 100644 --- a/frontend/src/app/taskgroups/taskgroup-creation/taskgroup-creation.component.ts +++ b/frontend/src/app/taskgroups/taskgroup-creation/taskgroup-creation.component.ts @@ -72,7 +72,5 @@ export class TaskgroupCreationComponent implements OnInit { } }) } - - } } diff --git a/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.html b/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.html index 03ec6d5..747ee96 100644 --- a/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.html +++ b/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.html @@ -11,7 +11,7 @@

{{taskgroup.taskgroupName}}

- + diff --git a/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.ts b/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.ts index 005ea39..fd65051 100644 --- a/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.ts +++ b/frontend/src/app/taskgroups/taskgroup-dashboard/taskgroup-dashboard.component.ts @@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core'; import {MatDialog} from "@angular/material/dialog"; import {TaskgroupCreationComponent} from "../taskgroup-creation/taskgroup-creation.component"; import {TaskgroupEntityInfo, TaskgroupService} from "../../../api"; +import {TaskgroupDeletionComponent} from "../taskgroup-deletion/taskgroup-deletion.component"; @Component({ selector: 'app-taskgroup-dashboard', @@ -40,4 +41,13 @@ export class TaskgroupDashboardComponent implements OnInit { } }) } + + openTaskgroupDeletion(taskgroup: TaskgroupEntityInfo) { + const dialogRef = this.dialog.open(TaskgroupDeletionComponent, {data: taskgroup, minWidth: "400px"}); + dialogRef.afterClosed().subscribe(res => { + if(res) { + this.taskgroups = this.taskgroups.filter(ctg => ctg.taskgroupID != taskgroup.taskgroupID) + } + }) + } } diff --git a/frontend/src/app/taskgroups/taskgroup-deletion/taskgroup-deletion.component.css b/frontend/src/app/taskgroups/taskgroup-deletion/taskgroup-deletion.component.css new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/app/taskgroups/taskgroup-deletion/taskgroup-deletion.component.html b/frontend/src/app/taskgroups/taskgroup-deletion/taskgroup-deletion.component.html new file mode 100644 index 0000000..71015c2 --- /dev/null +++ b/frontend/src/app/taskgroups/taskgroup-deletion/taskgroup-deletion.component.html @@ -0,0 +1,8 @@ +

Delete Taskgroup

+ +

Are you sure, you want to delete your taskgroup {{data.taskgroupName}}? This cannot be undone!

+ +
+ + +
diff --git a/frontend/src/app/taskgroups/taskgroup-deletion/taskgroup-deletion.component.spec.ts b/frontend/src/app/taskgroups/taskgroup-deletion/taskgroup-deletion.component.spec.ts new file mode 100644 index 0000000..4f7d1d5 --- /dev/null +++ b/frontend/src/app/taskgroups/taskgroup-deletion/taskgroup-deletion.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TaskgroupDeletionComponent } from './taskgroup-deletion.component'; + +describe('TaskgroupDeletionComponent', () => { + let component: TaskgroupDeletionComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ TaskgroupDeletionComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(TaskgroupDeletionComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/taskgroups/taskgroup-deletion/taskgroup-deletion.component.ts b/frontend/src/app/taskgroups/taskgroup-deletion/taskgroup-deletion.component.ts new file mode 100644 index 0000000..d19a62d --- /dev/null +++ b/frontend/src/app/taskgroups/taskgroup-deletion/taskgroup-deletion.component.ts @@ -0,0 +1,46 @@ +import {Component, Inject, OnInit} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; +import {TaskgroupEntityInfo, TaskgroupService} from "../../../api"; +import {MatSnackBar} from "@angular/material/snack-bar"; + +@Component({ + selector: 'app-taskgroup-deletion', + templateUrl: './taskgroup-deletion.component.html', + styleUrls: ['./taskgroup-deletion.component.css'] +}) +export class TaskgroupDeletionComponent implements OnInit { + + constructor(@Inject(MAT_DIALOG_DATA) public data: TaskgroupEntityInfo, + private dialogRef: MatDialogRef, + private taskgroupService: TaskgroupService, + private snackbar: MatSnackBar) { } + + pending: boolean = false; + + ngOnInit(): void { + } + + cancel() { + this.dialogRef.close(false); + } + + confirm() { + this.pending = true; + this.taskgroupService.taskgroupsTaskgroupIDDelete(this.data.taskgroupID).subscribe({ + next: resp => { + this.pending = false; + this.dialogRef.close(true); + }, + error: err => { + this.pending = false; + if(err.stats == 403) { + this.snackbar.open("No permission", "", {duration: 2000}); + } else if(err.status == 404) { + this.snackbar.open("Not found", "", {duration: 2000}); + } else { + this.snackbar.open("Unexpected error", ""); + } + } + }) + } +} -- 2.34.1