From aa96be95500c713f028c38da939b42356600ddf5 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Tue, 25 Aug 2026 23:09:30 +0200 Subject: [PATCH] feat: add resource group entity, repository, and service --- .../com/slotline/resource/ResourceGroup.java | 61 ++++++++++++++++++ .../resource/ResourceGroupRepository.java | 15 +++++ .../resource/ResourceGroupService.java | 63 +++++++++++++++++++ 3 files changed, 139 insertions(+) create mode 100644 src/main/java/com/slotline/resource/ResourceGroup.java create mode 100644 src/main/java/com/slotline/resource/ResourceGroupRepository.java create mode 100644 src/main/java/com/slotline/resource/ResourceGroupService.java diff --git a/src/main/java/com/slotline/resource/ResourceGroup.java b/src/main/java/com/slotline/resource/ResourceGroup.java new file mode 100644 index 0000000..68e08fc --- /dev/null +++ b/src/main/java/com/slotline/resource/ResourceGroup.java @@ -0,0 +1,61 @@ +package com.slotline.resource; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +import java.time.Instant; + +@Entity +@Table(name = "resource_group") +public class ResourceGroup { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "organization_id", nullable = false) + private Long organizationId; + + @Column(name = "parent_group_id") + private Long parentGroupId; + + @Column(nullable = false, length = 128) + private String name; + + @Column(name = "created_at", nullable = false) + private Instant createdAt; + + protected ResourceGroup() { + } + + public ResourceGroup(Long organizationId, Long parentGroupId, String name, Instant createdAt) { + this.organizationId = organizationId; + this.parentGroupId = parentGroupId; + this.name = name; + this.createdAt = createdAt; + } + + public Long getId() { + return id; + } + + public Long getOrganizationId() { + return organizationId; + } + + public Long getParentGroupId() { + return parentGroupId; + } + + public String getName() { + return name; + } + + public Instant getCreatedAt() { + return createdAt; + } +} diff --git a/src/main/java/com/slotline/resource/ResourceGroupRepository.java b/src/main/java/com/slotline/resource/ResourceGroupRepository.java new file mode 100644 index 0000000..12dc5b1 --- /dev/null +++ b/src/main/java/com/slotline/resource/ResourceGroupRepository.java @@ -0,0 +1,15 @@ +package com.slotline.resource; + +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; +import java.util.Optional; + +public interface ResourceGroupRepository extends JpaRepository { + + List findByOrganizationIdOrderByCreatedAtAsc(Long organizationId); + + List findByParentGroupId(Long parentGroupId); + + Optional findByIdAndOrganizationId(Long id, Long organizationId); +} diff --git a/src/main/java/com/slotline/resource/ResourceGroupService.java b/src/main/java/com/slotline/resource/ResourceGroupService.java new file mode 100644 index 0000000..486b187 --- /dev/null +++ b/src/main/java/com/slotline/resource/ResourceGroupService.java @@ -0,0 +1,63 @@ +package com.slotline.resource; + +import com.slotline.common.NotFoundException; +import com.slotline.resource.dto.ResourceGroupRequest; +import com.slotline.resource.dto.ResourceGroupResponse; +import com.slotline.resource.dto.ResourceResponse; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.Instant; +import java.util.List; + +@Service +public class ResourceGroupService { + + private final ResourceGroupRepository groups; + private final ResourceService resources; + private final ResourceRepository resourceRepository; + + public ResourceGroupService(ResourceGroupRepository groups, ResourceService resources, + ResourceRepository resourceRepository) { + this.groups = groups; + this.resources = resources; + this.resourceRepository = resourceRepository; + } + + @Transactional + public ResourceGroupResponse create(Long organizationId, ResourceGroupRequest request) { + if (request.parentGroupId() != null) { + require(organizationId, request.parentGroupId()); + } + ResourceGroup group = new ResourceGroup(organizationId, request.parentGroupId(), request.name(), Instant.now()); + return ResourceGroupResponse.from(groups.save(group)); + } + + @Transactional(readOnly = true) + public List findAll(Long organizationId) { + return groups.findByOrganizationIdOrderByCreatedAtAsc(organizationId).stream() + .map(ResourceGroupResponse::from) + .toList(); + } + + @Transactional + public ResourceResponse assignResource(Long organizationId, Long groupId, Long resourceId) { + ResourceGroup group = require(organizationId, groupId); + Resource resource = resources.require(organizationId, resourceId); + resource.setGroupId(group.getId()); + return ResourceResponse.from(resource); + } + + @Transactional(readOnly = true) + public List resourcesInGroup(Long organizationId, Long groupId) { + ResourceGroup group = require(organizationId, groupId); + return resourceRepository.findByGroupIdOrderByCreatedAtDesc(group.getId()).stream() + .map(ResourceResponse::from) + .toList(); + } + + private ResourceGroup require(Long organizationId, Long groupId) { + return groups.findByIdAndOrganizationId(groupId, organizationId) + .orElseThrow(() -> new NotFoundException("Resource group " + groupId + " not found")); + } +}