From dc86d229c13ff27124b4d413d16408253fdaec82 Mon Sep 17 00:00:00 2001 From: Artur Date: Fri, 9 May 2025 11:25:28 +0200 Subject: [PATCH 01/11] Commit to check the liquibase work, + added fixes from last review + readme.me demo file (not ready yet) --- README.md | 132 ++++++++++++++++++ pom.xml | 16 ++- .../controller/ShoppingCartController.java | 3 +- .../shoppingCart/ShoppingCartResponseDto.java | 2 + .../changelog/changes/001-insert-users.yaml | 30 +++- .../ShoppingCartControllerTest.java | 5 +- .../service/ShoppingCartServiceTest.java | 41 +++++- 7 files changed, 222 insertions(+), 7 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..4ad4a76 --- /dev/null +++ b/README.md @@ -0,0 +1,132 @@ +# ๐Ÿ“š Online Book Store API + +A comprehensive backend application for managing an online bookstore, built with Java and Spring Boot. It offers full CRUD functionality for books, categories, shopping carts, and orders, along with user authentication and role-based access control. + +--- + +## ๐ŸŽฏ Project Overview + +This application serves as the backend for an online book store, supporting two roles: + +* **Shopper (User):** + + * Sign up / Sign in + * Browse books by category or all at once + * View book details + * Add/remove books to/from cart + * Place orders and view order history + +* **Manager (Admin):** + + * Add, update, delete books + * Manage categories + * Update order status + +The system is structured around 8 core domain models: +`User`, `Role`, `Book`, `Category`, `ShoppingCart`, `CartItem`, `Order`, `OrderItem` + +--- + +## ๐Ÿš€ Technologies & Tools + +| Tool | Description | +| ------------------- | ------------------------------ | +| Java 21 | Core language | +| Spring Boot 3.4.1 | Main framework | +| Spring Security | Authentication & authorization | +| Spring Data JPA | Data persistence | +| JWT | Token-based authentication | +| MapStruct | DTO mapping | +| Liquibase | DB schema management | +| Hibernate Validator | Input validation | +| Testcontainers | Integration tests with Docker | +| MySQL / H2 | Databases (prod/test) | +| Swagger | API documentation | +| Lombok | Less boilerplate | +| Checkstyle | Code quality | + +--- + +## ๐Ÿ”Œ API Endpoints Overview + +### โœ… Authentication + +* `POST /api/auth/register` โ€“ Register a new user +* `POST /api/auth/login` โ€“ Login and receive a JWT token + +### ๐Ÿ“š Book + +* `GET /books` โ€“ List all books +* `GET /books/{id}` โ€“ View book by ID +* `POST /books` โ€“ Add a book (admin only) +* `PUT /books/{id}` โ€“ Update book +* `DELETE /books/{id}` โ€“ Delete book +* `GET /books/search` โ€“ Search books + +### ๐Ÿท๏ธ Category + +* `POST /api/categories` โ€“ Add a category +* `GET /api/categories` โ€“ List categories +* `GET /api/categories/{id}` โ€“ View category +* `PUT /api/categories/{id}` โ€“ Update category +* `DELETE /api/categories/{id}` โ€“ Delete category +* `GET /api/categories/{id}/books` โ€“ View books in category + +### ๐Ÿ›’ Shopping Cart + +* `GET /api/cart` โ€“ View cart +* `POST /api/cart` โ€“ Add item to cart +* `PUT /api/cart/cart-items/{cartItemId}` โ€“ Update item +* `DELETE /api/cart/cart-items/{cartItemId}` โ€“ Remove item + +### ๐Ÿ“ฆ Order + +* `POST /api/orders` โ€“ Place an order +* `GET /api/orders` โ€“ View order history +* `GET /api/orders/{orderId}/items` โ€“ Items in an order +* `GET /api/orders/{orderId}/items/{itemId}` โ€“ View specific item +* `PATCH /api/orders/{id}` โ€“ Update order status + +--- + +## ๐ŸŒ Live Demo + +๐Ÿงช Swagger UI (hosted on AWS): +[http://ec2-13-60-51-178.eu-north-1.compute.amazonaws.com/swagger-ui/index.html](http://ec2-13-60-51-178.eu-north-1.compute.amazonaws.com/swagger-ui/index.html) + +๐Ÿ“น YouTube Demo *(Add your link here)* + +--- + +## ๐Ÿ” Default Users + +| Role | Email | Password | +| ----- | ------------------- | -------------- | +| Admin | `admin@example.com` | `adminExample` | +| User | `user@example.com` | `userExample` | + +> ๐Ÿ› ๏ธ These accounts are automatically created on application startup via `DataInitializer`. + +--- + +## **โš™๏ธ Setup Instructions** + +### **โœ… Prerequisites** + +* Java 17+ +* Docker +* Maven + +### **๐Ÿงช Clone & Run Locally** + +``` +# Clone repo +git clone https://github.com/your-username/your-repo-name.git +cd your-repo-name + +# Package app +./mvnw clean package + +# Run app with Docker +docker compose up +``` diff --git a/pom.xml b/pom.xml index 441c174..f2d6b26 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,7 @@ SpringBoot-BookShop - 21 + 21 checkstyle.xml 0.11.5 1.19.4 @@ -203,6 +203,20 @@ liquibase-maven-plugin 4.23.0 + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.0 + + + + org.example.SpringBootBookShopApplication + + + + diff --git a/src/main/java/org/example/controller/ShoppingCartController.java b/src/main/java/org/example/controller/ShoppingCartController.java index 5ee9873..2756e19 100644 --- a/src/main/java/org/example/controller/ShoppingCartController.java +++ b/src/main/java/org/example/controller/ShoppingCartController.java @@ -2,6 +2,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.example.dto.cartItem.AddItemToCartRequestDto; import org.example.dto.cartItem.UpdateCartItemRequestDto; @@ -53,7 +54,7 @@ public void removeCartItem(@PathVariable Long cartItemId) { @PutMapping("/cart-items/{cartItemId}") @PreAuthorize("hasRole('ROLE_USER')") public ShoppingCartResponseDto updateCartItem(@PathVariable Long cartItemId, - @RequestBody UpdateCartItemRequestDto request) { + @Valid @RequestBody UpdateCartItemRequestDto request) { return shoppingCartServiceImpl.updateCartItem(cartItemId, request); } diff --git a/src/main/java/org/example/dto/shoppingCart/ShoppingCartResponseDto.java b/src/main/java/org/example/dto/shoppingCart/ShoppingCartResponseDto.java index 5ab115c..b509745 100644 --- a/src/main/java/org/example/dto/shoppingCart/ShoppingCartResponseDto.java +++ b/src/main/java/org/example/dto/shoppingCart/ShoppingCartResponseDto.java @@ -1,8 +1,10 @@ package org.example.dto.shoppingCart; +import lombok.Builder; import org.example.dto.cartItem.CartItemResponseDto; import java.util.Set; +@Builder public record ShoppingCartResponseDto( Long id, Long userId, diff --git a/src/main/resources/db/changelog/changes/001-insert-users.yaml b/src/main/resources/db/changelog/changes/001-insert-users.yaml index 8252a8d..64b4cd0 100644 --- a/src/main/resources/db/changelog/changes/001-insert-users.yaml +++ b/src/main/resources/db/changelog/changes/001-insert-users.yaml @@ -18,10 +18,34 @@ databaseChangeLog: value: admin@example.com - column: name: password - value: $2a$10$XyZ3wQ9E1PJKL6VjFdfSseCEq9rOvhA/UNmV94QHqkG2l6bBZyV6G + value: $2a$10$EQVI2UweY22CoQXOd4I3EOF41lk55sboVMYQ7sgroVveCyR6wviZC - column: name: first_name - value: Alice + value: Admin - column: name: last_name - value: Stone \ No newline at end of file + value: admin + - column: + name: shipping_address + value: 123 Elm Street + - insert: + tableName: users + columns: + - column: + name: id + valueNumeric: "2" + - column: + name: email + value: user@example.com + - column: + name: password + value: $2a$10$DZKy0ba28TVjZDrvY9hcpu9jIq2DlXrduGWpvPHg6Tt1.9UWYgiSC + - column: + name: first_name + value: User + - column: + name: last_name + value: user + - column: + name: shipping_address + value: 456 Oxford Road \ No newline at end of file diff --git a/src/test/java/org/example/controller/ShoppingCartControllerTest.java b/src/test/java/org/example/controller/ShoppingCartControllerTest.java index d111e11..184cf2b 100644 --- a/src/test/java/org/example/controller/ShoppingCartControllerTest.java +++ b/src/test/java/org/example/controller/ShoppingCartControllerTest.java @@ -21,10 +21,12 @@ import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import com.fasterxml.jackson.databind.ObjectMapper; class ShoppingCartControllerTest { private MockMvc mockMvc; + private ObjectMapper objectMapper; @Mock private ShoppingCartServiceImpl shoppingCartServiceImpl; @@ -38,6 +40,7 @@ class ShoppingCartControllerTest { @BeforeEach void setUp() { MockitoAnnotations.openMocks(this); + objectMapper = new ObjectMapper(); mockUser = new User(); mockUser.setId(1L); @@ -58,7 +61,7 @@ void updateCartItem_WhenCartItemExists_ShouldUpdateQuantity() throws Exception { mockMvc.perform(put("/api/cart/cart-items/1") .contentType(MediaType.APPLICATION_JSON) - .content("{\"quantity\":3}")) + .content(objectMapper.writeValueAsString(request))) .andExpect(status().isOk()) .andExpect(jsonPath("$.id").value(1L)); diff --git a/src/test/java/org/example/service/ShoppingCartServiceTest.java b/src/test/java/org/example/service/ShoppingCartServiceTest.java index 08af7c6..035915d 100644 --- a/src/test/java/org/example/service/ShoppingCartServiceTest.java +++ b/src/test/java/org/example/service/ShoppingCartServiceTest.java @@ -1,8 +1,10 @@ package org.example.service; import org.example.dto.cartItem.AddItemToCartRequestDto; +import org.example.dto.cartItem.CartItemResponseDto; import org.example.dto.cartItem.UpdateCartItemRequestDto; import org.example.dto.shoppingCart.ShoppingCartResponseDto; +import org.example.exception.BookNotFoundException; import org.example.exception.CartItemNotFoundException; import org.example.exception.UserNotFoundException; import org.example.mapper.ShoppingCartMapper; @@ -22,6 +24,7 @@ import org.mockito.MockitoAnnotations; import java.util.HashSet; import java.util.Optional; +import java.util.Set; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @@ -74,12 +77,26 @@ void setUp() { cartItem.setQuantity(2); cartItem.setShoppingCart(shoppingCart); - shoppingCartResponseDto = new ShoppingCartResponseDto(1L, 1L, new HashSet<>()); + CartItemResponseDto itemDto = CartItemResponseDto.builder() + .id(1L) + .bookId(1L) + .bookTitle("Test Book") + .quantity(2) + .build(); + + Set cartItems = Set.of(itemDto); + + shoppingCartResponseDto = ShoppingCartResponseDto.builder() + .id(1L) + .userId(1L) + .cartItems(cartItems) + .build(); } @Test void addToCart_WhenUserExistsAndBookExists_ShouldAddItemToCart() { AddItemToCartRequestDto request = new AddItemToCartRequestDto(1L, 2); + when(userRepository.findById(1L)).thenReturn(Optional.of(user)); when(shoppingCartRepository.findByUser(user)).thenReturn(Optional.of(shoppingCart)); when(bookRepository.findById(1L)).thenReturn(Optional.of(book)); @@ -88,6 +105,16 @@ void addToCart_WhenUserExistsAndBookExists_ShouldAddItemToCart() { ShoppingCartResponseDto result = shoppingCartService.addToCart(1L, request); assertNotNull(result); + assertEquals(1L, result.userId()); + assertEquals(shoppingCart.getId(), result.id()); + assertNotNull(result.cartItems()); + assertEquals(1, result.cartItems().size()); + + CartItemResponseDto cartItemResponseDto = result.cartItems().iterator().next(); + assertEquals(1L, cartItemResponseDto.bookId()); + assertEquals("Test Book", cartItemResponseDto.bookTitle()); + assertEquals(2, cartItemResponseDto.quantity()); + verify(cartItemRepository).save(any(CartItem.class)); } @@ -155,4 +182,16 @@ void removeCartItem_WhenItemNotFound_ShouldThrowException() { assertThrows(CartItemNotFoundException.class, () -> shoppingCartService.removeCartItem(1L)); } + + @Test + void addToCart_WhenBookNotFound_ShouldThrowException() { + AddItemToCartRequestDto request = new AddItemToCartRequestDto(1L, 2); + + when(userRepository.findById(1L)).thenReturn(Optional.of(user)); + when(shoppingCartRepository.findByUser(user)).thenReturn(Optional.of(shoppingCart)); + when(bookRepository.findById(1L)).thenReturn(Optional.empty()); + + assertThrows(BookNotFoundException.class, () -> shoppingCartService.addToCart(1L, request)); + } + } From dc0f84ba587fac6ee474ee7f0f0f1f9afb89ba3c Mon Sep 17 00:00:00 2001 From: Artur Date: Fri, 9 May 2025 19:49:40 +0200 Subject: [PATCH 02/11] changes in docker-compose.yaml --- docker-compose.yaml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index b8e76ee..4d20a8b 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -14,7 +14,7 @@ services: volumes: - mysql-data:/var/lib/mysql healthcheck: - test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-pWetuop34!"] + test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-p${MYSQLDB_ROOT_PASSWORD}"] interval: 30s timeout: 10s retries: 3 @@ -24,9 +24,9 @@ services: depends_on: - db restart: on-failure - image: my-app-image build: - context: ./app + context: ./ + dockerfile: Dockerfile env_file: - .env ports: @@ -36,8 +36,11 @@ services: SPRING_APPLICATION_JSON: > {"spring.datasource.url":"jdbc:mysql://db:3306/lombok?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true", "spring.datasource.username":"root", - "spring.datasource.password":"${MYSQL_ROOT_PASSWORD}", + "spring.datasource.password":"${MYSQLDB_ROOT_PASSWORD}", "spring.jpa.hibernate.ddl-auto":"update", "spring.jpa.show-sql":"true", "spring.jpa.properties.hibernate.format_sql":"true"} JAVA_TOOL_OPTIONS: "-Djava.security.egd=file:/dev/./urandom" + +volumes: + mysql-data: From 6aa9f8bd6b80f275a780c6eca7e3649d7dff88e7 Mon Sep 17 00:00:00 2001 From: Artur Date: Mon, 12 May 2025 13:48:38 +0200 Subject: [PATCH 03/11] liquibase fixed --- Dockerfile | 18 +++---- docker-compose.yaml | 2 +- pom.xml | 12 +++-- .../example/dto/user/UserLoginRequestDto.java | 2 +- src/main/resources/application.properties | 2 +- .../changelog/changes/001-insert-users.yaml | 51 ------------------- .../changelog/changes/002-insert-roles.yaml | 27 ---------- .../changes/003-create-users-roles-table.yaml | 25 +++++---- .../changelog/changes/004-assign-roles.yaml | 27 ---------- .../changes/005-create-categories-table.yaml | 30 ----------- ...gories.yaml => 005-insert-categories.yaml} | 11 ++-- .../db/changelog/db.changelog-master.yaml | 14 +++-- 12 files changed, 49 insertions(+), 172 deletions(-) delete mode 100644 src/main/resources/db/changelog/changes/001-insert-users.yaml delete mode 100644 src/main/resources/db/changelog/changes/002-insert-roles.yaml delete mode 100644 src/main/resources/db/changelog/changes/004-assign-roles.yaml delete mode 100644 src/main/resources/db/changelog/changes/005-create-categories-table.yaml rename src/main/resources/db/changelog/changes/{006-insert-categories.yaml => 005-insert-categories.yaml} (56%) diff --git a/Dockerfile b/Dockerfile index 217fc15..0657c1f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,17 +1,17 @@ # Builder stage -FROM openjdk:21-jdk-slim as BUILDER -WORKDIR application +FROM openjdk:21-jdk-slim as builder +WORKDIR /application ARG JAR_FILE=target/*.jar COPY ${JAR_FILE} application.jar RUN java -Djarmode=layertools -jar application.jar extract -#Final stage +# Final stage FROM openjdk:21-jdk-slim -WORKDIR Application -COPY --from=builder application/dependencies/ ./ -COPY --from=builder application/spring-boot-loader/ ./ -COPY --from=builder application/snapshot-dependencies/ ./ -COPY --from=builder application/application/ ./ -ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"] +WORKDIR /application +COPY --from=builder /application/dependencies/ ./ +COPY --from=builder /application/spring-boot-loader/ ./ +COPY --from=builder /application/snapshot-dependencies/ ./ +COPY --from=builder /application/application/ ./ +ENTRYPOINT ["java", "org.springframework.boot.loader.launch.JarLauncher"] EXPOSE 8080 diff --git a/docker-compose.yaml b/docker-compose.yaml index 4d20a8b..e6021c3 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -37,7 +37,7 @@ services: {"spring.datasource.url":"jdbc:mysql://db:3306/lombok?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true", "spring.datasource.username":"root", "spring.datasource.password":"${MYSQLDB_ROOT_PASSWORD}", - "spring.jpa.hibernate.ddl-auto":"update", + "spring.jpa.hibernate.ddl-auto":"none", "spring.jpa.show-sql":"true", "spring.jpa.properties.hibernate.format_sql":"true"} JAVA_TOOL_OPTIONS: "-Djava.security.egd=file:/dev/./urandom" diff --git a/pom.xml b/pom.xml index f2d6b26..b868491 100644 --- a/pom.xml +++ b/pom.xml @@ -217,6 +217,15 @@ + + org.springframework.boot + spring-boot-maven-plugin + + + true + + + @@ -224,9 +233,6 @@ with-liquibase - - true - diff --git a/src/main/java/org/example/dto/user/UserLoginRequestDto.java b/src/main/java/org/example/dto/user/UserLoginRequestDto.java index d1debf4..2c7b9ff 100644 --- a/src/main/java/org/example/dto/user/UserLoginRequestDto.java +++ b/src/main/java/org/example/dto/user/UserLoginRequestDto.java @@ -6,7 +6,7 @@ public record UserLoginRequestDto( @NotEmpty - @Size(min = 8, max = 20) + @Size(min = 8, max = 35) @Email String email, @NotEmpty diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 1ba1fa6..6e59149 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -5,7 +5,7 @@ spring.datasource.password=Wetuop34! spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # Ustawienia JPA -spring.jpa.hibernate.ddl-auto=update +spring.jpa.hibernate.ddl-auto=none spring.jpa.show-sql=true spring.jpa.properties.hibernate.format_sql=true diff --git a/src/main/resources/db/changelog/changes/001-insert-users.yaml b/src/main/resources/db/changelog/changes/001-insert-users.yaml deleted file mode 100644 index 64b4cd0..0000000 --- a/src/main/resources/db/changelog/changes/001-insert-users.yaml +++ /dev/null @@ -1,51 +0,0 @@ -databaseChangeLog: - - changeSet: - id: 001-insert-users - author: artur - preConditions: - - onFail: MARK_RAN - - tableExists: - tableName: users - changes: - - insert: - tableName: users - columns: - - column: - name: id - valueNumeric: "1" - - column: - name: email - value: admin@example.com - - column: - name: password - value: $2a$10$EQVI2UweY22CoQXOd4I3EOF41lk55sboVMYQ7sgroVveCyR6wviZC - - column: - name: first_name - value: Admin - - column: - name: last_name - value: admin - - column: - name: shipping_address - value: 123 Elm Street - - insert: - tableName: users - columns: - - column: - name: id - valueNumeric: "2" - - column: - name: email - value: user@example.com - - column: - name: password - value: $2a$10$DZKy0ba28TVjZDrvY9hcpu9jIq2DlXrduGWpvPHg6Tt1.9UWYgiSC - - column: - name: first_name - value: User - - column: - name: last_name - value: user - - column: - name: shipping_address - value: 456 Oxford Road \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/002-insert-roles.yaml b/src/main/resources/db/changelog/changes/002-insert-roles.yaml deleted file mode 100644 index 3e76b68..0000000 --- a/src/main/resources/db/changelog/changes/002-insert-roles.yaml +++ /dev/null @@ -1,27 +0,0 @@ -databaseChangeLog: - - changeSet: - id: 002-insert-roles - author: artur - preConditions: - - onFail: MARK_RAN - - tableExists: - tableName: roles - changes: - - insert: - tableName: roles - columns: - - column: - name: id - valueNumeric: "1" - - column: - name: name - value: ROLE_ADMIN - - insert: - tableName: roles - columns: - - column: - name: id - valueNumeric: "2" - - column: - name: name - value: ROLE_USER diff --git a/src/main/resources/db/changelog/changes/003-create-users-roles-table.yaml b/src/main/resources/db/changelog/changes/003-create-users-roles-table.yaml index a0a7603..a9388a7 100644 --- a/src/main/resources/db/changelog/changes/003-create-users-roles-table.yaml +++ b/src/main/resources/db/changelog/changes/003-create-users-roles-table.yaml @@ -2,13 +2,6 @@ databaseChangeLog: - changeSet: id: 003-create-users-roles-table author: artur - preConditions: - - onFail: MARK_RAN - - not: - - tableExists: - tableName: users_roles - - tableExists: - tableName: roles changes: - createTable: tableName: users_roles @@ -18,18 +11,24 @@ databaseChangeLog: type: BIGINT constraints: nullable: false - foreignKeyName: fk_users_roles_user - referencedTableName: users - referencedColumnNames: id - column: name: role_id type: BIGINT constraints: nullable: false - foreignKeyName: fk_users_roles_role - referencedTableName: roles - referencedColumnNames: id - addPrimaryKey: tableName: users_roles columnNames: user_id, role_id constraintName: pk_users_roles + - addForeignKeyConstraint: + baseTableName: users_roles + baseColumnNames: user_id + constraintName: fk_users_roles_user + referencedTableName: users + referencedColumnNames: id + - addForeignKeyConstraint: + baseTableName: users_roles + baseColumnNames: role_id + constraintName: fk_users_roles_role + referencedTableName: roles + referencedColumnNames: id \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/004-assign-roles.yaml b/src/main/resources/db/changelog/changes/004-assign-roles.yaml deleted file mode 100644 index dc39755..0000000 --- a/src/main/resources/db/changelog/changes/004-assign-roles.yaml +++ /dev/null @@ -1,27 +0,0 @@ -databaseChangeLog: - - changeSet: - id: 004-assign-roles - author: artur - preConditions: - - onFail: MARK_RAN - - tableExists: - tableName: users_roles - changes: - - insert: - tableName: users_roles - columns: - - column: - name: user_id - valueNumeric: "1" - - column: - name: role_id - valueNumeric: "1" - - insert: - tableName: users_roles - columns: - - column: - name: user_id - valueNumeric: "2" - - column: - name: role_id - valueNumeric: "2" diff --git a/src/main/resources/db/changelog/changes/005-create-categories-table.yaml b/src/main/resources/db/changelog/changes/005-create-categories-table.yaml deleted file mode 100644 index c59ce98..0000000 --- a/src/main/resources/db/changelog/changes/005-create-categories-table.yaml +++ /dev/null @@ -1,30 +0,0 @@ -databaseChangeLog: - - changeSet: - id: 005-create-categories-table - author: artur - changes: - - createTable: - tableName: categories - columns: - - column: - name: id - type: bigint - autoIncrement: true - constraints: - primaryKey: true - nullable: false - - column: - name: name - type: varchar(255) - constraints: - nullable: false - - column: - name: description - type: varchar(255) - constraints: - nullable: true - - column: - name: is_deleted - type: boolean - constraints: - nullable: false diff --git a/src/main/resources/db/changelog/changes/006-insert-categories.yaml b/src/main/resources/db/changelog/changes/005-insert-categories.yaml similarity index 56% rename from src/main/resources/db/changelog/changes/006-insert-categories.yaml rename to src/main/resources/db/changelog/changes/005-insert-categories.yaml index ccb342b..95d75ef 100644 --- a/src/main/resources/db/changelog/changes/006-insert-categories.yaml +++ b/src/main/resources/db/changelog/changes/005-insert-categories.yaml @@ -1,17 +1,20 @@ databaseChangeLog: - changeSet: - id: 006-insert-categories + id: 005-insert-categories author: artur changes: - insert: tableName: categories columns: + - column: + name: id + valueNumeric: 1 - column: name: name - value: "Fiction" + value: "Programming" - column: name: description - value: "Fiction books" + value: "Books about programming" - column: name: is_deleted - valueBoolean: false + valueBoolean: false \ No newline at end of file diff --git a/src/main/resources/db/changelog/db.changelog-master.yaml b/src/main/resources/db/changelog/db.changelog-master.yaml index 5676852..4552524 100644 --- a/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/src/main/resources/db/changelog/db.changelog-master.yaml @@ -1,13 +1,17 @@ databaseChangeLog: - include: - file: db/changelog/changes/001-insert-users.yaml + file: db/changelog/changes/001-create-users-table.yaml - include: - file: db/changelog/changes/002-insert-roles.yaml + file: db/changelog/changes/002-create-roles-table.yaml - include: file: db/changelog/changes/003-create-users-roles-table.yaml - include: - file: db/changelog/changes/004-assign-roles.yaml + file: db/changelog/changes/004-create-categories-table.yaml - include: - file: db/changelog/changes/005-create-categories-table.yaml + file: db/changelog/changes/005-insert-categories.yaml - include: - file: db/changelog/changes/006-insert-categories.yaml + file: db/changelog/changes/006-insert-users.yaml + - include: + file: db/changelog/changes/007-insert-roles.yaml + - include: + file: db/changelog/changes/008-assign-roles.yaml \ No newline at end of file From 4f7e1c0432a0d81318b3a4ee0fd26568d2c711d5 Mon Sep 17 00:00:00 2001 From: Artur Date: Mon, 12 May 2025 19:23:59 +0200 Subject: [PATCH 04/11] added liquibase files to git --- .../changes/001-create-users-table.yaml | 38 +++++++++++++++++++ .../changes/002-create-roles-table.yaml | 20 ++++++++++ .../changes/004-create-categories-table.yaml | 27 +++++++++++++ .../changelog/changes/006-insert-users.yaml | 35 +++++++++++++++++ .../changelog/changes/007-insert-roles.yaml | 23 +++++++++++ .../changelog/changes/008-assign-roles.yaml | 15 ++++++++ 6 files changed, 158 insertions(+) create mode 100644 src/main/resources/db/changelog/changes/001-create-users-table.yaml create mode 100644 src/main/resources/db/changelog/changes/002-create-roles-table.yaml create mode 100644 src/main/resources/db/changelog/changes/004-create-categories-table.yaml create mode 100644 src/main/resources/db/changelog/changes/006-insert-users.yaml create mode 100644 src/main/resources/db/changelog/changes/007-insert-roles.yaml create mode 100644 src/main/resources/db/changelog/changes/008-assign-roles.yaml diff --git a/src/main/resources/db/changelog/changes/001-create-users-table.yaml b/src/main/resources/db/changelog/changes/001-create-users-table.yaml new file mode 100644 index 0000000..dcff92c --- /dev/null +++ b/src/main/resources/db/changelog/changes/001-create-users-table.yaml @@ -0,0 +1,38 @@ +databaseChangeLog: + - changeSet: + id: 001-create-users-table + author: artur + changes: + - createTable: + tableName: users + columns: + - column: + name: id + type: BIGINT + autoIncrement: true + constraints: + primaryKey: true + nullable: false + - column: + name: email + type: VARCHAR(255) + constraints: + nullable: false + - column: + name: first_name + type: VARCHAR(255) + constraints: + nullable: false + - column: + name: last_name + type: VARCHAR(255) + constraints: + nullable: false + - column: + name: password + type: VARCHAR(255) + constraints: + nullable: false + - column: + name: shipping_address + type: VARCHAR(255) \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/002-create-roles-table.yaml b/src/main/resources/db/changelog/changes/002-create-roles-table.yaml new file mode 100644 index 0000000..b9ac842 --- /dev/null +++ b/src/main/resources/db/changelog/changes/002-create-roles-table.yaml @@ -0,0 +1,20 @@ +databaseChangeLog: + - changeSet: + id: 002-create-roles-table + author: artur + changes: + - createTable: + tableName: roles + columns: + - column: + name: id + type: BIGINT + autoIncrement: true + constraints: + primaryKey: true + nullable: false + - column: + name: name + type: VARCHAR(255) + constraints: + nullable: false \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/004-create-categories-table.yaml b/src/main/resources/db/changelog/changes/004-create-categories-table.yaml new file mode 100644 index 0000000..5f5504a --- /dev/null +++ b/src/main/resources/db/changelog/changes/004-create-categories-table.yaml @@ -0,0 +1,27 @@ +databaseChangeLog: + - changeSet: + id: 004-create-categories-table + author: artur + changes: + - createTable: + tableName: categories + columns: + - column: + name: id + type: BIGINT + autoIncrement: true + constraints: + primaryKey: true + nullable: false + - column: + name: name + type: VARCHAR(255) + constraints: + nullable: false + - column: + name: description + type: VARCHAR(255) + - column: + name: is_deleted + type: BOOLEAN + defaultValueBoolean: false \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/006-insert-users.yaml b/src/main/resources/db/changelog/changes/006-insert-users.yaml new file mode 100644 index 0000000..d8edff9 --- /dev/null +++ b/src/main/resources/db/changelog/changes/006-insert-users.yaml @@ -0,0 +1,35 @@ +databaseChangeLog: + - changeSet: + id: 006-insert-users + author: artur + changes: + - insert: + tableName: users + columns: + - column: + name: first_name + value: "Admin" + - column: + name: last_name + value: "Admin" + - column: + name: email + value: "admin@example.com" + - column: + name: password + value: "$2a$10$EQVI2UweY22CoQXOd4I3EOF41lk55sboVMYQ7sgroVveCyR6wviZC" + - insert: + tableName: users + columns: + - column: + name: first_name + value: "User" + - column: + name: last_name + value: "User" + - column: + name: email + value: "user@example.com" + - column: + name: password + value: "$2a$10$DZKy0ba28TVjZDrvY9hcpu9jIq2DlXrduGWpvPHg6Tt1.9UWYgiSC" \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/007-insert-roles.yaml b/src/main/resources/db/changelog/changes/007-insert-roles.yaml new file mode 100644 index 0000000..cbb6a95 --- /dev/null +++ b/src/main/resources/db/changelog/changes/007-insert-roles.yaml @@ -0,0 +1,23 @@ +databaseChangeLog: + - changeSet: + id: 007-insert-roles + author: artur + changes: + - insert: + tableName: roles + columns: + - column: + name: id + valueNumeric: 1 + - column: + name: name + value: "ROLE_USER" + - insert: + tableName: roles + columns: + - column: + name: id + valueNumeric: 2 + - column: + name: name + value: "ROLE_ADMIN" \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/008-assign-roles.yaml b/src/main/resources/db/changelog/changes/008-assign-roles.yaml new file mode 100644 index 0000000..462efa8 --- /dev/null +++ b/src/main/resources/db/changelog/changes/008-assign-roles.yaml @@ -0,0 +1,15 @@ +databaseChangeLog: + - changeSet: + id: 008-assign-roles + author: artur + changes: + - sql: + sql: > + INSERT INTO users_roles (user_id, role_id) + SELECT u.id, r.id FROM users u, roles r + WHERE u.email = 'admin@example.com' AND r.name = 'ROLE_ADMIN'; + - sql: + sql: > + INSERT INTO users_roles (user_id, role_id) + SELECT u.id, r.id FROM users u, roles r + WHERE u.email = 'admin@example.com' AND r.name = 'ROLE_USER'; \ No newline at end of file From fa58dd4ce6220b53276cd21ea68b7d9ef4e85a61 Mon Sep 17 00:00:00 2001 From: Artur Date: Tue, 13 May 2025 18:12:42 +0200 Subject: [PATCH 05/11] Fixed logging/registration --- .../org/example/config/SecurityConfig.java | 2 +- .../validators/FieldMatchValidator.java | 27 +++++++------------ .../CustomGlobalExceptionHandler.java | 9 +++---- src/main/java/org/example/model/User.java | 2 +- .../filter/JwtAuthenticationFilter.java | 2 +- src/main/resources/application.properties | 2 +- .../changelog/changes/008-assign-roles.yaml | 7 ++++- 7 files changed, 24 insertions(+), 27 deletions(-) diff --git a/src/main/java/org/example/config/SecurityConfig.java b/src/main/java/org/example/config/SecurityConfig.java index 67977e5..c9708ee 100644 --- a/src/main/java/org/example/config/SecurityConfig.java +++ b/src/main/java/org/example/config/SecurityConfig.java @@ -33,7 +33,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws .csrf(AbstractHttpConfigurer::disable) .authorizeHttpRequests( auth -> auth - .requestMatchers("/auth/**", "/error", "/swagger-ui/**", "/v3/api-docs/**") + .requestMatchers("/api/auth/**", "/error", "/swagger-ui/**", "/v3/api-docs/**") .permitAll() .anyRequest() .authenticated() diff --git a/src/main/java/org/example/customAnnotations/validators/FieldMatchValidator.java b/src/main/java/org/example/customAnnotations/validators/FieldMatchValidator.java index 95d9f6b..271573b 100644 --- a/src/main/java/org/example/customAnnotations/validators/FieldMatchValidator.java +++ b/src/main/java/org/example/customAnnotations/validators/FieldMatchValidator.java @@ -2,10 +2,11 @@ import jakarta.validation.ConstraintValidator; import jakarta.validation.ConstraintValidatorContext; -import org.example.dto.user.UserRegistrationRequestDto; import org.example.customAnnotations.FieldMatch; +import org.springframework.beans.BeanWrapperImpl; + +public class FieldMatchValidator implements ConstraintValidator { -public class FieldMatchValidator implements ConstraintValidator { private String field; private String fieldMatch; @@ -16,22 +17,14 @@ public void initialize(FieldMatch constraintAnnotation) { } @Override - public boolean isValid(UserRegistrationRequestDto dto, ConstraintValidatorContext context) { - if (dto == null) { - return true; - } - - String fieldValue = getFieldValue(dto, field); - String fieldMatchValue = getFieldValue(dto, fieldMatch); + public boolean isValid(Object value, ConstraintValidatorContext context) { + Object fieldValue = new BeanWrapperImpl(value).getPropertyValue(field); + Object fieldMatchValue = new BeanWrapperImpl(value).getPropertyValue(fieldMatch); - return fieldValue != null && fieldValue.equals(fieldMatchValue); - } - - private String getFieldValue(UserRegistrationRequestDto dto, String fieldName) { - try { - return (String) dto.getClass().getDeclaredField(fieldName).get(dto); - } catch (Exception e) { - return null; + if (fieldValue == null || fieldMatchValue == null) { + return false; } + + return fieldValue.equals(fieldMatchValue); } } diff --git a/src/main/java/org/example/exception/CustomGlobalExceptionHandler.java b/src/main/java/org/example/exception/CustomGlobalExceptionHandler.java index 153c332..c963cb7 100644 --- a/src/main/java/org/example/exception/CustomGlobalExceptionHandler.java +++ b/src/main/java/org/example/exception/CustomGlobalExceptionHandler.java @@ -49,11 +49,10 @@ public ResponseEntity handleRegistrationException(@NonNull RegistrationE } private String getErrorMessage(ObjectError objectError) { - if (objectError instanceof FieldError) { - String field = ((FieldError) objectError).getField(); - String defaultMessage = objectError.getDefaultMessage(); - return field + " " + defaultMessage; + if (objectError instanceof FieldError fieldError) { + return fieldError.getField() + " " + fieldError.getDefaultMessage(); + } else { + return objectError.getDefaultMessage(); } - return null; } } diff --git a/src/main/java/org/example/model/User.java b/src/main/java/org/example/model/User.java index c7dddb6..f514fd9 100644 --- a/src/main/java/org/example/model/User.java +++ b/src/main/java/org/example/model/User.java @@ -28,7 +28,7 @@ public class User implements UserDetails { private String shippingAddress; @ManyToMany(fetch = FetchType.EAGER) @JoinTable( - name = "user_roles", + name = "users_roles", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id") ) diff --git a/src/main/java/org/example/security/filter/JwtAuthenticationFilter.java b/src/main/java/org/example/security/filter/JwtAuthenticationFilter.java index 4a0fc0d..71957bf 100644 --- a/src/main/java/org/example/security/filter/JwtAuthenticationFilter.java +++ b/src/main/java/org/example/security/filter/JwtAuthenticationFilter.java @@ -34,7 +34,7 @@ protected void doFilterInternal( if (token != null && jwtUtil.isValidToken(token)) { String username = jwtUtil.getUserName(token); - UserDetails userDetails = customUserDetailsService.loadUserByUsername(username); // Uลผycie customUserDetailsService + UserDetails userDetails = customUserDetailsService.loadUserByUsername(username); Authentication authentication = new UsernamePasswordAuthenticationToken( userDetails, null, userDetails.getAuthorities() ); diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 6e59149..f30d73f 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -14,5 +14,5 @@ spring.liquibase.enabled=true spring.liquibase.change-log=classpath:db/changelog/db.changelog-master.yaml # Konfiguracja JWT -jwt.expiration=300 +jwt.expiration=3600000 jwt.secret=oajshfoliaslfas213ojhagsgd343adfadfhdfhffhsgwr543sfdgs2 diff --git a/src/main/resources/db/changelog/changes/008-assign-roles.yaml b/src/main/resources/db/changelog/changes/008-assign-roles.yaml index 462efa8..8824937 100644 --- a/src/main/resources/db/changelog/changes/008-assign-roles.yaml +++ b/src/main/resources/db/changelog/changes/008-assign-roles.yaml @@ -12,4 +12,9 @@ databaseChangeLog: sql: > INSERT INTO users_roles (user_id, role_id) SELECT u.id, r.id FROM users u, roles r - WHERE u.email = 'admin@example.com' AND r.name = 'ROLE_USER'; \ No newline at end of file + WHERE u.email = 'admin@example.com' AND r.name = 'ROLE_USER'; + - sql: + sql: > + INSERT INTO users_roles (user_id, role_id) + SELECT u.id, r.id FROM users u, roles r + WHERE u.email = 'user@example.com' AND r.name = 'ROLE_USER'; \ No newline at end of file From b725995c8545b351ac6f886dbc73a9303f58bff4 Mon Sep 17 00:00:00 2001 From: Artur Date: Tue, 13 May 2025 20:30:55 +0200 Subject: [PATCH 06/11] Added missing tables --- .../changes/009-create-books-table.yaml | 46 ++++++++++++++++++ .../010-create-book-category-table.yaml | 34 ++++++++++++++ .../011-create-shopping-carts-table.yaml | 26 ++++++++++ .../changes/012-create-cart-items-table.yaml | 42 +++++++++++++++++ .../changes/013-create-orders-table.yaml | 46 ++++++++++++++++++ .../changes/014-create-order-items-table.yaml | 47 +++++++++++++++++++ .../db/changelog/db.changelog-master.yaml | 14 +++++- 7 files changed, 254 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/db/changelog/changes/009-create-books-table.yaml create mode 100644 src/main/resources/db/changelog/changes/010-create-book-category-table.yaml create mode 100644 src/main/resources/db/changelog/changes/011-create-shopping-carts-table.yaml create mode 100644 src/main/resources/db/changelog/changes/012-create-cart-items-table.yaml create mode 100644 src/main/resources/db/changelog/changes/013-create-orders-table.yaml create mode 100644 src/main/resources/db/changelog/changes/014-create-order-items-table.yaml diff --git a/src/main/resources/db/changelog/changes/009-create-books-table.yaml b/src/main/resources/db/changelog/changes/009-create-books-table.yaml new file mode 100644 index 0000000..ee1a5ce --- /dev/null +++ b/src/main/resources/db/changelog/changes/009-create-books-table.yaml @@ -0,0 +1,46 @@ +databaseChangeLog: + - changeSet: + id: 009-create-books-table + author: artur + changes: + - createTable: + tableName: books + columns: + - column: + name: id + type: BIGINT + autoIncrement: true + constraints: + primaryKey: true + nullable: false + - column: + name: title + type: VARCHAR(255) + constraints: + nullable: false + - column: + name: author + type: VARCHAR(255) + constraints: + nullable: false + - column: + name: isbn + type: VARCHAR(255) + constraints: + nullable: false + unique: true + - column: + name: price + type: DECIMAL(10,2) + constraints: + nullable: false + - column: + name: description + type: VARCHAR(1000) + - column: + name: cover_image + type: VARCHAR(255) + - column: + name: is_deleted + type: BOOLEAN + defaultValueBoolean: false diff --git a/src/main/resources/db/changelog/changes/010-create-book-category-table.yaml b/src/main/resources/db/changelog/changes/010-create-book-category-table.yaml new file mode 100644 index 0000000..d56a33c --- /dev/null +++ b/src/main/resources/db/changelog/changes/010-create-book-category-table.yaml @@ -0,0 +1,34 @@ +databaseChangeLog: + - changeSet: + id: 010-create-book-category-table + author: artur + changes: + - createTable: + tableName: book_category + columns: + - column: + name: book_id + type: BIGINT + constraints: + nullable: false + - column: + name: category_id + type: BIGINT + constraints: + nullable: false + - addPrimaryKey: + tableName: book_category + columnNames: book_id, category_id + constraintName: pk_book_category + - addForeignKeyConstraint: + baseTableName: book_category + baseColumnNames: book_id + referencedTableName: books + referencedColumnNames: id + constraintName: fk_book_category_book + - addForeignKeyConstraint: + baseTableName: book_category + baseColumnNames: category_id + referencedTableName: categories + referencedColumnNames: id + constraintName: fk_book_category_category diff --git a/src/main/resources/db/changelog/changes/011-create-shopping-carts-table.yaml b/src/main/resources/db/changelog/changes/011-create-shopping-carts-table.yaml new file mode 100644 index 0000000..c46ed1e --- /dev/null +++ b/src/main/resources/db/changelog/changes/011-create-shopping-carts-table.yaml @@ -0,0 +1,26 @@ +databaseChangeLog: + - changeSet: + id: 011-create-shopping-carts-table + author: artur + changes: + - createTable: + tableName: shopping_carts + columns: + - column: + name: id + type: BIGINT + autoIncrement: true + constraints: + primaryKey: true + nullable: false + - column: + name: user_id + type: BIGINT + constraints: + nullable: false + - addForeignKeyConstraint: + baseTableName: shopping_carts + baseColumnNames: user_id + referencedTableName: users + referencedColumnNames: id + constraintName: fk_shopping_cart_user diff --git a/src/main/resources/db/changelog/changes/012-create-cart-items-table.yaml b/src/main/resources/db/changelog/changes/012-create-cart-items-table.yaml new file mode 100644 index 0000000..fc811fe --- /dev/null +++ b/src/main/resources/db/changelog/changes/012-create-cart-items-table.yaml @@ -0,0 +1,42 @@ +databaseChangeLog: + - changeSet: + id: 012-create-cart-items-table + author: artur + changes: + - createTable: + tableName: cart_items + columns: + - column: + name: id + type: BIGINT + autoIncrement: true + constraints: + primaryKey: true + nullable: false + - column: + name: shopping_cart_id + type: BIGINT + constraints: + nullable: false + - column: + name: book_id + type: BIGINT + constraints: + nullable: false + - column: + name: quantity + type: INT + constraints: + nullable: false + - addForeignKeyConstraint: + baseTableName: cart_items + baseColumnNames: shopping_cart_id + referencedTableName: shopping_carts + referencedColumnNames: id + constraintName: fk_cart_items_cart + - addForeignKeyConstraint: + baseTableName: cart_items + baseColumnNames: book_id + referencedTableName: books + referencedColumnNames: id + constraintName: fk_cart_items_book diff --git a/src/main/resources/db/changelog/changes/013-create-orders-table.yaml b/src/main/resources/db/changelog/changes/013-create-orders-table.yaml new file mode 100644 index 0000000..e40af2b --- /dev/null +++ b/src/main/resources/db/changelog/changes/013-create-orders-table.yaml @@ -0,0 +1,46 @@ +databaseChangeLog: + - changeSet: + id: 013-create-orders-table + author: artur + changes: + - createTable: + tableName: orders + columns: + - column: + name: id + type: BIGINT + autoIncrement: true + constraints: + primaryKey: true + nullable: false + - column: + name: user_id + type: BIGINT + constraints: + nullable: false + - column: + name: status + type: VARCHAR(50) + constraints: + nullable: false + - column: + name: total + type: DECIMAL(10,2) + constraints: + nullable: false + - column: + name: shipping_address + type: VARCHAR(255) + constraints: + nullable: false + - column: + name: order_date + type: DATETIME + constraints: + nullable: false + - addForeignKeyConstraint: + baseTableName: orders + baseColumnNames: user_id + referencedTableName: users + referencedColumnNames: id + constraintName: fk_orders_user diff --git a/src/main/resources/db/changelog/changes/014-create-order-items-table.yaml b/src/main/resources/db/changelog/changes/014-create-order-items-table.yaml new file mode 100644 index 0000000..23db12b --- /dev/null +++ b/src/main/resources/db/changelog/changes/014-create-order-items-table.yaml @@ -0,0 +1,47 @@ +databaseChangeLog: + - changeSet: + id: 014-create-order-items-table + author: artur + changes: + - createTable: + tableName: order_items + columns: + - column: + name: id + type: BIGINT + autoIncrement: true + constraints: + primaryKey: true + nullable: false + - column: + name: order_id + type: BIGINT + constraints: + nullable: false + - column: + name: book_id + type: BIGINT + constraints: + nullable: false + - column: + name: quantity + type: INT + constraints: + nullable: false + - column: + name: price + type: DECIMAL(10,2) + constraints: + nullable: false + - addForeignKeyConstraint: + baseTableName: order_items + baseColumnNames: order_id + referencedTableName: orders + referencedColumnNames: id + constraintName: fk_order_items_order + - addForeignKeyConstraint: + baseTableName: order_items + baseColumnNames: book_id + referencedTableName: books + referencedColumnNames: id + constraintName: fk_order_items_book diff --git a/src/main/resources/db/changelog/db.changelog-master.yaml b/src/main/resources/db/changelog/db.changelog-master.yaml index 4552524..1af39ff 100644 --- a/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/src/main/resources/db/changelog/db.changelog-master.yaml @@ -14,4 +14,16 @@ databaseChangeLog: - include: file: db/changelog/changes/007-insert-roles.yaml - include: - file: db/changelog/changes/008-assign-roles.yaml \ No newline at end of file + file: db/changelog/changes/008-assign-roles.yaml + - include: + file: db/changelog/changes/009-create-books-table.yaml + - include: + file: db/changelog/changes/010-create-book-category-table.yaml + - include: + file: db/changelog/changes/011-create-shopping-carts-table.yaml + - include: + file: db/changelog/changes/012-create-cart-items-table.yaml + - include: + file: db/changelog/changes/013-create-orders-table.yaml + - include: + file: db/changelog/changes/014-create-order-items-table.yaml \ No newline at end of file From bb106fa3c73ca4c9b5dafe7648c1dd23dc76dfff Mon Sep 17 00:00:00 2001 From: Artur Date: Thu, 15 May 2025 12:15:48 +0200 Subject: [PATCH 07/11] added @EnableMethodSecurity, and shipping adress --- src/main/java/org/example/config/SecurityConfig.java | 2 ++ .../resources/db/changelog/changes/006-insert-users.yaml | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/example/config/SecurityConfig.java b/src/main/java/org/example/config/SecurityConfig.java index c9708ee..ee97c85 100644 --- a/src/main/java/org/example/config/SecurityConfig.java +++ b/src/main/java/org/example/config/SecurityConfig.java @@ -8,6 +8,7 @@ import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @@ -16,6 +17,7 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @Configuration +@EnableMethodSecurity @RequiredArgsConstructor public class SecurityConfig { private final CustomUserDetailsServiceImpl customUserDetailServiceImpl; diff --git a/src/main/resources/db/changelog/changes/006-insert-users.yaml b/src/main/resources/db/changelog/changes/006-insert-users.yaml index d8edff9..e12c75d 100644 --- a/src/main/resources/db/changelog/changes/006-insert-users.yaml +++ b/src/main/resources/db/changelog/changes/006-insert-users.yaml @@ -18,6 +18,9 @@ databaseChangeLog: - column: name: password value: "$2a$10$EQVI2UweY22CoQXOd4I3EOF41lk55sboVMYQ7sgroVveCyR6wviZC" + - column: + name: shipping_address + value: "random Adress Admin" - insert: tableName: users columns: @@ -32,4 +35,7 @@ databaseChangeLog: value: "user@example.com" - column: name: password - value: "$2a$10$DZKy0ba28TVjZDrvY9hcpu9jIq2DlXrduGWpvPHg6Tt1.9UWYgiSC" \ No newline at end of file + value: "$2a$10$DZKy0ba28TVjZDrvY9hcpu9jIq2DlXrduGWpvPHg6Tt1.9UWYgiSC" + - column: + name: shipping_address + value: "random Adress User" \ No newline at end of file From d3d8dd9288bbed45bb0696531504c1435e0c7fb9 Mon Sep 17 00:00:00 2001 From: Artur Date: Thu, 15 May 2025 22:58:09 +0200 Subject: [PATCH 08/11] updated versions in pom.xml --- pom.xml | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/pom.xml b/pom.xml index b868491..8a96a9e 100644 --- a/pom.xml +++ b/pom.xml @@ -69,17 +69,9 @@ com.mysql mysql-connector-j - 8.2.0 runtime - - - org.hibernate.orm - hibernate-core - 6.2.7.Final - - org.mapstruct @@ -110,7 +102,7 @@ org.springdoc springdoc-openapi-starter-webmvc-ui - 2.1.0 + 2.8.8 @@ -257,4 +249,4 @@ - + \ No newline at end of file From 1cc2c121990574f05c0577b3cfccfd0dd7da1427 Mon Sep 17 00:00:00 2001 From: Artur Date: Fri, 16 May 2025 08:22:07 +0200 Subject: [PATCH 09/11] shortened the token's lifetime --- src/main/resources/application.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index f30d73f..c95cde0 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -14,5 +14,5 @@ spring.liquibase.enabled=true spring.liquibase.change-log=classpath:db/changelog/db.changelog-master.yaml # Konfiguracja JWT -jwt.expiration=3600000 +jwt.expiration=600000 jwt.secret=oajshfoliaslfas213ojhagsgd343adfadfhdfhffhsgwr543sfdgs2 From 2f657a4e75b802cb8c95b43b5e0ab83d1019733b Mon Sep 17 00:00:00 2001 From: Artur Date: Wed, 4 Jun 2025 19:41:02 +0200 Subject: [PATCH 10/11] added /api prefix to book controller --- src/main/java/org/example/controller/BookController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/example/controller/BookController.java b/src/main/java/org/example/controller/BookController.java index 2ec8aff..a2c3f4a 100644 --- a/src/main/java/org/example/controller/BookController.java +++ b/src/main/java/org/example/controller/BookController.java @@ -28,7 +28,7 @@ @Tag(name = "Book management", description = "Endpoints for managing books") @RequiredArgsConstructor @RestController -@RequestMapping(value = "/books") +@RequestMapping(value = "/api/books") public class BookController { private final BookService bookService; From 58db42df036950f6a168e0a4805fd2d2c853a05a Mon Sep 17 00:00:00 2001 From: Artur Date: Fri, 6 Jun 2025 13:31:27 +0200 Subject: [PATCH 11/11] added README.md with link to video --- README.md | 178 +++++++++++++++++++++++++----------------------------- 1 file changed, 83 insertions(+), 95 deletions(-) diff --git a/README.md b/README.md index 4ad4a76..68ddb92 100644 --- a/README.md +++ b/README.md @@ -1,132 +1,120 @@ -# ๐Ÿ“š Online Book Store API - +๐Ÿ“š Online Book Store API A comprehensive backend application for managing an online bookstore, built with Java and Spring Boot. It offers full CRUD functionality for books, categories, shopping carts, and orders, along with user authentication and role-based access control. --- -## ๐ŸŽฏ Project Overview - +๐ŸŽฏ Project Overview This application serves as the backend for an online book store, supporting two roles: -* **Shopper (User):** - - * Sign up / Sign in - * Browse books by category or all at once - * View book details - * Add/remove books to/from cart - * Place orders and view order history - -* **Manager (Admin):** +โ€ข **Shopper (User)** +- Sign up / Sign in +- Browse books by category or all at once +- View book details +- Add/remove books to/from cart +- Place orders and view order history - * Add, update, delete books - * Manage categories - * Update order status +โ€ข **Manager (Admin)** +- Add, update, delete books +- Manage categories +- Update order status -The system is structured around 8 core domain models: +The system is structured around 8 core domain models: `User`, `Role`, `Book`, `Category`, `ShoppingCart`, `CartItem`, `Order`, `OrderItem` --- -## ๐Ÿš€ Technologies & Tools - -| Tool | Description | -| ------------------- | ------------------------------ | -| Java 21 | Core language | -| Spring Boot 3.4.1 | Main framework | -| Spring Security | Authentication & authorization | -| Spring Data JPA | Data persistence | -| JWT | Token-based authentication | -| MapStruct | DTO mapping | -| Liquibase | DB schema management | -| Hibernate Validator | Input validation | -| Testcontainers | Integration tests with Docker | -| MySQL / H2 | Databases (prod/test) | -| Swagger | API documentation | -| Lombok | Less boilerplate | -| Checkstyle | Code quality | +๐Ÿš€ Technologies & Tools + +| Tool | Description | +|--------------------|----------------------------------| +| Java 21 | Core language | +| Spring Boot 3.4.1 | Main framework | +| Spring Security | Authentication & authorization | +| Spring Data JPA | Data persistence | +| JWT | Token-based authentication | +| MapStruct | DTO mapping | +| Liquibase | DB schema management | +| Hibernate Validator| Input validation | +| Testcontainers | Integration tests with Docker | +| MySQL / H2 | Databases (prod/test) | +| Swagger | API documentation | +| Lombok | Less boilerplate | +| Checkstyle | Code quality | --- -## ๐Ÿ”Œ API Endpoints Overview - -### โœ… Authentication - -* `POST /api/auth/register` โ€“ Register a new user -* `POST /api/auth/login` โ€“ Login and receive a JWT token - -### ๐Ÿ“š Book - -* `GET /books` โ€“ List all books -* `GET /books/{id}` โ€“ View book by ID -* `POST /books` โ€“ Add a book (admin only) -* `PUT /books/{id}` โ€“ Update book -* `DELETE /books/{id}` โ€“ Delete book -* `GET /books/search` โ€“ Search books - -### ๐Ÿท๏ธ Category - -* `POST /api/categories` โ€“ Add a category -* `GET /api/categories` โ€“ List categories -* `GET /api/categories/{id}` โ€“ View category -* `PUT /api/categories/{id}` โ€“ Update category -* `DELETE /api/categories/{id}` โ€“ Delete category -* `GET /api/categories/{id}/books` โ€“ View books in category - -### ๐Ÿ›’ Shopping Cart - -* `GET /api/cart` โ€“ View cart -* `POST /api/cart` โ€“ Add item to cart -* `PUT /api/cart/cart-items/{cartItemId}` โ€“ Update item -* `DELETE /api/cart/cart-items/{cartItemId}` โ€“ Remove item - -### ๐Ÿ“ฆ Order - -* `POST /api/orders` โ€“ Place an order -* `GET /api/orders` โ€“ View order history -* `GET /api/orders/{orderId}/items` โ€“ Items in an order -* `GET /api/orders/{orderId}/items/{itemId}` โ€“ View specific item -* `PATCH /api/orders/{id}` โ€“ Update order status +๐Ÿ”Œ API Endpoints Overview + +โœ… **Authentication** +- `POST /api/auth/register` โ€“ Register a new user +- `POST /api/auth/login` โ€“ Login and receive a JWT token + +๐Ÿ“š **Book** +- `GET /api/books` โ€“ List all books +- `GET /api/books/{id}` โ€“ View book by ID +- `POST /api/books` โ€“ Add a book (admin only) +- `PUT /api/books/{id}` โ€“ Update book +- `DELETE /api/books/{id}` โ€“ Delete book +- `GET /api/books/search` โ€“ Search books + +๐Ÿท๏ธ **Category** +- `POST /api/categories` โ€“ Add a category +- `GET /api/categories` โ€“ List categories +- `GET /api/categories/{id}` โ€“ View category +- `PUT /api/categories/{id}` โ€“ Update category +- `DELETE /api/categories/{id}` โ€“ Delete category +- `GET /api/categories/{id}/books` โ€“ View books in category + +๐Ÿ›’ **Shopping Cart** +- `GET /api/cart` โ€“ View cart +- `POST /api/cart` โ€“ Add item to cart +- `PUT /api/cart/cart-items/{cartItemId}` โ€“ Update item +- `DELETE /api/cart/cart-items/{cartItemId}` โ€“ Remove item + +๐Ÿ“ฆ **Order** +- `POST /api/orders` โ€“ Place an order +- `GET /api/orders` โ€“ View order history +- `GET /api/orders/{orderId}/items` โ€“ Items in an order +- `GET /api/orders/{orderId}/items/{itemId}` โ€“ View specific item +- `PATCH /api/orders/{id}` โ€“ Update order status --- -## ๐ŸŒ Live Demo +๐ŸŒ Live Demo -๐Ÿงช Swagger UI (hosted on AWS): -[http://ec2-13-60-51-178.eu-north-1.compute.amazonaws.com/swagger-ui/index.html](http://ec2-13-60-51-178.eu-north-1.compute.amazonaws.com/swagger-ui/index.html) +๐Ÿงช Swagger UI after starting the application locally: +http://localhost:8080/swagger-ui.html -๐Ÿ“น YouTube Demo *(Add your link here)* +๐Ÿ“น YouTube Demo: +https://youtu.be/K64DTGeaMEM --- -## ๐Ÿ” Default Users +๐Ÿ” Default Users -| Role | Email | Password | -| ----- | ------------------- | -------------- | -| Admin | `admin@example.com` | `adminExample` | -| User | `user@example.com` | `userExample` | +| Role | Email | Password | +|-------|---------------------|---------------| +| Admin | admin@example.com | adminExample | +| User | user@example.com | userExample | -> ๐Ÿ› ๏ธ These accounts are automatically created on application startup via `DataInitializer`. +๐Ÿ› ๏ธ These accounts are automatically created on application startup via `DataInitializer`. --- -## **โš™๏ธ Setup Instructions** - -### **โœ… Prerequisites** - -* Java 17+ -* Docker -* Maven +โš™๏ธ Setup Instructions -### **๐Ÿงช Clone & Run Locally** +โœ… **Prerequisites** +- Java 17+ +- Docker +- Maven -``` +๐Ÿงช **Clone & Run Locally** +```bash # Clone repo -git clone https://github.com/your-username/your-repo-name.git -cd your-repo-name +git clone https://github.com/dedis34/SpringBoot-BookShop.git # Package app ./mvnw clean package # Run app with Docker docker compose up -```