-
Notifications
You must be signed in to change notification settings - Fork 24
Add endpoint for linking skills to task #186
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
sunilk429
wants to merge
19
commits into
Real-Dev-Squad:develop
Choose a base branch
from
sunilk429:feat/task-skill-association
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
205a080
add migration file for task_skills table
sunilk429 0a0d814
add TaskSkillId as composite key and TaskSkill entity
sunilk429 ac4a653
add TaskSkillRepository to find skills by taskId
sunilk429 819284e
add custom exception for duplicate task-skill association
sunilk429 0f8f193
add TaskSkillService to handle services related to task and skill
sunilk429 fe7ead3
add controller TaskSkillApi
sunilk429 79c9765
add @NotNull validation and serialVersionUID to TaskSkillID model
sunilk429 e2c5248
fix: remove duplicate skill IDs sent through request body
sunilk429 587069a
add relationship mapping in TaskSkill and ensure Skill is fetched bef…
sunilk429 389c38b
create TaskSkill request and creation view models
sunilk429 f2819d2
use dedicated TaskSkill request and creation view-models for modularity
sunilk429 be90dd4
add validation for taskId and move exception handler from TaskSkillAp…
sunilk429 7b56aba
add detailed JavaDoc to TaskSkillService#createTaskSkills
sunilk429 4b55066
optimize TaskSkillService by batch retrieving Skill entities for crea…
sunilk429 6f0227a
optimize TaskSkillService by batch validating and saving TaskSkill as…
sunilk429 9c30802
Merge branch 'develop' into feat/task-skill-association
iamitprakash 9c76736
update status code 200 to 201 for resource creation
sunilk429 6f6086d
Merge branch 'Real-Dev-Squad:develop' into feat/task-skill-association
sunilk429 92df1ea
optimize task-skill creation with batch checks and map-based lookups
sunilk429 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
41 changes: 41 additions & 0 deletions
41
skill-tree/src/main/java/com/RDS/skilltree/apis/TaskSkillApi.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| package com.RDS.skilltree.apis; | ||
|
|
||
| import com.RDS.skilltree.annotations.AuthorizedRoles; | ||
| import com.RDS.skilltree.enums.UserRoleEnum; | ||
| import com.RDS.skilltree.models.JwtUser; | ||
| import com.RDS.skilltree.services.TaskSkillService; | ||
| import com.RDS.skilltree.viewmodels.CreateTaskSkillViewModel; | ||
| import com.RDS.skilltree.viewmodels.TaskSkillRequestViewModel; | ||
| import jakarta.validation.Valid; | ||
| import jakarta.validation.constraints.Pattern; | ||
| import lombok.RequiredArgsConstructor; | ||
| import lombok.extern.slf4j.Slf4j; | ||
| import org.springframework.http.HttpStatus; | ||
| import org.springframework.http.ResponseEntity; | ||
| import org.springframework.security.core.context.SecurityContextHolder; | ||
| import org.springframework.validation.annotation.Validated; | ||
| import org.springframework.web.bind.annotation.*; | ||
|
|
||
| @Slf4j | ||
| @RestController | ||
| @RequiredArgsConstructor | ||
| @RequestMapping("v1/tasks") | ||
| @Validated | ||
| public class TaskSkillApi { | ||
|
|
||
| private final TaskSkillService taskSkillService; | ||
|
|
||
| @AuthorizedRoles({UserRoleEnum.SUPERUSER}) | ||
| @PostMapping("/{taskId}/skills") | ||
| public ResponseEntity<CreateTaskSkillViewModel> createTaskSkills( | ||
| @PathVariable @Pattern(regexp = "^[A-Za-z0-9]+$", message = "Task ID must be valid") | ||
| String taskId, | ||
| @Valid @RequestBody TaskSkillRequestViewModel request) { | ||
| JwtUser currentUser = | ||
| (JwtUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); | ||
| String createdBy = currentUser.getRdsUserId(); | ||
| CreateTaskSkillViewModel response = | ||
| taskSkillService.createTaskSkills(taskId, request.getSkillIds(), createdBy); | ||
| return ResponseEntity.status(HttpStatus.CREATED).body(response); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
11 changes: 11 additions & 0 deletions
11
...rc/main/java/com/RDS/skilltree/exceptions/TaskSkillAssociationAlreadyExistsException.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package com.RDS.skilltree.exceptions; | ||
|
|
||
| public class TaskSkillAssociationAlreadyExistsException extends RuntimeException { | ||
| public TaskSkillAssociationAlreadyExistsException(String message, Throwable cause) { | ||
| super(message, cause); | ||
| } | ||
|
|
||
| public TaskSkillAssociationAlreadyExistsException(String message) { | ||
| super(message); | ||
| } | ||
| } | ||
sunilk429 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
47 changes: 47 additions & 0 deletions
47
skill-tree/src/main/java/com/RDS/skilltree/models/TaskSkill.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| package com.RDS.skilltree.models; | ||
|
|
||
| import jakarta.persistence.*; | ||
| import java.time.LocalDateTime; | ||
| import lombok.*; | ||
| import org.springframework.data.annotation.CreatedBy; | ||
| import org.springframework.data.annotation.CreatedDate; | ||
| import org.springframework.data.annotation.LastModifiedBy; | ||
| import org.springframework.data.annotation.LastModifiedDate; | ||
|
|
||
| @Entity | ||
| @Table(name = "task_skills") | ||
| @Getter | ||
| @Setter | ||
| @Builder | ||
| @AllArgsConstructor | ||
| @NoArgsConstructor | ||
| public class TaskSkill { | ||
|
|
||
| @EmbeddedId private TaskSkillId id; | ||
|
|
||
| @CreatedDate | ||
| @Column(name = "created_at", nullable = false, updatable = false) | ||
| private LocalDateTime createdAt; | ||
|
|
||
| @Column(name = "is_deleted", nullable = false) | ||
| @Builder.Default | ||
| private boolean isDeleted = false; | ||
sunilk429 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| @LastModifiedDate | ||
| @Column(name = "updated_at") | ||
| private LocalDateTime updatedAt; | ||
|
|
||
| @CreatedBy | ||
| @Column(name = "created_by", nullable = false, updatable = false) | ||
| private String createdBy; | ||
|
|
||
| @LastModifiedBy | ||
| @Column(name = "updated_by") | ||
| private String updatedBy; | ||
|
|
||
| // Relationship to Skill entity for richer detail access. | ||
| @ManyToOne(fetch = FetchType.LAZY) | ||
| @MapsId("skillId") | ||
| @JoinColumn(name = "skill_id", insertable = false, updatable = false) | ||
| private Skill skill; | ||
| } | ||
24 changes: 24 additions & 0 deletions
24
skill-tree/src/main/java/com/RDS/skilltree/models/TaskSkillId.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| package com.RDS.skilltree.models; | ||
|
|
||
| import jakarta.persistence.Embeddable; | ||
| import jakarta.validation.constraints.NotNull; | ||
| import java.io.Serial; | ||
| import java.io.Serializable; | ||
| import lombok.*; | ||
|
|
||
| @Embeddable | ||
| @Getter | ||
| @Setter | ||
| @NoArgsConstructor | ||
| @AllArgsConstructor | ||
| @Builder | ||
| @EqualsAndHashCode | ||
| public class TaskSkillId implements Serializable { | ||
| @Serial private static final long serialVersionUID = 1L; | ||
|
|
||
| @NotNull(message = "Task ID cannot be null") | ||
| private String taskId; | ||
|
|
||
| @NotNull(message = "Skill ID cannot be null") | ||
| private Integer skillId; | ||
| } |
20 changes: 20 additions & 0 deletions
20
skill-tree/src/main/java/com/RDS/skilltree/repositories/TaskSkillRepository.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| package com.RDS.skilltree.repositories; | ||
|
|
||
| import com.RDS.skilltree.models.TaskSkill; | ||
| import com.RDS.skilltree.models.TaskSkillId; | ||
| import java.util.Set; | ||
| import org.springframework.data.jpa.repository.JpaRepository; | ||
| import org.springframework.data.jpa.repository.Query; | ||
| import org.springframework.data.repository.query.Param; | ||
| import org.springframework.stereotype.Repository; | ||
|
|
||
| @Repository | ||
| public interface TaskSkillRepository extends JpaRepository<TaskSkill, TaskSkillId> { | ||
| /** | ||
| * Find skill IDs that already have associations with the given task ID | ||
| */ | ||
| @Query( | ||
| "SELECT ts.id.skillId FROM TaskSkill ts WHERE ts.id.taskId = :taskId AND ts.id.skillId IN :skillIds") | ||
| Set<Integer> findSkillIdsByTaskIdAndSkillIdIn( | ||
| @Param("taskId") String taskId, @Param("skillIds") Set<Integer> skillIds); | ||
| } |
21 changes: 21 additions & 0 deletions
21
skill-tree/src/main/java/com/RDS/skilltree/services/TaskSkillService.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| package com.RDS.skilltree.services; | ||
|
|
||
| import com.RDS.skilltree.exceptions.SkillNotFoundException; | ||
| import com.RDS.skilltree.exceptions.TaskSkillAssociationAlreadyExistsException; | ||
| import com.RDS.skilltree.viewmodels.CreateTaskSkillViewModel; | ||
| import java.util.List; | ||
|
|
||
| public interface TaskSkillService { | ||
| /** | ||
| * Creates associations between a task and multiple skills. | ||
| * | ||
| * @param taskId The unique identifier of the task. | ||
| * @param skillIds List of skill identifiers to associate with the task. | ||
| * @param createdBy The identifier of the user creating these associations. | ||
| * @return A response view model indicating success. | ||
| * @throws TaskSkillAssociationAlreadyExistsException if an association already exists. | ||
| * @throws SkillNotFoundException if any skill does not exist. | ||
| */ | ||
| CreateTaskSkillViewModel createTaskSkills( | ||
| String taskId, List<Integer> skillIds, String createdBy); | ||
| } |
82 changes: 82 additions & 0 deletions
82
skill-tree/src/main/java/com/RDS/skilltree/services/TaskSkillServiceImplementation.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| package com.RDS.skilltree.services; | ||
|
|
||
| import com.RDS.skilltree.exceptions.SkillNotFoundException; | ||
| import com.RDS.skilltree.exceptions.TaskSkillAssociationAlreadyExistsException; | ||
| import com.RDS.skilltree.models.Skill; | ||
| import com.RDS.skilltree.models.TaskSkill; | ||
| import com.RDS.skilltree.models.TaskSkillId; | ||
| import com.RDS.skilltree.repositories.SkillRepository; | ||
| import com.RDS.skilltree.repositories.TaskSkillRepository; | ||
| import com.RDS.skilltree.viewmodels.CreateTaskSkillViewModel; | ||
| import java.time.LocalDateTime; | ||
| import java.util.HashSet; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.Set; | ||
| import java.util.stream.Collectors; | ||
| import org.springframework.stereotype.Service; | ||
| import org.springframework.transaction.annotation.Transactional; | ||
|
|
||
| @Service | ||
| public class TaskSkillServiceImplementation implements TaskSkillService { | ||
|
|
||
| private final TaskSkillRepository taskSkillRepository; | ||
| private final SkillRepository skillRepository; | ||
|
|
||
| public TaskSkillServiceImplementation( | ||
| TaskSkillRepository taskSkillRepository, SkillRepository skillRepository) { | ||
| this.taskSkillRepository = taskSkillRepository; | ||
| this.skillRepository = skillRepository; | ||
| } | ||
|
|
||
| @Override | ||
| @Transactional | ||
| public CreateTaskSkillViewModel createTaskSkills( | ||
| String taskId, List<Integer> skillIds, String createdBy) { | ||
| // Remove duplicate skill IDs | ||
| Set<Integer> uniqueSkillIds = new HashSet<>(skillIds); | ||
|
|
||
| // FIRST: Check if any TaskSkill associations already exist (batch check) | ||
| Set<Integer> existingSkillIds = | ||
| taskSkillRepository.findSkillIdsByTaskIdAndSkillIdIn(taskId, uniqueSkillIds); | ||
| if (!existingSkillIds.isEmpty()) { | ||
| throw new TaskSkillAssociationAlreadyExistsException( | ||
| "Task-Skill associations already exist for task " | ||
| + taskId | ||
| + " and skills: " | ||
| + existingSkillIds); | ||
| } | ||
|
|
||
| // SECOND: Load all skills at once and verify they exist | ||
| List<Skill> skills = skillRepository.findAllById(uniqueSkillIds); | ||
|
|
||
| // Check for missing skills | ||
| if (skills.size() != uniqueSkillIds.size()) { | ||
| Set<Integer> foundSkillIds = skills.stream().map(Skill::getId).collect(Collectors.toSet()); | ||
| Set<Integer> missingIds = new HashSet<>(uniqueSkillIds); | ||
| missingIds.removeAll(foundSkillIds); | ||
| throw new SkillNotFoundException("Skill not found for skillId(s): " + missingIds); | ||
| } | ||
|
|
||
| // Create a map for quick lookups | ||
| Map<Integer, Skill> skillsMap = skills.stream().collect(Collectors.toMap(Skill::getId, s -> s)); | ||
|
|
||
| // Create and save TaskSkill entities | ||
| LocalDateTime now = LocalDateTime.now(); | ||
| List<TaskSkill> taskSkillsToSave = | ||
| uniqueSkillIds.stream() | ||
| .map( | ||
| skillId -> | ||
| TaskSkill.builder() | ||
| .id(new TaskSkillId(taskId, skillId)) | ||
| .skill(skillsMap.get(skillId)) // Set the actual Skill entity reference | ||
| .createdAt(now) | ||
| .createdBy(createdBy) | ||
| .build()) | ||
| .collect(Collectors.toList()); | ||
|
|
||
| taskSkillRepository.saveAll(taskSkillsToSave); | ||
|
|
||
| return new CreateTaskSkillViewModel("Skills are linked to task successfully!"); | ||
| } | ||
| } |
12 changes: 12 additions & 0 deletions
12
skill-tree/src/main/java/com/RDS/skilltree/viewmodels/CreateTaskSkillViewModel.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| package com.RDS.skilltree.viewmodels; | ||
|
|
||
| import lombok.AllArgsConstructor; | ||
| import lombok.Data; | ||
| import lombok.NoArgsConstructor; | ||
|
|
||
| @Data | ||
| @AllArgsConstructor | ||
| @NoArgsConstructor | ||
| public class CreateTaskSkillViewModel { | ||
| private String message; | ||
| } | ||
sunilk429 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
15 changes: 15 additions & 0 deletions
15
skill-tree/src/main/java/com/RDS/skilltree/viewmodels/TaskSkillRequestViewModel.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| package com.RDS.skilltree.viewmodels; | ||
|
|
||
| import jakarta.validation.constraints.NotEmpty; | ||
| import java.util.List; | ||
| import lombok.AllArgsConstructor; | ||
| import lombok.Data; | ||
| import lombok.NoArgsConstructor; | ||
|
|
||
| @Data | ||
| @NoArgsConstructor | ||
| @AllArgsConstructor | ||
| public class TaskSkillRequestViewModel { | ||
| @NotEmpty(message = "Skill IDs list cannot be empty") | ||
| private List<Integer> skillIds; | ||
| } | ||
sunilk429 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
11 changes: 11 additions & 0 deletions
11
skill-tree/src/main/resources/db/migrations/V2__task_skills_association_table.sql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| CREATE TABLE `task_skills` ( | ||
| `task_id` varchar(255) NOT NULL, | ||
| `skill_id` int NOT NULL, | ||
| `created_at` datetime(6) NOT NULL, | ||
| `is_deleted` tinyint(1) NOT NULL DEFAULT '0', | ||
| `updated_at` datetime(6) DEFAULT NULL, | ||
| `created_by` varchar(255) NOT NULL, | ||
| `updated_by` varchar(255) DEFAULT NULL, | ||
| PRIMARY KEY (`task_id`, `skill_id`), | ||
| CONSTRAINT `fk_task_skills_skill_id` FOREIGN KEY (`skill_id`) REFERENCES `skills` (`id`) ON DELETE CASCADE ON UPDATE CASCADE | ||
| ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.