Compare commits

1 Commits

12 changed files with 444 additions and 0 deletions

View File

@@ -0,0 +1,32 @@
package com.celestialarchives.celestialarchives.api;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.ArrayList;
import java.util.List;
public class ApiResponse {
final static Logger LOG = LogManager.getLogger(ApiResponse.class);
private List<String> errors = new ArrayList<>();
public static ApiResponse fromErrors (String... errors){
ApiResponse apiResponse = new ApiResponse();
for (String err : errors){
apiResponse.addError(err);
}
return apiResponse;
}
public void addError(String err) {
LOG.error("API Response ERROR: " + err);
errors.add(err);
}
public List<String> getErrors() {
return errors;
}
public boolean isSuccessful () {return errors.isEmpty();}
}

View File

@@ -0,0 +1,141 @@
package com.celestialarchives.celestialarchives.controller;
import com.celestialarchives.celestialarchives.api.ApiResponse;
import com.celestialarchives.celestialarchives.entity.hoardable.Hoardable;
import com.celestialarchives.celestialarchives.entity.hoardable.HoardableCategory;
import com.celestialarchives.celestialarchives.entity.hoardable.HoardableField;
import com.celestialarchives.celestialarchives.repository.HoardableCategoryRepository;
import com.celestialarchives.celestialarchives.repository.HoardableFieldTypeRepository;
import com.celestialarchives.celestialarchives.repository.HoardableRepository;
import com.celestialarchives.celestialarchives.utils.HoardableUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/hoardable")
public class HoardableController {
@Autowired
private HoardableRepository hoardableRepository;
@Autowired
private HoardableCategoryRepository hoardableCategoryRepository;
@Autowired
private HoardableFieldTypeRepository hoardableFieldTypeRepository;
@CrossOrigin
@PostMapping(value = "/category")
@Transactional(propagation = Propagation.REQUIRED)
public ResponseEntity<ApiResponse> createHoardableCategory(@RequestBody HoardableCategory category) {
ApiResponse apiResponse = new ApiResponse();
if (category.getDisplayName().isEmpty()) {
apiResponse = ApiResponse.fromErrors("Name must not be blank!");
} else {
for (HoardableField field : category.getFields()) {
field.setHoardableCategory(category);
field.setSystemName(HoardableUtil.generateSystemName(field.getDisplayName()));
field.setFieldType(hoardableFieldTypeRepository.getTypeByCode(field.getFieldType().getCode()).get(0));
}
category.setSystemName(HoardableUtil.generateSystemName(category.getDisplayName()));
hoardableCategoryRepository.save(category);
}
return apiResponse.isSuccessful()
? new ResponseEntity(apiResponse, HttpStatus.CREATED)
: new ResponseEntity(apiResponse, HttpStatus.BAD_REQUEST);
}
@CrossOrigin
@GetMapping(value = "categories")
public List<HoardableCategory> getAllCategories() {
return hoardableCategoryRepository.findAll();
}
// TODO: countHoardableCategories(), searchHoardablesByNameAndCategory(), searchHoardablesByName(), countSearchResults()
@CrossOrigin
@GetMapping("items")
public List<HoardableCategory> getCategoryById(@RequestParam("categoryId") Integer categoryId) {
return hoardableCategoryRepository.getCategoryById(categoryId);
}
@CrossOrigin
@GetMapping("itemsByCategory")
public List<Hoardable> getItemsByCategoryId(@RequestParam("categoryId") Integer categoryId, @RequestParam("page") int page, @RequestParam("size") int size) {
Pageable pageable = PageRequest.of(page, size);
return hoardableRepository.getHoardablesByCategoryId(categoryId, pageable);
}
@CrossOrigin
@PostMapping(value = "new")
@Transactional(propagation = Propagation.REQUIRED)
public ResponseEntity<ApiResponse> createTrackedItem(@RequestBody Hoardable hoardable) {
ApiResponse apiResponse = new ApiResponse();
HoardableCategory category = hoardableCategoryRepository.getReferenceById(hoardable.getCategory().getId());
for (HoardableField field : hoardable.getFields()) {
field.setHoardable(hoardable);
field.setSystemName(HoardableUtil.generateSystemName(field.getDisplayName()));
field.setFieldType(hoardableFieldTypeRepository.getTypeByCode(field.getFieldType().getCode()).get(0));
}
hoardable.setCategory(category);
List<Hoardable> existingHoardables = category.getHoardables();
existingHoardables.add(hoardable);
category.setHoardables(existingHoardables);
hoardableCategoryRepository.save(category);
return apiResponse.isSuccessful()
? new ResponseEntity(apiResponse, HttpStatus.CREATED)
: new ResponseEntity(apiResponse, HttpStatus.BAD_REQUEST);
}
@CrossOrigin
@GetMapping(value = "/item/detail")
public List<Hoardable> getItemDetailsById(@RequestParam("id") Integer id) {
return hoardableRepository.getHoardableById(id);
}
@CrossOrigin
@PostMapping(value = "/item/update")
@Transactional(propagation = Propagation.REQUIRED)
public ResponseEntity<ApiResponse> updateHoardable(@RequestParam("id") Integer id, @RequestParam("categoryId") Integer categoryId, @RequestBody Hoardable hoardable) {
ApiResponse apiResponse = new ApiResponse();
Hoardable hoardableFromDao = hoardableRepository.getReferenceById(id);
hoardableFromDao.setCategory(hoardableCategoryRepository.getReferenceById(categoryId));
for (HoardableField daoField : hoardableFromDao.getFields()) {
for (HoardableField field : hoardable.getFields()) {
field.setHoardable(hoardable);
if (daoField.getId() == field.getId()) {
daoField.setValue(field.getValue());
}
}
}
hoardableRepository.save(hoardableFromDao);
return apiResponse.isSuccessful()
? new ResponseEntity(apiResponse, HttpStatus.CREATED)
: new ResponseEntity(apiResponse, HttpStatus.BAD_REQUEST);
}
// Counts
@CrossOrigin
@GetMapping(value = "itemCount")
public long countHoardablesByCategoryId(@RequestParam("categoryId") Integer categoryId) {
return hoardableRepository.countAllByCategoryId(categoryId);
}
}

View File

@@ -0,0 +1,22 @@
package com.celestialarchives.celestialarchives.entity;
import jakarta.persistence.*;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
@MappedSuperclass
@Data
@Getter
@Setter
public class ReferenceData {
@Id
@Column(name = "ref_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "ref_cd")
private String code;
@Column(name = "ref_desc")
private String desc;
}

View File

@@ -0,0 +1,28 @@
package com.celestialarchives.celestialarchives.entity.hoardable;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.persistence.*;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Data
@Getter
@Setter
@Entity
@Table(name = "hoardable_item")
public class Hoardable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "hoardable_item_id")
private int id;
@JoinColumn(name = "hoardable_category_id", referencedColumnName = "hoardable_category_id")
@ManyToOne(targetEntity = HoardableCategory.class)
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private HoardableCategory category;
@OneToMany(mappedBy = "hoardable", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@OrderBy("sortIndex asc")
private List<HoardableField> fields;
}

View File

@@ -0,0 +1,56 @@
package com.celestialarchives.celestialarchives.entity.hoardable;
import com.celestialarchives.celestialarchives.utils.HoardableUtil;
import jakarta.persistence.*;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import java.time.Instant;
import java.util.List;
@Data
@NoArgsConstructor
@Getter
@Setter
@Entity
@Table(name = "hoardable_category")
public class HoardableCategory {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "hoardable_category_id")
private int id;
@Column(name = "hoardable_category_display_name")
private String displayName;
@Column(name = "hoardable_category_system_name")
private String systemName;
@OneToMany(mappedBy = "hoardableCategory", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@OrderBy("sortIndex asc")
private List<HoardableField> fields;
@Column(name = "hoardable_category_nav_index")
private int navIndex;
@OneToMany(mappedBy = "category", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<Hoardable> hoardables;
@CreationTimestamp
@Column(name = "created")
private Instant createdOn;
@UpdateTimestamp
@Column(name = "updated")
private Instant updatedOn;
public HoardableCategory(String displayName, List<HoardableField> fields, int navIndex) {
this.displayName = displayName;
this.systemName = HoardableUtil.generateSystemName(displayName);
this.fields = fields;
this.navIndex = navIndex;
}
public HoardableCategory(String displayName, int navIndex) {
this.displayName = displayName;
this.systemName = HoardableUtil.generateSystemName(displayName);
this.navIndex = navIndex;
}
}

View File

@@ -0,0 +1,69 @@
package com.celestialarchives.celestialarchives.entity.hoardable;
import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import java.time.Instant;
@Data
@NoArgsConstructor
@Getter
@Setter
@Entity
@Table(name = "hoardable_field")
public class HoardableField {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "hoardable_field_id")
private int id;
@Column(name = "hoardable_field_display_name")
private String displayName;
@Column(name = "hoardable_field_system_name")
private String systemName;
@Column(name = "hoardable_field_value")
// If FieldType is select/dropdown, value is set as comma-separated and then split by ','
private String value;
@Column(name = "hoardable_field_header_indicator")
private boolean isListHeader;
@Column(name = "hoardable_field_sort_index")
private int sortIndex;
@JoinColumn(name = "hoardable_field_field_type_id")
@ManyToOne(fetch = FetchType.EAGER)
private HoardableFieldType fieldType;
@JoinColumn(name = "hoardable_category_id", referencedColumnName = "hoardable_category_id")
@ManyToOne(targetEntity = HoardableCategory.class)
@JsonIgnore
private HoardableCategory hoardableCategory;
@JoinColumn(name = "hoardable_item_id")
@ManyToOne(targetEntity = Hoardable.class)
@JsonIgnore
private Hoardable hoardable;
@CreationTimestamp
@Column(name = "created")
private Instant createdOn;
@UpdateTimestamp
@Column(name = "updated")
private Instant updatedOn;
public HoardableField(String displayName, String systemName, String value, boolean isListHeader, int sortIndex, HoardableFieldType fieldType) {
this.displayName = displayName;
this.systemName = systemName;
this.value = value;
this.isListHeader = isListHeader;
this.sortIndex = sortIndex;
this.fieldType = fieldType;
}
public HoardableField(String displayName, String systemName, String value, boolean isListHeader, int sortIndex, HoardableFieldType fieldType, HoardableCategory hoardableCategory) {
this.displayName = displayName;
this.systemName = systemName;
this.value = value;
this.isListHeader = isListHeader;
this.sortIndex = sortIndex;
this.fieldType = fieldType;
this.hoardableCategory = hoardableCategory;
}
}

View File

@@ -0,0 +1,17 @@
package com.celestialarchives.celestialarchives.entity.hoardable;
import com.celestialarchives.celestialarchives.entity.ReferenceData;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
@Data
@Getter
@Setter
@Entity
@Table(name = "hoardable_field_type", catalog = "celestial_ref")
public class HoardableFieldType extends ReferenceData {
private String systemName;
}

View File

@@ -0,0 +1,16 @@
package com.celestialarchives.celestialarchives.repository;
import com.celestialarchives.celestialarchives.entity.hoardable.HoardableCategory;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface HoardableCategoryRepository extends JpaRepository<HoardableCategory,Integer> {
List<HoardableCategory> getHoardableCategoriesBySystemName(String systemName);
@Query("from HoardableCategory h where h.id = ?1")
List<HoardableCategory> getCategoryById(int id);
}

View File

@@ -0,0 +1,17 @@
package com.celestialarchives.celestialarchives.repository;
import com.celestialarchives.celestialarchives.entity.hoardable.HoardableField;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface HoardableFieldRepository extends JpaRepository<HoardableField, Integer> {
@Query("from HoardableField h where h.hoardableCategory.id = ?1 order by h.sortIndex asc")
List<HoardableField> getFieldsByCategoryId(int categoryId);
@Query("from HoardableField h where h.hoardable.id = ?1 order by h.sortIndex asc")
List<HoardableField> getFieldsByHoardableId(int hoardableId);
}

View File

@@ -0,0 +1,17 @@
package com.celestialarchives.celestialarchives.repository;
import com.celestialarchives.celestialarchives.entity.hoardable.HoardableFieldType;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface HoardableFieldTypeRepository extends JpaRepository<HoardableFieldType, Integer> {
@Query("from HoardableFieldType r where r.code = ?1")
List<HoardableFieldType> getTypeByCode(String code);
@Query("from HoardableFieldType r order by r.id asc")
List<HoardableFieldType> getAllTypes();
}

View File

@@ -0,0 +1,21 @@
package com.celestialarchives.celestialarchives.repository;
import com.celestialarchives.celestialarchives.entity.hoardable.Hoardable;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface HoardableRepository extends JpaRepository<Hoardable, Integer> {
@Query("from Hoardable h where h.category.id = ?1")
List<Hoardable> getHoardablesByCategoryId(int categoryId, Pageable pageable);
@Query("select count(h) from Hoardable h where h.category.id = ?1")
Long countAllByCategoryId(int categoryId);
@Query("from Hoardable h where h.id = ?1")
List<Hoardable> getHoardableById(int id);
}

View File

@@ -0,0 +1,8 @@
package com.celestialarchives.celestialarchives.utils;
public class HoardableUtil {
public static String generateSystemName(String displayName) {
String out = displayName.replaceAll("\s", "");
return out.toLowerCase();
}
}