Skip to content
Snippets Groups Projects
Commit 029b39b5 authored by GAYDAMAKHA MIKHAIL's avatar GAYDAMAKHA MIKHAIL
Browse files

Merge branch 'feature/post_item' into 'develop'

:sparkles: add post item endpoint

See merge request !24
parents fbf7fad4 cc0be4b5
Branches
2 merge requests!25Develop,!24:sparkles: add post item endpoint
Showing
with 287 additions and 7 deletions
......@@ -24,6 +24,7 @@ dependencies {
implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.8'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation:2.5.6'
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
......
......@@ -49,7 +49,7 @@ public class WebMvcConfig implements WebMvcConfigurer {
/**
* API Mapping for retrieving all items.
*/
public static final String MAPPING_RETRIEVEALL = API_FULL_PREFIX +
public static final String MAPPING_ITEMS = API_FULL_PREFIX +
"/item";
/**
......
package fr.unistra.sil.erp.back.controller.api;
import fr.unistra.sil.erp.back.model.Item;
import fr.unistra.sil.erp.back.service.CantStoreItemException;
import fr.unistra.sil.erp.back.service.StoreItemRequest;
import fr.unistra.sil.erp.back.service.StoreItemService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import javax.validation.Valid;
import static fr.unistra.sil.erp.back.WebMvcConfig.MAPPING_ITEMS;
@Controller
public class ApiPostItemController {
private final StoreItemService service;
public ApiPostItemController(StoreItemService service) {
this.service = service;
}
/**
* Creates a product.
*
* @param requestBody request body
* @return a JSON response.
* @throws ApiServerErrorException if the request could not be served.
*/
@PostMapping(MAPPING_ITEMS)
public ResponseEntity<Item> postItem(
@Validated @RequestBody PostItemDTO requestBody
) throws ApiServerErrorException {
Item item;
try {
item = service.store(new StoreItemRequest(
requestBody.getName(),
requestBody.getPrice(),
requestBody.getSubscriberPrice(),
requestBody.getCategory()
));
} catch (CantStoreItemException e) {
throw new ApiServerErrorException(e.getMessage());
}
return new ResponseEntity<>(item, HttpStatus.CREATED);
}
}
......@@ -4,7 +4,7 @@
*/
package fr.unistra.sil.erp.back.controller.api;
import static fr.unistra.sil.erp.back.WebMvcConfig.MAPPING_RETRIEVEALL;
import static fr.unistra.sil.erp.back.WebMvcConfig.MAPPING_ITEMS;
import fr.unistra.sil.erp.back.controller.IRetrieveInfoController;
import fr.unistra.sil.erp.back.model.Item;
......@@ -40,7 +40,7 @@ public class ApiRetrieveItemsController implements IRetrieveInfoController {
* @throws ApiServerErrorException if the request could not be served.
* @throws ApiBadRequestException if the category parameter is invalid.
*/
@GetMapping(MAPPING_RETRIEVEALL)
@GetMapping(MAPPING_ITEMS)
public ResponseEntity<Object> retrieveInfo(
@RequestParam(value = "category", defaultValue = "") String cat
) throws ApiServerErrorException, ApiBadRequestException {
......
package fr.unistra.sil.erp.back.controller.api;
import com.fasterxml.jackson.annotation.JsonProperty;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Positive;
import java.math.BigDecimal;
public class PostItemDTO {
/**
* The product's name.
*/
@NotBlank
private final String name;
/**
* The product's regular price.
*/
@NotNull
@Positive
private final BigDecimal price;
/**
* The product's price for subscribers.
*/
@NotNull
@Positive
private final BigDecimal subscriberPrice;
/**
* This product's category identifier.
*/
@NotNull
@Positive
private final int category;
public PostItemDTO(
@JsonProperty("name") String name,
@JsonProperty("price") BigDecimal price,
@JsonProperty("subscriber_price") BigDecimal subscriberPrice,
@JsonProperty("category") int category
) {
this.name = name;
this.price = price;
this.subscriberPrice = subscriberPrice;
this.category = category;
}
public String getName() {
return name;
}
public BigDecimal getPrice() {
return price;
}
@JsonProperty("subscriber_price")
public BigDecimal getSubscriberPrice() {
return subscriberPrice;
}
public int getCategory() {
return category;
}
}
package fr.unistra.sil.erp.back.controller.api;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import java.util.HashMap;
import java.util.Map;
@ControllerAdvice
public class ValidationHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException ex,
HttpHeaders headers,
HttpStatus status,
WebRequest request
) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getAllErrors().forEach((error) -> {
String fieldName = ((FieldError) error).getField();
String message = error.getDefaultMessage();
errors.put(fieldName, message);
});
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
}
......@@ -4,6 +4,8 @@
*/
package fr.unistra.sil.erp.back.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.math.BigDecimal;
/**
......@@ -38,6 +40,7 @@ public class Item {
/**
* The product's price for subscribers.
*/
@JsonProperty("subscriber_price")
private final BigDecimal subscriberPrice;
/**
......
......@@ -18,4 +18,6 @@ public interface IItemsRepository {
* @return the list of items, or null if an error occurred.
*/
List<Item> getItemsFromCategory(int category);
Item store(Item item);
}
......@@ -5,10 +5,7 @@ import fr.unistra.sil.erp.back.repository.IItemsRepository;
import fr.unistra.sil.erp.back.repository.SqliteRepository;
import org.springframework.stereotype.Repository;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
......@@ -109,4 +106,49 @@ public class SqliteItemsRepository extends SqliteRepository implements IItemsRep
return res;
}
@Override
public Item store(Item item) {
String query = "INSERT INTO items (name, price, subscriberPrice, category) VALUES (?, ?, ?, ?);";
PreparedStatement ps;
try {
ps = this.conn.prepareStatement(query);
ps.setString(1, item.getName());
ps.setBigDecimal(2, item.getPrice());
ps.setBigDecimal(3, item.getSubscriberPrice());
ps.setInt(4, item.getCategory());
} catch (SQLException ex) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Failed to connect to database.", ex);
return null;
}
try {
ps.executeUpdate();
} catch (SQLException ex) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Failed to create item: " + ex.getMessage());
return null;
}
int id;
query = "SELECT MAX(id) AS max_id FROM items";
ResultSet rs;
try {
ps = this.conn.prepareStatement(query);
rs = ps.executeQuery();
} catch (SQLException ex) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Failed to find item id: " + ex.getMessage());
return null;
}
try {
id = rs.getInt("max_id");
} catch (SQLException ex) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Failed to parse item id: " + ex.getMessage());
return null;
}
return new Item(
id,
item.getName(),
item.getPrice(),
item.getSubscriberPrice(),
item.getCategory()
);
}
}
package fr.unistra.sil.erp.back.service;
public class CantStoreItemException extends Exception
{
}
package fr.unistra.sil.erp.back.service;
import java.math.BigDecimal;
public class StoreItemRequest {
/**
* The product's name.
*/
private final String name;
/**
* The product's regular price.
*/
private final BigDecimal price;
/**
* The product's price for subscribers.
*/
private final BigDecimal subscriberPrice;
/**
* This product's category identifier.
*/
private final int category;
public StoreItemRequest(String name, BigDecimal price, BigDecimal subscriberPrice, int category) {
this.name = name;
this.price = price;
this.subscriberPrice = subscriberPrice;
this.category = category;
}
public String getName() {
return name;
}
public BigDecimal getPrice() {
return price;
}
public BigDecimal getSubscriberPrice() {
return subscriberPrice;
}
public int getCategory() {
return category;
}
}
package fr.unistra.sil.erp.back.service;
import fr.unistra.sil.erp.back.model.Item;
import fr.unistra.sil.erp.back.repository.IItemsRepository;
import org.springframework.stereotype.Service;
@Service
public class StoreItemService {
private final IItemsRepository repository;
public StoreItemService(IItemsRepository repository) {
this.repository = repository;
}
public Item store(StoreItemRequest request) throws CantStoreItemException {
Item stored = repository.store(new Item(
null,
request.getName(),
request.getPrice(),
request.getSubscriberPrice(),
request.getCategory()
));
if (stored == null) {
throw new CantStoreItemException();
}
return stored;
}
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment