mirror of
https://gitea.gofwd.group/Forward_Group/ballistic-builder-spring.git
synced 2026-01-20 16:51:03 -05:00
new classifier and resolver for product mappings. also cleaned up /product endpoints
This commit is contained in:
@@ -1,83 +0,0 @@
|
|||||||
package group.goforward.battlbuilder.controllers;
|
|
||||||
|
|
||||||
import group.goforward.battlbuilder.services.GunbuilderProductService;
|
|
||||||
import group.goforward.battlbuilder.web.dto.GunbuilderProductDto;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/gunbuilder")
|
|
||||||
public class GunbuilderProductController {
|
|
||||||
|
|
||||||
private final GunbuilderProductService gunbuilderProductService;
|
|
||||||
|
|
||||||
public GunbuilderProductController(GunbuilderProductService gunbuilderProductService) {
|
|
||||||
this.gunbuilderProductService = gunbuilderProductService;
|
|
||||||
System.out.println(">>> GunbuilderProductController initialized");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 🔹 sanity check: is this controller even mapped?
|
|
||||||
@GetMapping("/ping")
|
|
||||||
public Map<String, String> ping() {
|
|
||||||
return Map.of("status", "ok", "source", "GunbuilderProductController");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 🔹 super-dumb test: no DB, no service, just prove the route works
|
|
||||||
@GetMapping("/test-products")
|
|
||||||
public Map<String, Object> testProducts(@RequestParam String platform) {
|
|
||||||
System.out.println(">>> /api/gunbuilder/test-products hit for platform=" + platform);
|
|
||||||
|
|
||||||
Map<String, Object> m = new java.util.HashMap<>();
|
|
||||||
m.put("platform", platform);
|
|
||||||
m.put("note", "test endpoint only");
|
|
||||||
m.put("ok", true);
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List products for the builder UI.
|
|
||||||
*
|
|
||||||
* Examples:
|
|
||||||
* GET /api/gunbuilder/products?platform=AR-15
|
|
||||||
* GET /api/gunbuilder/products?platform=AR-15&partRoles=LOWER_RECEIVER_STRIPPED&partRoles=LOWER_RECEIVER_COMPLETE
|
|
||||||
*/
|
|
||||||
@GetMapping("/products")
|
|
||||||
public List<GunbuilderProductDto> listProducts(
|
|
||||||
@RequestParam String platform,
|
|
||||||
@RequestParam(required = false) List<String> partRoles
|
|
||||||
) {
|
|
||||||
return gunbuilderProductService.listGunbuilderProducts(platform, partRoles);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/products/by-category")
|
|
||||||
public List<GunbuilderProductDto> listProductsByCategory(
|
|
||||||
@RequestParam String platform,
|
|
||||||
@RequestParam String categorySlug
|
|
||||||
) {
|
|
||||||
return gunbuilderProductService.listGunbuilderProductsByCategory(platform, categorySlug);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 🔹 DB test: hit repo via service and return a tiny view of products
|
|
||||||
@GetMapping("/test-products-db")
|
|
||||||
public List<Map<String, Object>> testProductsDb(@RequestParam String platform) {
|
|
||||||
System.out.println(">>> /api/gunbuilder/test-products-db hit for platform=" + platform);
|
|
||||||
|
|
||||||
var products = gunbuilderProductService.getSampleProducts(platform);
|
|
||||||
|
|
||||||
return products.stream()
|
|
||||||
.map(p -> {
|
|
||||||
Map<String, Object> m = new java.util.HashMap<>();
|
|
||||||
m.put("id", p.getId());
|
|
||||||
m.put("name", p.getName());
|
|
||||||
m.put("brand", p.getBrand() != null ? p.getBrand().getName() : null);
|
|
||||||
m.put("partRole", p.getPartRole());
|
|
||||||
return m;
|
|
||||||
})
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,182 +0,0 @@
|
|||||||
package group.goforward.battlbuilder.services;
|
|
||||||
|
|
||||||
import group.goforward.battlbuilder.model.PartCategory;
|
|
||||||
import group.goforward.battlbuilder.model.Product;
|
|
||||||
import group.goforward.battlbuilder.repos.ProductRepository;
|
|
||||||
import group.goforward.battlbuilder.web.dto.GunbuilderProductDto;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import group.goforward.battlbuilder.model.PartRoleMapping;
|
|
||||||
import group.goforward.battlbuilder.repos.PartRoleMappingRepository;
|
|
||||||
import group.goforward.battlbuilder.model.ImportStatus;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class GunbuilderProductService {
|
|
||||||
|
|
||||||
private final ProductRepository productRepository;
|
|
||||||
private final PartCategoryResolverService partCategoryResolverService;
|
|
||||||
private final PartRoleMappingRepository partRoleMappingRepository;
|
|
||||||
|
|
||||||
public GunbuilderProductService(
|
|
||||||
ProductRepository productRepository,
|
|
||||||
PartCategoryResolverService partCategoryResolverService,
|
|
||||||
PartRoleMappingRepository partRoleMappingRepository
|
|
||||||
) {
|
|
||||||
this.productRepository = productRepository;
|
|
||||||
this.partCategoryResolverService = partCategoryResolverService;
|
|
||||||
this.partRoleMappingRepository = partRoleMappingRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main builder endpoint.
|
|
||||||
* For now we ONLY support calls that provide partRoles,
|
|
||||||
* to avoid pulling the entire catalog into memory.
|
|
||||||
*/
|
|
||||||
public List<GunbuilderProductDto> listGunbuilderProducts(String platform, List<String> partRoles) {
|
|
||||||
|
|
||||||
System.out.println(">>> GB: listGunbuilderProducts platform=" + platform
|
|
||||||
+ ", partRoles=" + partRoles);
|
|
||||||
|
|
||||||
if (partRoles == null || partRoles.isEmpty()) {
|
|
||||||
System.out.println(">>> GB: no partRoles provided, returning empty list");
|
|
||||||
return List.of();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Product> products =
|
|
||||||
productRepository.findForGunbuilderByPlatformAndPartRoles(
|
|
||||||
platform,
|
|
||||||
partRoles,
|
|
||||||
ImportStatus.MAPPED
|
|
||||||
);
|
|
||||||
|
|
||||||
System.out.println(">>> GB: repo returned " + products.size() + " products");
|
|
||||||
|
|
||||||
Map<String, PartCategory> categoryCache = new HashMap<>();
|
|
||||||
|
|
||||||
return products.stream()
|
|
||||||
.map(p -> {
|
|
||||||
PartCategory cat = categoryCache.computeIfAbsent(
|
|
||||||
p.getPartRole(),
|
|
||||||
role -> partCategoryResolverService
|
|
||||||
.resolveForPlatformAndPartRole(platform, role)
|
|
||||||
.orElse(null)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (cat == null) {
|
|
||||||
System.out.println(">>> GB: NO CATEGORY for platform=" + platform
|
|
||||||
+ ", partRole=" + p.getPartRole()
|
|
||||||
+ ", productId=" + p.getId());
|
|
||||||
} else {
|
|
||||||
System.out.println(">>> GB: CATEGORY for productId=" + p.getId()
|
|
||||||
+ " -> slug=" + cat.getSlug()
|
|
||||||
+ ", group=" + cat.getGroupName());
|
|
||||||
}
|
|
||||||
|
|
||||||
// TEMP: do NOT drop products if category is null.
|
|
||||||
// Just mark them as "unmapped" so we can see them in the JSON.
|
|
||||||
String categorySlug = (cat != null) ? cat.getSlug() : "unmapped";
|
|
||||||
String categoryGroup = (cat != null) ? cat.getGroupName() : "Unmapped";
|
|
||||||
|
|
||||||
return new GunbuilderProductDto(
|
|
||||||
p.getId(),
|
|
||||||
p.getName(),
|
|
||||||
p.getBrand().getName(),
|
|
||||||
platform,
|
|
||||||
p.getPartRole(),
|
|
||||||
p.getBestOfferPrice(),
|
|
||||||
p.getMainImageUrl(),
|
|
||||||
p.getBestOfferBuyUrl(),
|
|
||||||
categorySlug,
|
|
||||||
categoryGroup
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<GunbuilderProductDto> listGunbuilderProductsByCategory(
|
|
||||||
String platform,
|
|
||||||
String categorySlug
|
|
||||||
) {
|
|
||||||
System.out.println(">>> GB: listGunbuilderProductsByCategory platform=" + platform
|
|
||||||
+ ", categorySlug=" + categorySlug);
|
|
||||||
|
|
||||||
if (platform == null || platform.isBlank()
|
|
||||||
|| categorySlug == null || categorySlug.isBlank()) {
|
|
||||||
System.out.println(">>> GB: missing platform or categorySlug, returning empty list");
|
|
||||||
return List.of();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<PartRoleMapping> mappings =
|
|
||||||
partRoleMappingRepository.findByPlatformAndPartCategory_SlugAndDeletedAtIsNull(
|
|
||||||
platform,
|
|
||||||
categorySlug
|
|
||||||
);
|
|
||||||
|
|
||||||
List<String> partRoles = mappings.stream()
|
|
||||||
.map(PartRoleMapping::getPartRole)
|
|
||||||
.distinct()
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
System.out.println(">>> GB: resolved " + partRoles.size()
|
|
||||||
+ " partRoles for categorySlug=" + categorySlug + " -> " + partRoles);
|
|
||||||
|
|
||||||
if (partRoles.isEmpty()) {
|
|
||||||
return List.of();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reuse the existing method that already does all the DTO + category resolution logic
|
|
||||||
return listGunbuilderProducts(platform, partRoles);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Optional<GunbuilderProductDto> getGunbuilderProductById(String id) {
|
|
||||||
if (id == null || id.isBlank()) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
Integer numericId;
|
|
||||||
try {
|
|
||||||
numericId = Integer.parseInt(id);
|
|
||||||
} catch (NumberFormatException ex) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
return productRepository.findById(numericId)
|
|
||||||
.map(p -> {
|
|
||||||
String platform = p.getPlatform();
|
|
||||||
|
|
||||||
PartCategory cat = partCategoryResolverService
|
|
||||||
.resolveForPlatformAndPartRole(platform, p.getPartRole())
|
|
||||||
.orElse(null);
|
|
||||||
|
|
||||||
String categorySlug = (cat != null) ? cat.getSlug() : "unmapped";
|
|
||||||
String categoryGroup = (cat != null) ? cat.getGroupName() : "Unmapped";
|
|
||||||
|
|
||||||
return new GunbuilderProductDto(
|
|
||||||
p.getId(),
|
|
||||||
p.getName(),
|
|
||||||
p.getBrand().getName(),
|
|
||||||
platform,
|
|
||||||
p.getPartRole(),
|
|
||||||
p.getBestOfferPrice(),
|
|
||||||
p.getMainImageUrl(),
|
|
||||||
p.getBestOfferBuyUrl(),
|
|
||||||
categorySlug,
|
|
||||||
categoryGroup
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tiny helper used ONLY by /test-products-db to prove DB wiring.
|
|
||||||
*/
|
|
||||||
public List<Product> getSampleProducts(String platform) {
|
|
||||||
// You already have this wired via ProductRepository.findTop5ByPlatformWithBrand
|
|
||||||
// If that method exists, keep using it; if not, you can stub a tiny query here.
|
|
||||||
return productRepository.findTop5ByPlatformWithBrand(platform);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
package group.goforward.battlbuilder.web.dto;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
|
|
||||||
public class GunbuilderProductDto {
|
|
||||||
|
|
||||||
private Integer id;
|
|
||||||
private String name;
|
|
||||||
private String brand;
|
|
||||||
private String platform;
|
|
||||||
private String partRole;
|
|
||||||
private BigDecimal price;
|
|
||||||
private String imageUrl;
|
|
||||||
private String buyUrl;
|
|
||||||
private String categorySlug;
|
|
||||||
private String categoryGroup;
|
|
||||||
|
|
||||||
public GunbuilderProductDto(
|
|
||||||
Integer id,
|
|
||||||
String name,
|
|
||||||
String brand,
|
|
||||||
String platform,
|
|
||||||
String partRole,
|
|
||||||
BigDecimal price,
|
|
||||||
String imageUrl,
|
|
||||||
String buyUrl,
|
|
||||||
String categorySlug,
|
|
||||||
String categoryGroup
|
|
||||||
) {
|
|
||||||
this.id = id;
|
|
||||||
this.name = name;
|
|
||||||
this.brand = brand;
|
|
||||||
this.platform = platform;
|
|
||||||
this.partRole = partRole;
|
|
||||||
this.price = price;
|
|
||||||
this.imageUrl = imageUrl;
|
|
||||||
this.buyUrl = buyUrl;
|
|
||||||
this.categorySlug = categorySlug;
|
|
||||||
this.categoryGroup = categoryGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Getters only (DTOs are read-only in most cases) ---
|
|
||||||
public Integer getId() { return id; }
|
|
||||||
public String getName() { return name; }
|
|
||||||
public String getBrand() { return brand; }
|
|
||||||
public String getPlatform() { return platform; }
|
|
||||||
public String getPartRole() { return partRole; }
|
|
||||||
public BigDecimal getPrice() { return price; }
|
|
||||||
public String getImageUrl() { return imageUrl; }
|
|
||||||
public String getBuyUrl() { return buyUrl; }
|
|
||||||
public String getCategorySlug() { return categorySlug; }
|
|
||||||
public String getCategoryGroup() { return categoryGroup; }
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user