diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e097a2e --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.idea/ +.vscode/ +00-backend/target/ +01-frontend/node_modules/ diff --git a/00-backend/README.md b/00-backend/README.md new file mode 100644 index 0000000..1adf6d8 --- /dev/null +++ b/00-backend/README.md @@ -0,0 +1,30 @@ +# DPShop Backend + +# Compile & Run + +## Prerequisites + +- ``git`` installed & added to PATH +- Java Development Kit 17 (we recommend using OpenJDK with Hotspot) installed & added to PATH +- Maven >= 3.9.9 installed & added to PATH +- An Internet Connection (to download the Maven Dependencies) + + +## Compile + +1. Make sure you fulfill all prerequisites +2. Clone files & submodules with: + ```shell + git clone git@github.com:FlorianSpeicher04/webshop.git + ``` +3. (Optional) change the ``BASE_PORT`` in [WebshopApplication.java](src/main/java/de/htwsaar/webshop/WebshopApplication.java) from 8085 to something else +4. Compile with: + ```shell + mvn clean package + ``` + +# Contributors +- Laura Katharina Dolibois +- Mathusan Saravanapavan +- Florian Speicher +- Tim Wall \ No newline at end of file diff --git a/00-backend/pom.xml b/00-backend/pom.xml index 575da99..1acb389 100644 --- a/00-backend/pom.xml +++ b/00-backend/pom.xml @@ -53,6 +53,20 @@ spring-boot-starter-test test + + org.springframework.boot + spring-boot-starter-validation + 3.4.1 + + + org.xerial + sqlite-jdbc + 3.41.2.2 + + + org.hibernate.orm + hibernate-community-dialects + diff --git a/00-backend/src/main/java/de/htwsaar/webshop/WebshopApplication.java b/00-backend/src/main/java/de/htwsaar/webshop/WebshopApplication.java index db977cf..9bb5a36 100644 --- a/00-backend/src/main/java/de/htwsaar/webshop/WebshopApplication.java +++ b/00-backend/src/main/java/de/htwsaar/webshop/WebshopApplication.java @@ -5,8 +5,10 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class WebshopApplication { + private static final String BASE_PORT = "8085"; public static void main(String[] args) { + System.setProperty("server.port", BASE_PORT); SpringApplication.run(WebshopApplication.class, args); } diff --git a/00-backend/src/main/java/de/htwsaar/webshop/config/ControllerPathConfig.java b/00-backend/src/main/java/de/htwsaar/webshop/config/ControllerPathConfig.java new file mode 100644 index 0000000..a603e0e --- /dev/null +++ b/00-backend/src/main/java/de/htwsaar/webshop/config/ControllerPathConfig.java @@ -0,0 +1,19 @@ +package de.htwsaar.webshop.config; + +public class ControllerPathConfig { + //HealthController + public static final String HEALTH = "/health"; + + //ErrorController + public static final String ERROR = "/error"; + + //ItemController + public static final String ARTICLE_BASE = "/item"; + public static final String ARTICLE_ADD = "/item/add"; + public static final String ARTICLE_GET = "/item/get"; + public static final String ARTICLE_GETALL = "/item/getAll"; + + //ImageController + public static final String IMAGE_BASE = "/image"; + public static final String IMAGE_ADD = "/image/add"; +} diff --git a/00-backend/src/main/java/de/htwsaar/webshop/config/ParameterConfig.java b/00-backend/src/main/java/de/htwsaar/webshop/config/ParameterConfig.java new file mode 100644 index 0000000..7d4b2a0 --- /dev/null +++ b/00-backend/src/main/java/de/htwsaar/webshop/config/ParameterConfig.java @@ -0,0 +1,14 @@ +package de.htwsaar.webshop.config; + +public class ParameterConfig { + + public static final String PARAM_ID = "id"; + public static final String PARAM_UUID = "uuid"; + public static final String PARAM_NAME = "name"; + public static final String PARAM_DESCRIPTION = "description"; + public static final String PARAM_PRICE = "price"; + public static final String PARAM_DISCOUNT = "discount"; + public static final String PARAM_CATEGORY = "category"; + public static final String PARAM_STOCK = "stock"; + +} diff --git a/00-backend/src/main/java/de/htwsaar/webshop/controller/ArticleController.java b/00-backend/src/main/java/de/htwsaar/webshop/controller/ArticleController.java new file mode 100644 index 0000000..c1c16a1 --- /dev/null +++ b/00-backend/src/main/java/de/htwsaar/webshop/controller/ArticleController.java @@ -0,0 +1,92 @@ +package de.htwsaar.webshop.controller; + +import de.htwsaar.webshop.model.ArticleModel; +import de.htwsaar.webshop.repository.entities.Article; +import de.htwsaar.webshop.service.ArticleModelFactory; +import de.htwsaar.webshop.service.ArticleService; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; +import java.util.UUID; + +import static de.htwsaar.webshop.config.ControllerPathConfig.*; +import static de.htwsaar.webshop.config.ParameterConfig.*; +import static de.htwsaar.webshop.util.LoggerUtil.logRequest; + +@RestController +@Slf4j +public class ArticleController { + private final ArticleService articleService; + private final ArticleModelFactory articleModelFactory; + + @Autowired + public ArticleController(ArticleService articleService, ArticleModelFactory articleModelFactory) { + this.articleService = articleService; + this.articleModelFactory = articleModelFactory; + } + + @RequestMapping(path = ARTICLE_GETALL, method = RequestMethod.GET, produces = "application/json") + public ResponseEntity> getAll(HttpServletRequest request) { + logRequest(request); + return ResponseEntity.ok(articleModelFactory.from(articleService.findAll())); + } + + @RequestMapping(path = ARTICLE_GET, method = RequestMethod.GET, produces = "application/json") + public ResponseEntity getByUUID(HttpServletRequest request, + @RequestParam(value = PARAM_UUID) String uuid) { + logRequest(request); + return ResponseEntity.ok(articleModelFactory.from(articleService.findByUUID(uuid))); + } + + @RequestMapping(path = ARTICLE_ADD, method = RequestMethod.POST, produces = "application/json") + public ResponseEntity add(HttpServletRequest request, + @RequestParam(value = PARAM_NAME) String name, + @RequestParam(value = PARAM_STOCK) String stock, + @RequestParam(value = PARAM_DESCRIPTION) String description, + @RequestParam(value = PARAM_PRICE) String price, + @RequestParam(value = PARAM_DISCOUNT) String discount, + @RequestParam(value = PARAM_CATEGORY) String category) { + logRequest(request); + int stockInt; + int priceInt; + int discountInt; + try { + stockInt = Integer.parseInt(stock); + priceInt = Integer.parseInt(price); + discountInt = Integer.parseInt(discount); + if (priceInt < 0 || + stockInt < 0 || + discountInt > 100 || + discountInt < 0) { + return ResponseEntity.badRequest().body(false); + } + } catch (Exception e) { + log.warn("[{}] failed Validation: {}, sending bad request", request.getRequestURI(), e.getMessage()); + return ResponseEntity.badRequest().body(false); + } + + Article a = articleService.save(new Article( + 0L, + UUID.randomUUID().toString(), + stockInt, + name, + description, + priceInt, + discountInt, + category + )); + return ResponseEntity.ok(a != null); + } + + + +} diff --git a/00-backend/src/main/java/de/htwsaar/webshop/controller/ErrorController.java b/00-backend/src/main/java/de/htwsaar/webshop/controller/ErrorController.java new file mode 100644 index 0000000..6cb4595 --- /dev/null +++ b/00-backend/src/main/java/de/htwsaar/webshop/controller/ErrorController.java @@ -0,0 +1,65 @@ +package de.htwsaar.webshop.controller; + +import jakarta.servlet.RequestDispatcher; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.io.Resource; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import static de.htwsaar.webshop.config.ControllerPathConfig.ERROR; +import static de.htwsaar.webshop.util.LoggerUtil.logRequest; + + +/** + * Controller for handling application errors. + * This class implements the {@link org.springframework.boot.web.servlet.error.ErrorController} + * interface to provide custom error responses for the application. + *

+ * It uses predefined templates to replace placeholders with actual error details + * such as the error code, name, and timestamp. + *

+ */ +@RestController +@Slf4j +public class ErrorController implements org.springframework.boot.web.servlet.error.ErrorController { + + /** + * Handles error responses for the application. + * + * @param request the HTTP servlet request containing error details. + * @return a {@link ResponseEntity} containing the formatted error {@link Resource}. + */ + @RequestMapping(ERROR) + public ResponseEntity error(HttpServletRequest request) { + log.info("Request Error on: {}", request.getRequestURI()); + + // get Error Code & Name + Object errorCodeUnCast = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE); + int errorCode; + if (errorCodeUnCast == null) { + errorCode = 404; + log.info("[{}:error()] direct request to error page! Using default errorCode '{}'", + ErrorController.class.getSimpleName(), errorCode); + } else { + errorCode = (Integer) errorCodeUnCast; + } + + Object errorNameUnCast = request.getAttribute(RequestDispatcher.ERROR_MESSAGE); + String errorName; + if (errorNameUnCast == null) { + errorName = "Not Found"; + log.info("[{}:error()] direct request to error page! Using default errorName '{}'", + ErrorController.class.getSimpleName(), errorName); + } else { + errorName = (String) errorNameUnCast; + } + + log.warn("[{}] ErrorCode: {}, ErrorName: {}", request.getRequestURI(), errorCode, errorName); + + //replace + return ResponseEntity.status(errorCode).body(errorName); + } +} diff --git a/00-backend/src/main/java/de/htwsaar/webshop/controller/HealthController.java b/00-backend/src/main/java/de/htwsaar/webshop/controller/HealthController.java new file mode 100644 index 0000000..73cbf63 --- /dev/null +++ b/00-backend/src/main/java/de/htwsaar/webshop/controller/HealthController.java @@ -0,0 +1,20 @@ +package de.htwsaar.webshop.controller; + +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import static de.htwsaar.webshop.config.ControllerPathConfig.HEALTH; +import static de.htwsaar.webshop.util.LoggerUtil.logRequest; + +@RestController +@Slf4j +public class HealthController { + + @RequestMapping(HEALTH) + String getHealth(HttpServletRequest request) { + logRequest(request); + return "OK"; + } +} diff --git a/00-backend/src/main/java/de/htwsaar/webshop/model/ArticleModel.java b/00-backend/src/main/java/de/htwsaar/webshop/model/ArticleModel.java new file mode 100644 index 0000000..1fc5561 --- /dev/null +++ b/00-backend/src/main/java/de/htwsaar/webshop/model/ArticleModel.java @@ -0,0 +1,25 @@ +package de.htwsaar.webshop.model; + +import jakarta.annotation.Nullable; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import org.antlr.v4.runtime.misc.NotNull; + +/** + * What the Frontend gets when requesting an Article, POJO + */ +@AllArgsConstructor +@Setter +@Getter +public class ArticleModel { + private long id; + private String uuid; + private String name; + private String description; + private int price100; + private int discount100; + private int stock; + private String category; + private double rating; +} diff --git a/00-backend/src/main/java/de/htwsaar/webshop/repository/ArticleRepository.java b/00-backend/src/main/java/de/htwsaar/webshop/repository/ArticleRepository.java new file mode 100644 index 0000000..d69fccb --- /dev/null +++ b/00-backend/src/main/java/de/htwsaar/webshop/repository/ArticleRepository.java @@ -0,0 +1,15 @@ +package de.htwsaar.webshop.repository; + +import de.htwsaar.webshop.repository.entities.Article; +import lombok.NonNull; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface ArticleRepository extends JpaRepository { + Optional
findArticleById(@NonNull Long id); + Optional
findArticleByName(@NonNull String Name); + Optional
findArticleByUuid(@NonNull String uuid); +} diff --git a/00-backend/src/main/java/de/htwsaar/webshop/repository/ImageRepository.java b/00-backend/src/main/java/de/htwsaar/webshop/repository/ImageRepository.java new file mode 100644 index 0000000..bd0b8e7 --- /dev/null +++ b/00-backend/src/main/java/de/htwsaar/webshop/repository/ImageRepository.java @@ -0,0 +1,16 @@ +package de.htwsaar.webshop.repository; + +import de.htwsaar.webshop.repository.entities.Image; +import jakarta.validation.constraints.NotNull; +import lombok.NonNull; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface ImageRepository extends JpaRepository { + List findAllByArticleId(@NonNull Long articleId); + + Image findImageByArticleId(@NotNull Long articleId); +} diff --git a/00-backend/src/main/java/de/htwsaar/webshop/repository/ReviewRepository.java b/00-backend/src/main/java/de/htwsaar/webshop/repository/ReviewRepository.java new file mode 100644 index 0000000..19d0c83 --- /dev/null +++ b/00-backend/src/main/java/de/htwsaar/webshop/repository/ReviewRepository.java @@ -0,0 +1,15 @@ +package de.htwsaar.webshop.repository; + +import de.htwsaar.webshop.repository.entities.Review; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.stream.Stream; + +@Repository +public interface ReviewRepository extends JpaRepository { + Stream streamReviewsByArticleId(@NotNull @Positive Long id); +} diff --git a/00-backend/src/main/java/de/htwsaar/webshop/repository/entities/Article.java b/00-backend/src/main/java/de/htwsaar/webshop/repository/entities/Article.java new file mode 100644 index 0000000..da445f5 --- /dev/null +++ b/00-backend/src/main/java/de/htwsaar/webshop/repository/entities/Article.java @@ -0,0 +1,35 @@ +package de.htwsaar.webshop.repository.entities; + +import jakarta.annotation.*; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import lombok.*; + +@Entity +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class Article { + @Id + @NonNull + private Long id; + @NotNull + private String uuid; + @Min(0) + private Integer stock; + @NotNull + private String name; + @Nullable + private String description; + @Min(0) + private Integer price100; + @Min(0) + @Max(100) + private Integer discount100; + @Nullable + private String category; +} diff --git a/00-backend/src/main/java/de/htwsaar/webshop/repository/entities/Image.java b/00-backend/src/main/java/de/htwsaar/webshop/repository/entities/Image.java new file mode 100644 index 0000000..170e48f --- /dev/null +++ b/00-backend/src/main/java/de/htwsaar/webshop/repository/entities/Image.java @@ -0,0 +1,19 @@ +package de.htwsaar.webshop.repository.entities; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; + +@Entity +@Getter +public class Image { + @Id + private Long id; + @NotNull + private Long articleId; + @NotNull + @NotEmpty + private String uri; +} diff --git a/00-backend/src/main/java/de/htwsaar/webshop/repository/entities/Review.java b/00-backend/src/main/java/de/htwsaar/webshop/repository/entities/Review.java new file mode 100644 index 0000000..2738a64 --- /dev/null +++ b/00-backend/src/main/java/de/htwsaar/webshop/repository/entities/Review.java @@ -0,0 +1,27 @@ +package de.htwsaar.webshop.repository.entities; + +import jakarta.annotation.Nullable; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; +import lombok.Getter; +import lombok.Setter; + +@Entity +@Getter +@Setter +public class Review { + @Id + private Long id; + @Nullable + private String content; + @NotNull + @Positive + private Long articleId; + @NotNull + @Positive + @Max(10) + private Integer rating; +} diff --git a/00-backend/src/main/java/de/htwsaar/webshop/service/ArticleModelFactory.java b/00-backend/src/main/java/de/htwsaar/webshop/service/ArticleModelFactory.java new file mode 100644 index 0000000..bb5d21b --- /dev/null +++ b/00-backend/src/main/java/de/htwsaar/webshop/service/ArticleModelFactory.java @@ -0,0 +1,11 @@ +package de.htwsaar.webshop.service; + +import de.htwsaar.webshop.model.ArticleModel; +import de.htwsaar.webshop.repository.entities.Article; + +import java.util.List; + +public interface ArticleModelFactory { + ArticleModel from(Article article); + List from(List
articles); +} diff --git a/00-backend/src/main/java/de/htwsaar/webshop/service/ArticleService.java b/00-backend/src/main/java/de/htwsaar/webshop/service/ArticleService.java new file mode 100644 index 0000000..7bce06e --- /dev/null +++ b/00-backend/src/main/java/de/htwsaar/webshop/service/ArticleService.java @@ -0,0 +1,13 @@ +package de.htwsaar.webshop.service; + +import de.htwsaar.webshop.repository.entities.Article; + +import java.util.List; + +public interface ArticleService { + List
findAll(); + Article findByUUID(String uuid); + void delete(Long id); + Article save(Article article); + double getRating(Long id); +} diff --git a/00-backend/src/main/java/de/htwsaar/webshop/service/ImageService.java b/00-backend/src/main/java/de/htwsaar/webshop/service/ImageService.java new file mode 100644 index 0000000..b9d31e8 --- /dev/null +++ b/00-backend/src/main/java/de/htwsaar/webshop/service/ImageService.java @@ -0,0 +1,11 @@ +package de.htwsaar.webshop.service; + +import de.htwsaar.webshop.repository.entities.Image; + +import java.util.List; + +public interface ImageService { + List getImageByItemId(Long itemId); + Image getImageByArticleId(Long imageId); + Image saveImage(Image image); +} diff --git a/00-backend/src/main/java/de/htwsaar/webshop/service/impl/ArticleModelFactoryImpl.java b/00-backend/src/main/java/de/htwsaar/webshop/service/impl/ArticleModelFactoryImpl.java new file mode 100644 index 0000000..e82208f --- /dev/null +++ b/00-backend/src/main/java/de/htwsaar/webshop/service/impl/ArticleModelFactoryImpl.java @@ -0,0 +1,48 @@ +package de.htwsaar.webshop.service.impl; + +import de.htwsaar.webshop.model.ArticleModel; +import de.htwsaar.webshop.repository.entities.Article; +import de.htwsaar.webshop.service.ArticleModelFactory; +import de.htwsaar.webshop.service.ArticleService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +@Service +@Slf4j +public class ArticleModelFactoryImpl implements ArticleModelFactory { + + private final ArticleService articleService; + + @Autowired + public ArticleModelFactoryImpl(ArticleService articleService) { + this.articleService = articleService; + } + + @Override + public ArticleModel from(Article article) { + return new ArticleModel( + article.getId(), + article.getUuid(), + article.getName(), + article.getDescription(), + article.getPrice100(), + article.getDiscount100(), + article.getStock(), + article.getCategory(), + articleService.getRating(article.getId()) + ); + } + + @Override + public List from(List
articles) { + List articleModels = new ArrayList<>(); + for (Article article : articles) { + articleModels.add(from(article)); + } + return articleModels; + } +} diff --git a/00-backend/src/main/java/de/htwsaar/webshop/service/impl/ArticleServiceImpl.java b/00-backend/src/main/java/de/htwsaar/webshop/service/impl/ArticleServiceImpl.java new file mode 100644 index 0000000..e2a9e8e --- /dev/null +++ b/00-backend/src/main/java/de/htwsaar/webshop/service/impl/ArticleServiceImpl.java @@ -0,0 +1,50 @@ +package de.htwsaar.webshop.service.impl; + +import de.htwsaar.webshop.repository.ArticleRepository; +import de.htwsaar.webshop.repository.ReviewRepository; +import de.htwsaar.webshop.repository.entities.Article; +import de.htwsaar.webshop.repository.entities.Review; +import de.htwsaar.webshop.service.ArticleService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Slf4j +public class ArticleServiceImpl implements ArticleService { + private final ArticleRepository articleRepository; + private final ReviewRepository reviewRepository; + + @Autowired + public ArticleServiceImpl(ArticleRepository articleRepository, ReviewRepository reviewRepository) { + this.articleRepository = articleRepository; + this.reviewRepository = reviewRepository; + } + + @Override + public List
findAll() { + return articleRepository.findAll(); + } + + @Override + public Article findByUUID(String uuid) { + return articleRepository.findArticleByUuid(uuid).orElse(null); + } + + @Override + public void delete(Long id) { + articleRepository.deleteById(id); + } + + @Override + public Article save(Article article) { + return articleRepository.save(article); + } + + @Override + public double getRating(Long id) { + return reviewRepository.streamReviewsByArticleId(id).mapToInt(Review::getRating).average().orElse(-1); + } +} diff --git a/00-backend/src/main/java/de/htwsaar/webshop/service/impl/ImageServiceImpl.java b/00-backend/src/main/java/de/htwsaar/webshop/service/impl/ImageServiceImpl.java new file mode 100644 index 0000000..de45cb7 --- /dev/null +++ b/00-backend/src/main/java/de/htwsaar/webshop/service/impl/ImageServiceImpl.java @@ -0,0 +1,37 @@ +package de.htwsaar.webshop.service.impl; + +import de.htwsaar.webshop.repository.ImageRepository; +import de.htwsaar.webshop.repository.entities.Image; +import de.htwsaar.webshop.service.ImageService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Slf4j +public class ImageServiceImpl implements ImageService { + private final ImageRepository imageRepository; + + @Autowired + public ImageServiceImpl(ImageRepository imageRepository) { + this.imageRepository = imageRepository; + } + + + @Override + public List getImageByItemId(Long itemId) { + return imageRepository.findAllByArticleId(itemId); + } + + @Override + public Image getImageByArticleId(Long imageId) { + return imageRepository.findImageByArticleId(imageId); + } + + @Override + public Image saveImage(Image image) { + return imageRepository.save(image); + } +} diff --git a/00-backend/src/main/java/de/htwsaar/webshop/util/LoggerUtil.java b/00-backend/src/main/java/de/htwsaar/webshop/util/LoggerUtil.java new file mode 100644 index 0000000..38c9bf2 --- /dev/null +++ b/00-backend/src/main/java/de/htwsaar/webshop/util/LoggerUtil.java @@ -0,0 +1,33 @@ +package de.htwsaar.webshop.util; + +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; + +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +/** + * Class for often used logging requests. + */ +@Slf4j +public class LoggerUtil { + + public static Map getRequestHeaders(HttpServletRequest request) { + Map headers = new HashMap<>(); + Enumeration headerNames = request.getHeaderNames(); + while (headerNames.hasMoreElements()) { + String headerName = headerNames.nextElement(); + headers.put(headerName, request.getHeader(headerName)); + } + return headers; + } + + public static void logRequest(HttpServletRequest request) { + log.info("Request {} on URI {} from {} with {}", + request.getMethod(), + request.getRequestURI(), + request.getRemoteAddr(), + getRequestHeaders(request)); //TODO: sanitize content when there is sensitive content + } +} diff --git a/00-backend/src/main/resources/application.properties b/00-backend/src/main/resources/application.properties index 9fed96f..4e52be8 100644 --- a/00-backend/src/main/resources/application.properties +++ b/00-backend/src/main/resources/application.properties @@ -1 +1,20 @@ spring.application.name=webshop +server.port=8085 + +# DataSource +spring.datasource.url=jdbc:sqlite:./datasource/database.sqlite +spring.datasource.driver-class-name=org.sqlite.JDBC +spring.sql.init.mode=always +spring.jpa.properties.hibernate.dialect=org.hibernate.community.dialect.SQLiteDialect + +# Logging +logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS} [CET] %-5level %logger{36} - %msg%n +logging.level.root=INFO +spring.main.banner-mode=off + +# Flyway +spring.flyway.enabled=true +spring.flyway.url=jdbc:sqlite:./datasource/database.sqlite +spring.flyway.locations=classpath:db/sqlite +spring.flyway.baseline-on-migrate=true +spring.flyway.mixed=true \ No newline at end of file diff --git a/00-backend/src/main/resources/db/initdb.sql b/00-backend/src/main/resources/db/initdb.sql new file mode 100644 index 0000000..a0fb199 --- /dev/null +++ b/00-backend/src/main/resources/db/initdb.sql @@ -0,0 +1,30 @@ +-- articles +CREATE TABLE IF NOT EXISTS Articles( + id INTEGER PRIMARY KEY NOT NULL, + uuid TEXT UNIQUE NOT NULL, -- UUID + stock INTEGER NOT NULL DEFAULT 0, + name TEXT NOT NULL, + description TEXT NULL, --in html + price100 INTEGER NOT NULL, -- in cents + discount100 INTEGER NULL, -- in percent + category TEXT NULL, + + CONSTRAINT c_stock CHECK ( stock >= 0 ) +); + +-- article images +CREATE TABLE IF NOT EXISTS Images( + id INTEGER PRIMARY KEY NOT NULL, + articleId INTEGER NOT NULL, + uri TEXT NOT NULL, + FOREIGN KEY (articleId) REFERENCES Articles(id) +); + +CREATE TABLE IF NOT EXISTS Reviews( + id INTEGER PRIMARY KEY NOT NULL, + articleId INTEGER NOT NULL, + rating INTEGER NOT NULL, + content TEXT NULL, + FOREIGN KEY (articleId) REFERENCES Articles(id), + CONSTRAINT c_rating CHECK ( rating >= 0 AND rating <= 10) +) \ No newline at end of file diff --git a/00-backend/src/test/java/de/htwsaar/webshop/WebshopApplicationTests.java b/00-backend/src/test/java/de/htwsaar/webshop/WebshopApplicationTests.java index d113f09..9a863e2 100644 --- a/00-backend/src/test/java/de/htwsaar/webshop/WebshopApplicationTests.java +++ b/00-backend/src/test/java/de/htwsaar/webshop/WebshopApplicationTests.java @@ -8,6 +8,7 @@ class WebshopApplicationTests { @Test void contextLoads() { + //checks whether all spring stuff is configured correctly } }