diff --git a/src/main/java/group/goforward/ballistic/controllers/admin/AdminCategoryController.java b/src/main/java/group/goforward/ballistic/controllers/admin/AdminCategoryController.java index a5603ab..3f9be99 100644 --- a/src/main/java/group/goforward/ballistic/controllers/admin/AdminCategoryController.java +++ b/src/main/java/group/goforward/ballistic/controllers/admin/AdminCategoryController.java @@ -20,21 +20,21 @@ public class AdminCategoryController { @GetMapping public List listCategories() { - return partCategories.findAllByOrderByGroupNameAscSortOrderAscNameAsc() + return partCategories + .findAllByOrderByGroupNameAscSortOrderAscNameAsc() .stream() .map(this::toDto) .toList(); } private PartCategoryDto toDto(PartCategory entity) { - PartCategoryDto dto = new PartCategoryDto(); - dto.setId(entity.getId()); - dto.setSlug(entity.getSlug()); - dto.setName(entity.getName()); - dto.setDescription(entity.getDescription()); - dto.setGroupName(entity.getGroupName()); - dto.setSortOrder(entity.getSortOrder()); - dto.setUuid(entity.getUuid()); - return dto; + return new PartCategoryDto( + entity.getId(), + entity.getSlug(), + entity.getName(), + entity.getDescription(), + entity.getGroupName(), + entity.getSortOrder() + ); } } \ No newline at end of file diff --git a/src/main/java/group/goforward/ballistic/controllers/admin/AdminCategoryMappingController.java b/src/main/java/group/goforward/ballistic/controllers/admin/AdminCategoryMappingController.java new file mode 100644 index 0000000..e7553cd --- /dev/null +++ b/src/main/java/group/goforward/ballistic/controllers/admin/AdminCategoryMappingController.java @@ -0,0 +1,125 @@ +package group.goforward.ballistic.controllers.admin; + +import group.goforward.ballistic.model.AffiliateCategoryMap; +import group.goforward.ballistic.model.PartCategory; +import group.goforward.ballistic.repos.CategoryMappingRepository; +import group.goforward.ballistic.repos.PartCategoryRepository; +import group.goforward.ballistic.web.dto.admin.PartRoleMappingDto; +import group.goforward.ballistic.web.dto.admin.PartRoleMappingRequest; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.server.ResponseStatusException; + +import java.util.List; + +@RestController +@RequestMapping("/api/admin/category-mappings") +@CrossOrigin +public class AdminCategoryMappingController { + + private final CategoryMappingRepository categoryMappingRepository; + private final PartCategoryRepository partCategoryRepository; + + public AdminCategoryMappingController( + CategoryMappingRepository categoryMappingRepository, + PartCategoryRepository partCategoryRepository + ) { + this.categoryMappingRepository = categoryMappingRepository; + this.partCategoryRepository = partCategoryRepository; + } + + // GET /api/admin/category-mappings?platform=AR-15 + @GetMapping + public List list( + @RequestParam(name = "platform", defaultValue = "AR-15") String platform + ) { + List mappings = + categoryMappingRepository.findBySourceTypeAndPlatformOrderById("PART_ROLE", platform); + + return mappings.stream() + .map(this::toDto) + .toList(); + } + + // POST /api/admin/category-mappings + @PostMapping + public ResponseEntity create( + @RequestBody PartRoleMappingRequest request + ) { + if (request.platform() == null || request.partRole() == null || request.categorySlug() == null) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "platform, partRole, and categorySlug are required"); + } + + PartCategory category = partCategoryRepository.findBySlug(request.categorySlug()) + .orElseThrow(() -> new ResponseStatusException( + HttpStatus.BAD_REQUEST, + "Unknown category slug: " + request.categorySlug() + )); + + AffiliateCategoryMap mapping = new AffiliateCategoryMap(); + mapping.setSourceType("PART_ROLE"); + mapping.setSourceValue(request.partRole()); + mapping.setPlatform(request.platform()); + mapping.setPartCategory(category); + mapping.setNotes(request.notes()); + + AffiliateCategoryMap saved = categoryMappingRepository.save(mapping); + + return ResponseEntity.status(HttpStatus.CREATED).body(toDto(saved)); + } + + // PUT /api/admin/category-mappings/{id} + @PutMapping("/{id}") + public PartRoleMappingDto update( + @PathVariable Integer id, + @RequestBody PartRoleMappingRequest request + ) { + AffiliateCategoryMap mapping = categoryMappingRepository.findById(id) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Mapping not found")); + + if (request.platform() != null) { + mapping.setPlatform(request.platform()); + } + if (request.partRole() != null) { + mapping.setSourceValue(request.partRole()); + } + if (request.categorySlug() != null) { + PartCategory category = partCategoryRepository.findBySlug(request.categorySlug()) + .orElseThrow(() -> new ResponseStatusException( + HttpStatus.BAD_REQUEST, + "Unknown category slug: " + request.categorySlug() + )); + mapping.setPartCategory(category); + } + if (request.notes() != null) { + mapping.setNotes(request.notes()); + } + + AffiliateCategoryMap saved = categoryMappingRepository.save(mapping); + return toDto(saved); + } + + // DELETE /api/admin/category-mappings/{id} + @DeleteMapping("/{id}") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void delete(@PathVariable Integer id) { + if (!categoryMappingRepository.existsById(id)) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Mapping not found"); + } + categoryMappingRepository.deleteById(id); + } + + private PartRoleMappingDto toDto(AffiliateCategoryMap map) { + PartCategory cat = map.getPartCategory(); + + return new PartRoleMappingDto( + map.getId(), + map.getPlatform(), + map.getSourceValue(), // partRole + cat != null ? cat.getSlug() : null, // categorySlug + cat != null ? cat.getGroupName() : null, + map.getNotes() + ); + } +} \ No newline at end of file diff --git a/src/main/java/group/goforward/ballistic/controllers/admin/PartCategoryAdminController.java b/src/main/java/group/goforward/ballistic/controllers/admin/PartCategoryAdminController.java new file mode 100644 index 0000000..511a56f --- /dev/null +++ b/src/main/java/group/goforward/ballistic/controllers/admin/PartCategoryAdminController.java @@ -0,0 +1,35 @@ +package group.goforward.ballistic.controllers.admin; + +import group.goforward.ballistic.model.PartCategory; +import group.goforward.ballistic.repos.PartCategoryRepository; +import group.goforward.ballistic.web.dto.admin.PartCategoryDto; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/api/admin/part-categories") +@CrossOrigin // keep it loose for now, you can tighten origins later +public class PartCategoryAdminController { + + private final PartCategoryRepository partCategories; + + public PartCategoryAdminController(PartCategoryRepository partCategories) { + this.partCategories = partCategories; + } + + @GetMapping + public List list() { + return partCategories.findAllByOrderByGroupNameAscSortOrderAscNameAsc() + .stream() + .map(pc -> new PartCategoryDto( + pc.getId(), + pc.getSlug(), + pc.getName(), + pc.getDescription(), + pc.getGroupName(), + pc.getSortOrder() + )) + .toList(); + } +} \ No newline at end of file diff --git a/src/main/java/group/goforward/ballistic/model/AffiliateCategoryMap.java b/src/main/java/group/goforward/ballistic/model/AffiliateCategoryMap.java index d3e6cf4..eee49ec 100644 --- a/src/main/java/group/goforward/ballistic/model/AffiliateCategoryMap.java +++ b/src/main/java/group/goforward/ballistic/model/AffiliateCategoryMap.java @@ -8,18 +8,17 @@ public class AffiliateCategoryMap { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "id", nullable = false) private Integer id; - // e.g. "PART_ROLE" + // e.g. "PART_ROLE", "RAW_CATEGORY", etc. @Column(name = "source_type", nullable = false) private String sourceType; - // e.g. "suppressor" + // the value we’re mapping from (e.g. "suppressor", "TRIGGER") @Column(name = "source_value", nullable = false) private String sourceValue; - // e.g. "AR-15", nullable + // optional platform ("AR-15", "PRECISION", etc.) @Column(name = "platform") private String platform; @@ -30,6 +29,8 @@ public class AffiliateCategoryMap { @Column(name = "notes") private String notes; + // --- getters / setters --- + public Integer getId() { return id; } diff --git a/src/main/java/group/goforward/ballistic/repos/CategoryMappingRepository.java b/src/main/java/group/goforward/ballistic/repos/CategoryMappingRepository.java index cbdbc13..d483e05 100644 --- a/src/main/java/group/goforward/ballistic/repos/CategoryMappingRepository.java +++ b/src/main/java/group/goforward/ballistic/repos/CategoryMappingRepository.java @@ -3,18 +3,27 @@ package group.goforward.ballistic.repos; import group.goforward.ballistic.model.AffiliateCategoryMap; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.List; import java.util.Optional; public interface CategoryMappingRepository extends JpaRepository { + // Match by source_type + source_value + platform (case-insensitive) Optional findBySourceTypeAndSourceValueAndPlatformIgnoreCase( String sourceType, String sourceValue, String platform ); + // Fallback: match by source_type + source_value when platform is null/ignored Optional findBySourceTypeAndSourceValueIgnoreCase( String sourceType, String sourceValue ); + + // Used by AdminCategoryMappingController: list mappings for a given source_type + platform + List findBySourceTypeAndPlatformOrderById( + String sourceType, + String platform + ); } \ No newline at end of file diff --git a/src/main/java/group/goforward/ballistic/web/dto/admin/PartCategoryDto.java b/src/main/java/group/goforward/ballistic/web/dto/admin/PartCategoryDto.java index 69ba09d..17e5963 100644 --- a/src/main/java/group/goforward/ballistic/web/dto/admin/PartCategoryDto.java +++ b/src/main/java/group/goforward/ballistic/web/dto/admin/PartCategoryDto.java @@ -1,35 +1,10 @@ package group.goforward.ballistic.web.dto.admin; -import java.util.UUID; - -public class PartCategoryDto { - private Integer id; - private String slug; - private String name; - private String description; - private String groupName; - private Integer sortOrder; - private UUID uuid; - - // getters + setters - public Integer getId() { return id; } - public void setId(Integer id) { this.id = id; } - - public String getSlug() { return slug; } - public void setSlug(String slug) { this.slug = slug; } - - public String getName() { return name; } - public void setName(String name) { this.name = name; } - - public String getDescription() { return description; } - public void setDescription(String description) { this.description = description; } - - public String getGroupName() { return groupName; } - public void setGroupName(String groupName) { this.groupName = groupName; } - - public Integer getSortOrder() { return sortOrder; } - public void setSortOrder(Integer sortOrder) { this.sortOrder = sortOrder; } - - public UUID getUuid() { return uuid; } - public void setUuid(UUID uuid) { this.uuid = uuid; } -} \ No newline at end of file +public record PartCategoryDto( + Integer id, + String slug, + String name, + String description, + String groupName, + Integer sortOrder +) {} \ No newline at end of file diff --git a/src/main/java/group/goforward/ballistic/web/dto/admin/PartRoleMappingDto.java b/src/main/java/group/goforward/ballistic/web/dto/admin/PartRoleMappingDto.java index 93756e4..5082f89 100644 --- a/src/main/java/group/goforward/ballistic/web/dto/admin/PartRoleMappingDto.java +++ b/src/main/java/group/goforward/ballistic/web/dto/admin/PartRoleMappingDto.java @@ -1,69 +1,10 @@ package group.goforward.ballistic.web.dto.admin; -public class PartRoleMappingDto { - private Integer id; - private String platform; - private String partRole; - private String categorySlug; - private String categoryName; - private String groupName; - private String notes; - - // getters + setters... - - public Integer getId() { - return id; - } - - public void setId(Integer id) { - this.id = id; - } - - public String getPlatform() { - return platform; - } - - public void setPlatform(String platform) { - this.platform = platform; - } - - public String getPartRole() { - return partRole; - } - - public void setPartRole(String partRole) { - this.partRole = partRole; - } - - public String getCategorySlug() { - return categorySlug; - } - - public void setCategorySlug(String categorySlug) { - this.categorySlug = categorySlug; - } - - public String getCategoryName() { - return categoryName; - } - - public void setCategoryName(String categoryName) { - this.categoryName = categoryName; - } - - public String getGroupName() { - return groupName; - } - - public void setGroupName(String groupName) { - this.groupName = groupName; - } - - public String getNotes() { - return notes; - } - - public void setNotes(String notes) { - this.notes = notes; - } -} \ No newline at end of file +public record PartRoleMappingDto( + Integer id, + String platform, + String partRole, + String categorySlug, + String groupName, + String notes +) {} \ No newline at end of file diff --git a/src/main/java/group/goforward/ballistic/web/dto/admin/PartRoleMappingRequest.java b/src/main/java/group/goforward/ballistic/web/dto/admin/PartRoleMappingRequest.java new file mode 100644 index 0000000..45a4074 --- /dev/null +++ b/src/main/java/group/goforward/ballistic/web/dto/admin/PartRoleMappingRequest.java @@ -0,0 +1,8 @@ +package group.goforward.ballistic.web.dto.admin; + +public record PartRoleMappingRequest( + String platform, + String partRole, + String categorySlug, + String notes +) {} \ No newline at end of file