mirror of
https://gitea.gofwd.group/Forward_Group/ballistic-builder-spring.git
synced 2026-01-20 16:51:03 -05:00
support for filtering and updating caliber
This commit is contained in:
@@ -29,11 +29,12 @@ public class CatalogController {
|
|||||||
@RequestParam(required = false) String partRole,
|
@RequestParam(required = false) String partRole,
|
||||||
@RequestParam(required = false) List<String> partRoles,
|
@RequestParam(required = false) List<String> partRoles,
|
||||||
@RequestParam(required = false, name = "brand") List<String> brands,
|
@RequestParam(required = false, name = "brand") List<String> brands,
|
||||||
|
@RequestParam(required = false, name = "caliber") List<String> calibers,
|
||||||
@RequestParam(required = false) String q,
|
@RequestParam(required = false) String q,
|
||||||
Pageable pageable
|
Pageable pageable
|
||||||
) {
|
) {
|
||||||
Pageable safe = sanitizeCatalogPageable(pageable);
|
Pageable safe = sanitizeCatalogPageable(pageable);
|
||||||
return catalogQueryService.getOptions(platform, partRole, partRoles, brands, q, safe);
|
return catalogQueryService.getOptions(platform, partRole, partRoles, brands, calibers, q, safe);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Pageable sanitizeCatalogPageable(Pageable pageable) {
|
private Pageable sanitizeCatalogPageable(Pageable pageable) {
|
||||||
|
|||||||
@@ -37,20 +37,22 @@ public class CaliberEnrichmentService {
|
|||||||
*/
|
*/
|
||||||
@Transactional
|
@Transactional
|
||||||
public RunResult runRules(int limit) {
|
public RunResult runRules(int limit) {
|
||||||
// Adjust Product entity package if needed:
|
|
||||||
// IMPORTANT: Product must be a mapped @Entity named "Product"
|
|
||||||
List<Object[]> rows = em.createQuery("""
|
List<Object[]> rows = em.createQuery("""
|
||||||
select p.id, p.name, p.description
|
select p.id, p.name, p.description
|
||||||
from Product p
|
from Product p
|
||||||
where p.deletedAt is null
|
where p.deletedAt is null
|
||||||
and not exists (
|
and not exists (
|
||||||
select 1 from ProductEnrichment e
|
select 1 from ProductEnrichment e
|
||||||
where e.productId = p.id
|
where e.productId = p.id
|
||||||
and e.enrichmentType = group.goforward.battlbuilder.enrichment.EnrichmentType.CALIBER
|
and e.enrichmentType = :etype
|
||||||
and e.status in ('PENDING_REVIEW','APPROVED')
|
and e.status in (:s1, :s2)
|
||||||
)
|
)
|
||||||
order by p.id desc
|
order by p.id desc
|
||||||
""", Object[].class)
|
""", Object[].class)
|
||||||
|
.setParameter("etype", EnrichmentType.CALIBER)
|
||||||
|
.setParameter("s1", EnrichmentStatus.PENDING_REVIEW)
|
||||||
|
.setParameter("s2", EnrichmentStatus.APPROVED)
|
||||||
.setMaxResults(limit)
|
.setMaxResults(limit)
|
||||||
.getResultList();
|
.getResultList();
|
||||||
|
|
||||||
|
|||||||
@@ -77,6 +77,9 @@ public class Product {
|
|||||||
@Column(name = "classified_at")
|
@Column(name = "classified_at")
|
||||||
private Instant classifiedAt;
|
private Instant classifiedAt;
|
||||||
|
|
||||||
|
@Column(name = "caliber_locked", nullable = false)
|
||||||
|
private Boolean caliberLocked = false;
|
||||||
|
|
||||||
@Column(name = "part_role_locked", nullable = false)
|
@Column(name = "part_role_locked", nullable = false)
|
||||||
private Boolean partRoleLocked = false;
|
private Boolean partRoleLocked = false;
|
||||||
|
|
||||||
@@ -227,6 +230,9 @@ public class Product {
|
|||||||
this.platformLocked = platformLocked;
|
this.platformLocked = platformLocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getCaliberLocked() { return caliberLocked; }
|
||||||
|
public void setCaliberLocked(Boolean caliberLocked) { this.caliberLocked = caliberLocked; }
|
||||||
|
|
||||||
public String getRawCategoryKey() { return rawCategoryKey; }
|
public String getRawCategoryKey() { return rawCategoryKey; }
|
||||||
public void setRawCategoryKey(String rawCategoryKey) {
|
public void setRawCategoryKey(String rawCategoryKey) {
|
||||||
this.rawCategoryKey = rawCategoryKey;
|
this.rawCategoryKey = rawCategoryKey;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ public enum PartRoleSource {
|
|||||||
MERCHANT_MAP,
|
MERCHANT_MAP,
|
||||||
OVERRIDE,
|
OVERRIDE,
|
||||||
RULES,
|
RULES,
|
||||||
UNKNOWN
|
UNKNOWN,
|
||||||
|
ADMIN
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,7 @@ import org.springframework.data.jpa.domain.Specification;
|
|||||||
|
|
||||||
import jakarta.persistence.criteria.JoinType;
|
import jakarta.persistence.criteria.JoinType;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
public class CatalogProductSpecifications {
|
public class CatalogProductSpecifications {
|
||||||
|
|
||||||
@@ -39,6 +40,24 @@ public class CatalogProductSpecifications {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Specification<Product> caliberIn(List<String> calibers) {
|
||||||
|
return (root, query, cb) -> {
|
||||||
|
if (calibers == null || calibers.isEmpty()) return cb.conjunction();
|
||||||
|
|
||||||
|
// normalize + drop blanks
|
||||||
|
var cleaned = calibers.stream()
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.map(String::trim)
|
||||||
|
.filter(s -> !s.isBlank())
|
||||||
|
.distinct()
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
if (cleaned.isEmpty()) return cb.conjunction();
|
||||||
|
|
||||||
|
return root.get("caliber").in(cleaned);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public static Specification<Product> queryLike(String q) {
|
public static Specification<Product> queryLike(String q) {
|
||||||
final String like = "%" + q.toLowerCase().trim() + "%";
|
final String like = "%" + q.toLowerCase().trim() + "%";
|
||||||
return (root, query, cb) -> {
|
return (root, query, cb) -> {
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package group.goforward.battlbuilder.security;
|
||||||
|
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class Authz {
|
||||||
|
|
||||||
|
public UUID requireUserUuid() {
|
||||||
|
Authentication a = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
if (a == null || !a.isAuthenticated() || a.getPrincipal() == null) {
|
||||||
|
throw new RuntimeException("Unauthorized");
|
||||||
|
}
|
||||||
|
return UUID.fromString(a.getPrincipal().toString()); // principal is UUID string in your filter
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@ public interface CatalogQueryService {
|
|||||||
String partRole,
|
String partRole,
|
||||||
List<String> partRoles,
|
List<String> partRoles,
|
||||||
List<String> brands,
|
List<String> brands,
|
||||||
|
List<String> calibers,
|
||||||
String q,
|
String q,
|
||||||
Pageable pageable
|
Pageable pageable
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,8 +8,12 @@ import group.goforward.battlbuilder.web.dto.admin.BulkUpdateResult;
|
|||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
|
|
||||||
public interface AdminProductService {
|
import java.util.List;
|
||||||
Page<ProductAdminRowDto> search(AdminProductSearchRequest request, Pageable pageable);
|
|
||||||
|
|
||||||
|
public interface AdminProductService {
|
||||||
|
|
||||||
|
Page<ProductAdminRowDto> search(AdminProductSearchRequest request, Pageable pageable);
|
||||||
BulkUpdateResult bulkUpdate(ProductBulkUpdateRequest request);
|
BulkUpdateResult bulkUpdate(ProductBulkUpdateRequest request);
|
||||||
|
List<String> distinctRoles(AdminProductSearchRequest request);
|
||||||
|
List<String> distinctCalibers(AdminProductSearchRequest request);
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package group.goforward.battlbuilder.services.admin.impl;
|
package group.goforward.battlbuilder.services.admin.impl;
|
||||||
|
|
||||||
import group.goforward.battlbuilder.model.Product;
|
import group.goforward.battlbuilder.model.Product;
|
||||||
|
import group.goforward.battlbuilder.model.enums.PartRoleSource;
|
||||||
import group.goforward.battlbuilder.repos.ProductRepository;
|
import group.goforward.battlbuilder.repos.ProductRepository;
|
||||||
import group.goforward.battlbuilder.services.admin.AdminProductService;
|
import group.goforward.battlbuilder.services.admin.AdminProductService;
|
||||||
import group.goforward.battlbuilder.domain.specs.ProductSpecifications;
|
import group.goforward.battlbuilder.domain.specs.ProductSpecifications;
|
||||||
@@ -9,12 +10,27 @@ import group.goforward.battlbuilder.web.dto.admin.BulkUpdateResult;
|
|||||||
import group.goforward.battlbuilder.web.dto.admin.ProductAdminRowDto;
|
import group.goforward.battlbuilder.web.dto.admin.ProductAdminRowDto;
|
||||||
import group.goforward.battlbuilder.web.dto.admin.ProductBulkUpdateRequest;
|
import group.goforward.battlbuilder.web.dto.admin.ProductBulkUpdateRequest;
|
||||||
|
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
|
import jakarta.persistence.PersistenceContext;
|
||||||
|
import jakarta.persistence.TypedQuery;
|
||||||
|
|
||||||
|
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||||
|
import jakarta.persistence.criteria.CriteriaQuery;
|
||||||
|
import jakarta.persistence.criteria.Predicate;
|
||||||
|
import jakarta.persistence.criteria.Root;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.jpa.domain.Specification;
|
import org.springframework.data.jpa.domain.Specification;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Transactional
|
@Transactional
|
||||||
public class AdminProductServiceImpl implements AdminProductService {
|
public class AdminProductServiceImpl implements AdminProductService {
|
||||||
@@ -70,10 +86,52 @@ public class AdminProductServiceImpl implements AdminProductService {
|
|||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- CALIBER update with lock semantics ---
|
||||||
|
if (request.getCaliber() != null) {
|
||||||
|
boolean calLocked = Boolean.TRUE.equals(p.getCaliberLocked());
|
||||||
|
boolean forceCal = Boolean.TRUE.equals(request.getForceCaliberUpdate());
|
||||||
|
|
||||||
|
if (calLocked && !forceCal) {
|
||||||
|
skippedLocked++;
|
||||||
|
} else {
|
||||||
|
String next = request.getCaliber().trim();
|
||||||
|
if (next.isEmpty()) next = null;
|
||||||
|
|
||||||
|
if ((next == null && p.getCaliber() != null) || (next != null && !next.equals(p.getCaliber()))) {
|
||||||
|
p.setCaliber(next);
|
||||||
|
|
||||||
|
// optional group
|
||||||
|
if (request.getCaliberGroup() != null) {
|
||||||
|
String g = request.getCaliberGroup().trim();
|
||||||
|
p.setCaliberGroup(g.isEmpty() ? null : g);
|
||||||
|
}
|
||||||
|
|
||||||
|
// audit fields (keep consistent with role)
|
||||||
|
p.setClassifierVersion("admin-ui");
|
||||||
|
p.setClassifiedAt(Instant.now());
|
||||||
|
p.setClassificationReason(
|
||||||
|
request.getClassificationReason() != null
|
||||||
|
? request.getClassificationReason()
|
||||||
|
: "Admin bulk override"
|
||||||
|
);
|
||||||
|
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- apply caliberLocked toggle (even if caliber isn't being changed) ---
|
||||||
|
if (request.getCaliberLocked() != null) {
|
||||||
|
if (!request.getCaliberLocked().equals(p.getCaliberLocked())) {
|
||||||
|
p.setCaliberLocked(request.getCaliberLocked());
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// --- platform update with lock semantics ---
|
// --- platform update with lock semantics ---
|
||||||
if (request.getPlatform() != null) {
|
if (request.getPlatform() != null) {
|
||||||
boolean isLocked = Boolean.TRUE.equals(p.getPlatformLocked());
|
boolean isLocked = Boolean.TRUE.equals(p.getPlatformLocked());
|
||||||
boolean override = Boolean.TRUE.equals(request.getPlatformLocked()); // request says "I'm allowed to touch locked ones"
|
boolean override = Boolean.TRUE.equals(request.getPlatformLocked()); // caller says "ok to touch locked ones"
|
||||||
|
|
||||||
if (isLocked && !override) {
|
if (isLocked && !override) {
|
||||||
skippedLocked++;
|
skippedLocked++;
|
||||||
@@ -93,21 +151,122 @@ public class AdminProductServiceImpl implements AdminProductService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- ROLE update with lock semantics ---
|
||||||
|
if (request.getPartRole() != null) {
|
||||||
|
boolean roleLocked = Boolean.TRUE.equals(p.getPartRoleLocked());
|
||||||
|
boolean force = Boolean.TRUE.equals(request.getForceRoleUpdate());
|
||||||
|
|
||||||
|
if (roleLocked && !force) {
|
||||||
|
skippedLocked++;
|
||||||
|
} else {
|
||||||
|
if (!request.getPartRole().equals(p.getPartRole())) {
|
||||||
|
p.setPartRole(request.getPartRole());
|
||||||
|
p.setPartRoleSource(PartRoleSource.ADMIN);
|
||||||
|
p.setClassifiedAt(Instant.now());
|
||||||
|
p.setClassifierVersion("admin-ui");
|
||||||
|
p.setClassificationReason(
|
||||||
|
request.getClassificationReason() != null
|
||||||
|
? request.getClassificationReason()
|
||||||
|
: "Admin bulk override"
|
||||||
|
);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- apply partRoleLocked toggle (even if partRole isn't being changed) ---
|
||||||
|
if (request.getPartRoleLocked() != null) {
|
||||||
|
if (!request.getPartRoleLocked().equals(p.getPartRoleLocked())) {
|
||||||
|
p.setPartRoleLocked(request.getPartRoleLocked());
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (changed) updated++;
|
if (changed) updated++;
|
||||||
}
|
}
|
||||||
|
|
||||||
productRepository.saveAll(products);
|
productRepository.saveAll(products);
|
||||||
productRepository.flush(); // ✅ ensures UPDATEs are executed now
|
productRepository.flush();
|
||||||
|
|
||||||
var check = productRepository.findAllById(request.getProductIds());
|
var check = productRepository.findAllById(request.getProductIds());
|
||||||
for (var p : check) {
|
for (var p : check) {
|
||||||
System.out.println(
|
System.out.println("AFTER id=" + p.getId()
|
||||||
"AFTER FLUSH id=" + p.getId()
|
+ " role=" + p.getPartRole()
|
||||||
+ " platform=" + p.getPlatform()
|
+ " roleLocked=" + p.getPartRoleLocked()
|
||||||
+ " platformLocked=" + p.getPlatformLocked()
|
+ " source=" + p.getPartRoleSource()
|
||||||
);
|
+ " reason=" + p.getClassificationReason());
|
||||||
}
|
}
|
||||||
|
|
||||||
return new BulkUpdateResult(updated, skippedLocked);
|
return new BulkUpdateResult(updated, skippedLocked);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PersistenceContext
|
||||||
|
private EntityManager em;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public List<String> distinctRoles(AdminProductSearchRequest request) {
|
||||||
|
var spec = ProductSpecifications.adminSearch(request);
|
||||||
|
|
||||||
|
CriteriaBuilder cb = em.getCriteriaBuilder();
|
||||||
|
CriteriaQuery<String> cq = cb.createQuery(String.class);
|
||||||
|
Root<Product> root = cq.from(Product.class);
|
||||||
|
|
||||||
|
// Base predicate from your existing admin search spec
|
||||||
|
Predicate base = spec != null ? spec.toPredicate(root, cq, cb) : cb.conjunction();
|
||||||
|
|
||||||
|
// Only real values
|
||||||
|
Predicate notNull = cb.isNotNull(root.get("partRole"));
|
||||||
|
Predicate notBlank = cb.notEqual(cb.trim(root.get("partRole")), "");
|
||||||
|
|
||||||
|
cq.select(root.get("partRole"))
|
||||||
|
.distinct(true)
|
||||||
|
.where(cb.and(base, notNull, notBlank))
|
||||||
|
.orderBy(cb.asc(root.get("partRole")));
|
||||||
|
|
||||||
|
TypedQuery<String> q = em.createQuery(cq);
|
||||||
|
List<String> raw = q.getResultList();
|
||||||
|
|
||||||
|
// Defensive: normalize + de-dupe in case DB has whitespace variants
|
||||||
|
List<String> out = new ArrayList<>();
|
||||||
|
for (String r : raw) {
|
||||||
|
if (r == null) continue;
|
||||||
|
String t = r.trim();
|
||||||
|
if (t.isEmpty()) continue;
|
||||||
|
if (!out.contains(t)) out.add(t);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public List<String> distinctCalibers(AdminProductSearchRequest request) {
|
||||||
|
var spec = ProductSpecifications.adminSearch(request);
|
||||||
|
|
||||||
|
CriteriaBuilder cb = em.getCriteriaBuilder();
|
||||||
|
CriteriaQuery<String> cq = cb.createQuery(String.class);
|
||||||
|
Root<Product> root = cq.from(Product.class);
|
||||||
|
|
||||||
|
Predicate base = spec != null ? spec.toPredicate(root, cq, cb) : cb.conjunction();
|
||||||
|
|
||||||
|
Predicate notNull = cb.isNotNull(root.get("caliber"));
|
||||||
|
Predicate notBlank = cb.notEqual(cb.trim(root.get("caliber")), "");
|
||||||
|
|
||||||
|
cq.select(root.get("caliber"))
|
||||||
|
.distinct(true)
|
||||||
|
.where(cb.and(base, notNull, notBlank))
|
||||||
|
.orderBy(cb.asc(root.get("caliber")));
|
||||||
|
|
||||||
|
List<String> raw = em.createQuery(cq).getResultList();
|
||||||
|
|
||||||
|
// normalize + de-dupe
|
||||||
|
List<String> out = new ArrayList<>();
|
||||||
|
for (String c : raw) {
|
||||||
|
if (c == null) continue;
|
||||||
|
String t = c.trim();
|
||||||
|
if (t.isEmpty()) continue;
|
||||||
|
if (!out.contains(t)) out.add(t);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -42,6 +42,7 @@ public class CatalogQueryServiceImpl implements CatalogQueryService {
|
|||||||
String partRole,
|
String partRole,
|
||||||
List<String> partRoles,
|
List<String> partRoles,
|
||||||
List<String> brands,
|
List<String> brands,
|
||||||
|
List<String> calibers,
|
||||||
String q,
|
String q,
|
||||||
Pageable pageable
|
Pageable pageable
|
||||||
) {
|
) {
|
||||||
@@ -68,6 +69,10 @@ public class CatalogQueryServiceImpl implements CatalogQueryService {
|
|||||||
spec = spec.and(CatalogProductSpecifications.brandNameIn(brands));
|
spec = spec.and(CatalogProductSpecifications.brandNameIn(brands));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (calibers != null && !calibers.isEmpty()) {
|
||||||
|
spec = spec.and(CatalogProductSpecifications.caliberIn(calibers));
|
||||||
|
}
|
||||||
|
|
||||||
if (q != null && !q.isBlank()) {
|
if (q != null && !q.isBlank()) {
|
||||||
spec = spec.and(CatalogProductSpecifications.queryLike(q));
|
spec = spec.and(CatalogProductSpecifications.queryLike(q));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,13 @@ import group.goforward.battlbuilder.web.dto.admin.AdminProductSearchRequest;
|
|||||||
import group.goforward.battlbuilder.web.dto.admin.ProductBulkUpdateRequest;
|
import group.goforward.battlbuilder.web.dto.admin.ProductBulkUpdateRequest;
|
||||||
import group.goforward.battlbuilder.web.dto.admin.BulkUpdateResult;
|
import group.goforward.battlbuilder.web.dto.admin.BulkUpdateResult;
|
||||||
import group.goforward.battlbuilder.web.dto.admin.ProductAdminRowDto;
|
import group.goforward.battlbuilder.web.dto.admin.ProductAdminRowDto;
|
||||||
|
import group.goforward.battlbuilder.web.dto.admin.ProductFacetsDto;
|
||||||
|
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@@ -22,20 +24,21 @@ public class AdminProductController {
|
|||||||
this.adminProductService = adminProductService;
|
this.adminProductService = adminProductService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Admin product list (paged + filterable)
|
|
||||||
*/
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public Page<ProductAdminRowDto> search(
|
public Page<ProductAdminRowDto> search(AdminProductSearchRequest request, Pageable pageable) {
|
||||||
AdminProductSearchRequest request,
|
|
||||||
Pageable pageable
|
|
||||||
) {
|
|
||||||
return adminProductService.search(request, pageable);
|
return adminProductService.search(request, pageable);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@GetMapping("/roles")
|
||||||
* Bulk admin actions (disable, hide, lock, etc.)
|
public List<String> roles(AdminProductSearchRequest request) {
|
||||||
*/
|
return adminProductService.distinctRoles(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/calibers")
|
||||||
|
public List<String> calibers(AdminProductSearchRequest request) {
|
||||||
|
return adminProductService.distinctCalibers(request);
|
||||||
|
}
|
||||||
|
|
||||||
@PatchMapping("/bulk")
|
@PatchMapping("/bulk")
|
||||||
public Map<String, Object> bulkUpdate(@RequestBody ProductBulkUpdateRequest request) {
|
public Map<String, Object> bulkUpdate(@RequestBody ProductBulkUpdateRequest request) {
|
||||||
BulkUpdateResult result = adminProductService.bulkUpdate(request);
|
BulkUpdateResult result = adminProductService.bulkUpdate(request);
|
||||||
@@ -44,4 +47,12 @@ public class AdminProductController {
|
|||||||
"skippedLockedCount", result.skippedLockedCount()
|
"skippedLockedCount", result.skippedLockedCount()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/facets")
|
||||||
|
public ProductFacetsDto facets(@RequestBody AdminProductSearchRequest request) {
|
||||||
|
return new ProductFacetsDto(
|
||||||
|
adminProductService.distinctRoles(request),
|
||||||
|
adminProductService.distinctCalibers(request)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -23,6 +23,10 @@ public class ProductAdminRowDto {
|
|||||||
private String platform;
|
private String platform;
|
||||||
private String partRole;
|
private String partRole;
|
||||||
|
|
||||||
|
private String caliber;
|
||||||
|
private String caliberGroup;
|
||||||
|
private Boolean caliberLocked;
|
||||||
|
|
||||||
private String brandName;
|
private String brandName;
|
||||||
|
|
||||||
private ImportStatus importStatus;
|
private ImportStatus importStatus;
|
||||||
@@ -45,25 +49,21 @@ public class ProductAdminRowDto {
|
|||||||
|
|
||||||
dto.id = p.getId();
|
dto.id = p.getId();
|
||||||
dto.uuid = p.getUuid();
|
dto.uuid = p.getUuid();
|
||||||
|
|
||||||
dto.name = p.getName();
|
dto.name = p.getName();
|
||||||
dto.slug = p.getSlug();
|
dto.slug = p.getSlug();
|
||||||
|
|
||||||
dto.platform = p.getPlatform();
|
dto.platform = p.getPlatform();
|
||||||
dto.partRole = p.getPartRole();
|
dto.partRole = p.getPartRole();
|
||||||
|
dto.caliber = p.getCaliber();
|
||||||
|
dto.caliberGroup = p.getCaliberGroup();
|
||||||
|
dto.caliberLocked = p.getCaliberLocked();
|
||||||
dto.brandName = (p.getBrand() != null) ? p.getBrand().getName() : null;
|
dto.brandName = (p.getBrand() != null) ? p.getBrand().getName() : null;
|
||||||
|
|
||||||
dto.importStatus = p.getImportStatus();
|
dto.importStatus = p.getImportStatus();
|
||||||
|
|
||||||
dto.visibility = p.getVisibility();
|
dto.visibility = p.getVisibility();
|
||||||
dto.status = p.getStatus();
|
dto.status = p.getStatus();
|
||||||
dto.builderEligible = p.getBuilderEligible();
|
dto.builderEligible = p.getBuilderEligible();
|
||||||
dto.adminLocked = p.getAdminLocked();
|
dto.adminLocked = p.getAdminLocked();
|
||||||
|
|
||||||
dto.adminNote = p.getAdminNote();
|
dto.adminNote = p.getAdminNote();
|
||||||
dto.mainImageUrl = p.getMainImageUrl();
|
dto.mainImageUrl = p.getMainImageUrl();
|
||||||
|
|
||||||
dto.createdAt = p.getCreatedAt();
|
dto.createdAt = p.getCreatedAt();
|
||||||
dto.updatedAt = p.getUpdatedAt();
|
dto.updatedAt = p.getUpdatedAt();
|
||||||
|
|
||||||
@@ -120,6 +120,15 @@ public class ProductAdminRowDto {
|
|||||||
this.partRole = partRole;
|
this.partRole = partRole;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getCaliber() { return caliber; }
|
||||||
|
public void setCaliber(String caliber) { this.caliber = caliber; }
|
||||||
|
|
||||||
|
public String getCaliberGroup() { return caliberGroup; }
|
||||||
|
public void setCaliberGroup(String caliberGroup) { this.caliberGroup = caliberGroup; }
|
||||||
|
|
||||||
|
public Boolean getCaliberLocked() { return caliberLocked; }
|
||||||
|
public void setCaliberLocked(Boolean caliberLocked) { this.caliberLocked = caliberLocked; }
|
||||||
|
|
||||||
public String getBrandName() {
|
public String getBrandName() {
|
||||||
return brandName;
|
return brandName;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,13 +10,23 @@ public class ProductBulkUpdateRequest {
|
|||||||
private Set<Integer> productIds;
|
private Set<Integer> productIds;
|
||||||
private String platform;
|
private String platform;
|
||||||
private Boolean platformLocked;
|
private Boolean platformLocked;
|
||||||
|
private String caliber;
|
||||||
|
private Boolean caliberLocked;
|
||||||
|
private String caliberGroup;
|
||||||
|
private Boolean forceCaliberUpdate;
|
||||||
private ProductVisibility visibility;
|
private ProductVisibility visibility;
|
||||||
private ProductStatus status;
|
private ProductStatus status;
|
||||||
|
private String partRole;
|
||||||
|
private Boolean partRoleLocked;
|
||||||
|
private String classificationReason;
|
||||||
private Boolean builderEligible;
|
private Boolean builderEligible;
|
||||||
private Boolean adminLocked;
|
private Boolean adminLocked;
|
||||||
|
|
||||||
private String adminNote;
|
private String adminNote;
|
||||||
|
private Boolean forceRoleUpdate;
|
||||||
|
|
||||||
|
public Boolean getForceRoleUpdate() { return forceRoleUpdate; }
|
||||||
|
public void setForceRoleUpdate(Boolean forceRoleUpdate) { this.forceRoleUpdate = forceRoleUpdate; }
|
||||||
|
|
||||||
|
|
||||||
// --- getters/setters ---
|
// --- getters/setters ---
|
||||||
|
|
||||||
@@ -43,4 +53,40 @@ public class ProductBulkUpdateRequest {
|
|||||||
|
|
||||||
public Boolean getPlatformLocked() { return platformLocked; }
|
public Boolean getPlatformLocked() { return platformLocked; }
|
||||||
public void setPlatformLocked(Boolean platformLocked) { this.platformLocked = platformLocked; }
|
public void setPlatformLocked(Boolean platformLocked) { this.platformLocked = platformLocked; }
|
||||||
|
|
||||||
|
public String getCaliber() { return caliber; }
|
||||||
|
public void setCaliber(String caliber) { this.caliber = caliber; }
|
||||||
|
|
||||||
|
public String getCaliberGroup() { return caliberGroup; }
|
||||||
|
public void setCaliberGroup(String caliberGroup) { this.caliberGroup = caliberGroup; }
|
||||||
|
|
||||||
|
public Boolean getCaliberLocked() { return caliberLocked; }
|
||||||
|
public void setCaliberLocked(Boolean caliberLocked) { this.caliberLocked = caliberLocked; }
|
||||||
|
|
||||||
|
public Boolean getForceCaliberUpdate() { return forceCaliberUpdate; }
|
||||||
|
public void setForceCaliberUpdate(Boolean forceCaliberUpdate) { this.forceCaliberUpdate = forceCaliberUpdate; }
|
||||||
|
|
||||||
|
public String getPartRole() {
|
||||||
|
return partRole;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPartRole(String partRole) {
|
||||||
|
this.partRole = partRole;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getPartRoleLocked() {
|
||||||
|
return partRoleLocked;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPartRoleLocked(Boolean partRoleLocked) {
|
||||||
|
this.partRoleLocked = partRoleLocked;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClassificationReason() {
|
||||||
|
return classificationReason;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClassificationReason(String classificationReason) {
|
||||||
|
this.classificationReason = classificationReason;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package group.goforward.battlbuilder.web.dto.admin;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public record ProductFacetsDto(
|
||||||
|
List<String> roles,
|
||||||
|
List<String> calibers
|
||||||
|
) {}
|
||||||
Reference in New Issue
Block a user