From fdcecf836876048af2227313165ec2c52d9ede48 Mon Sep 17 00:00:00 2001 From: TakahashiNguyen Date: Sun, 12 Apr 2026 14:27:37 +0000 Subject: [PATCH] fix: better url (#20) Co-authored-by: TakahashiNg <83152264+TakahashiNguyen@users.noreply.github.com> Reviewed-on: https://git.demonkernel.io.vn/FoodSurf/backend/pulls/20 --- .devcontainer/devcontainer.json | 3 +- .gitea/workflows/test.yaml | 13 ++- account-service/pom.xml | 5 ++ .../com/drinkool/entities/CustomerEntity.java | 13 ++- .../com/drinkool/entities/ManagerEntity.java | 27 +++++++ .../java/com/drinkool/models/UserModel.java | 11 +-- .../com/drinkool/services/AccountService.java | 32 ++++++++ .../{UserService.java => BaseService.java} | 12 ++- ...ationService.java => CustomerService.java} | 32 ++------ .../com/drinkool/services/ManagerService.java | 55 +++++++++++++ .../src/main/resources/application.properties | 2 +- .../src/test/java/com/drinkool/Utils.java | 12 +++ .../drinkool/entities/CustomerEntityTest.java | 55 ++++--------- .../com/drinkool/models/UserModelTest.java | 18 ----- .../drinkool/services/AccountServiceTest.java | 40 ++++++++++ ...rServiceTest.java => BaseServiceTest.java} | 15 ++-- ...viceTest.java => CustomerServiceTest.java} | 71 ++++++++-------- eatery-service/pom.xml | 32 +++----- .../src/main/resources/application.properties | 18 ++++- gateway-service/pom.xml | 5 ++ ...ewayResource.java => GatewayResource.java} | 9 ++- .../com/drinkool/services/AccountService.java | 6 +- .../src/main/resources/application.properties | 3 +- k8s.yaml | 80 ++++++++++++++++--- lib/src/main/java/com/drinkool/Role.java | 1 + .../java/com/drinkool/dtos/ManagerSignup.java | 5 ++ pom.xml | 30 +++++-- 27 files changed, 409 insertions(+), 196 deletions(-) create mode 100644 account-service/src/main/java/com/drinkool/entities/ManagerEntity.java create mode 100644 account-service/src/main/java/com/drinkool/services/AccountService.java rename account-service/src/main/java/com/drinkool/services/{UserService.java => BaseService.java} (67%) rename account-service/src/main/java/com/drinkool/services/{AuthenticationService.java => CustomerService.java} (76%) create mode 100644 account-service/src/main/java/com/drinkool/services/ManagerService.java create mode 100644 account-service/src/test/java/com/drinkool/Utils.java create mode 100644 account-service/src/test/java/com/drinkool/services/AccountServiceTest.java rename account-service/src/test/java/com/drinkool/services/{UserServiceTest.java => BaseServiceTest.java} (71%) rename account-service/src/test/java/com/drinkool/services/{AuthenticationServiceTest.java => CustomerServiceTest.java} (74%) rename gateway-service/src/main/java/com/drinkool/{CustomerGatewayResource.java => GatewayResource.java} (81%) create mode 100644 lib/src/main/java/com/drinkool/dtos/ManagerSignup.java diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 56dee5e..c366dff 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -17,7 +17,8 @@ "redhat.vscode-xml", "esbenp.prettier-vscode", "PeterSchmalfeldt.explorer-exclude", - "redhat.java" + "redhat.java", + "ryanluker.vscode-coverage-gutters" ] } }, diff --git a/.gitea/workflows/test.yaml b/.gitea/workflows/test.yaml index 375419e..ee3b07e 100644 --- a/.gitea/workflows/test.yaml +++ b/.gitea/workflows/test.yaml @@ -38,8 +38,13 @@ jobs: ./mvnw -B install \ -Dquarkus.container-image.push=false \ - - name: Publish Test Report - uses: scacap/action-surefire-report@v1 - if: failure() + - name: Jacoco Report to PR + uses: madrapps/jacoco-report@v1.7.2 + if: always() with: - github_token: ${{ secrets.ACCESS_TOKEN }} + paths: | + ./**/jacoco.xml, + token: ${{ secrets.ACCESS_TOKEN }} + min-coverage-overall: 40 + min-coverage-changed-files: 60 + title: "📊 Báo cáo Độ bao phủ Kiểm thử (Test Coverage)" diff --git a/account-service/pom.xml b/account-service/pom.xml index 0081ef6..31abd86 100644 --- a/account-service/pom.xml +++ b/account-service/pom.xml @@ -46,6 +46,11 @@ + + io.quarkus + quarkus-jacoco + test + com.drinkool lib diff --git a/account-service/src/main/java/com/drinkool/entities/CustomerEntity.java b/account-service/src/main/java/com/drinkool/entities/CustomerEntity.java index 5824f0c..3f75fd7 100644 --- a/account-service/src/main/java/com/drinkool/entities/CustomerEntity.java +++ b/account-service/src/main/java/com/drinkool/entities/CustomerEntity.java @@ -1,8 +1,17 @@ package com.drinkool.entities; +import com.drinkool.Role; import com.drinkool.models.UserModel; import jakarta.persistence.*; +import jakarta.transaction.Transactional; +import java.util.UUID; @Entity -@Table(name = "customer") -public class CustomerEntity extends UserModel {} +@Table(name = Role.Customer) +public class CustomerEntity extends UserModel { + + @Transactional + public void signup(String phone) { + this.signup(phone, phone, UUID.randomUUID().toString().substring(0, 32)); + } +} diff --git a/account-service/src/main/java/com/drinkool/entities/ManagerEntity.java b/account-service/src/main/java/com/drinkool/entities/ManagerEntity.java new file mode 100644 index 0000000..582a489 --- /dev/null +++ b/account-service/src/main/java/com/drinkool/entities/ManagerEntity.java @@ -0,0 +1,27 @@ +package com.drinkool.entities; + +import com.drinkool.Role; +import com.drinkool.models.UserModel; +import jakarta.persistence.*; + +@Entity +@Table(name = Role.Manager) +public class ManagerEntity extends UserModel { + + public String eateryName; + + public boolean isVerified; + + public void signup( + String name, + String phone, + String rawPassword, + String eateryName + ) { + this.eateryName = eateryName; + + this.isVerified = false; + + this.signup(name, phone, rawPassword); + } +} diff --git a/account-service/src/main/java/com/drinkool/models/UserModel.java b/account-service/src/main/java/com/drinkool/models/UserModel.java index ef59493..7145ea3 100644 --- a/account-service/src/main/java/com/drinkool/models/UserModel.java +++ b/account-service/src/main/java/com/drinkool/models/UserModel.java @@ -7,7 +7,6 @@ import com.password4j.Password; import jakarta.persistence.*; import jakarta.transaction.*; import jakarta.ws.rs.BadRequestException; -import java.util.UUID; @Entity @Inheritance(strategy = InheritanceType.JOINED) @@ -24,19 +23,12 @@ public abstract class UserModel extends BaseEntity { @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) public String hashedPassword; - @Transactional - public void signup(String phone) { - this.signup(phone, phone, UUID.randomUUID().toString().substring(0, 32)); - } - @Transactional public void signup(String name, String phone, String rawPassword) { - // Check existed user - UserModel existedUser = find("phone", phone).firstResult(); + UserModel existedUser = UserModel.find("phone", phone).firstResult(); if (existedUser != null) throw new BadRequestException("ExistedUser"); - // Set user this.name = name; if (!PhoneValidator.isValidInternationalPhone(phone)) { @@ -47,7 +39,6 @@ public abstract class UserModel extends BaseEntity { this.hashedPassword = Password.hash(rawPassword).withArgon2().getResult(); - // Save user this.persist(); } diff --git a/account-service/src/main/java/com/drinkool/services/AccountService.java b/account-service/src/main/java/com/drinkool/services/AccountService.java new file mode 100644 index 0000000..5c7cb22 --- /dev/null +++ b/account-service/src/main/java/com/drinkool/services/AccountService.java @@ -0,0 +1,32 @@ +package com.drinkool.services; + +import com.drinkool.Url; +import com.drinkool.dtos.SmsOtp; +import com.drinkool.models.UserModel; +import jakarta.inject.Inject; +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.Response; + +@Path("") +public class AccountService { + + @Inject + OtpService otpService; + + @POST + @Path(Url.SmsOtp) + public Response smsOtp(SmsOtp input) { + UserModel customer = UserModel.find("phone", input.phone).firstResult(); + + if (customer == null) return Response.status(Response.Status.BAD_REQUEST) + .entity("InvalidPhoneNumber") + .build(); + + String otp = otpService.generateAndSaveOtp(input.phone); + + // Ở đây bạn sẽ gọi Kafka để gửi SMS thực tế + System.out.println("OTP cho " + input.phone + " là: " + otp); + + return Response.accepted().build(); + } +} diff --git a/account-service/src/main/java/com/drinkool/services/UserService.java b/account-service/src/main/java/com/drinkool/services/BaseService.java similarity index 67% rename from account-service/src/main/java/com/drinkool/services/UserService.java rename to account-service/src/main/java/com/drinkool/services/BaseService.java index 2cd2280..e03ece8 100644 --- a/account-service/src/main/java/com/drinkool/services/UserService.java +++ b/account-service/src/main/java/com/drinkool/services/BaseService.java @@ -8,9 +8,15 @@ import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; import java.util.UUID; -@Path("") -public class UserService { +public abstract class BaseService { + private UserModel model; + + public BaseService(UserModel model) { + this.model = model; + } + + @SuppressWarnings("static-access") @POST @Path(Url.Me) @Transactional @@ -19,6 +25,6 @@ public class UserService { .entity("InvalidUserId") .build(); - return Response.ok(UserModel.find("id", id).firstResult()).build(); + return Response.ok(model.find("id", id).firstResult()).build(); } } diff --git a/account-service/src/main/java/com/drinkool/services/AuthenticationService.java b/account-service/src/main/java/com/drinkool/services/CustomerService.java similarity index 76% rename from account-service/src/main/java/com/drinkool/services/AuthenticationService.java rename to account-service/src/main/java/com/drinkool/services/CustomerService.java index 490bcb4..eb5bbb1 100644 --- a/account-service/src/main/java/com/drinkool/services/AuthenticationService.java +++ b/account-service/src/main/java/com/drinkool/services/CustomerService.java @@ -1,8 +1,6 @@ package com.drinkool.services; -import com.drinkool.InternalValue; -import com.drinkool.Role; -import com.drinkool.Url; +import com.drinkool.*; import com.drinkool.dtos.*; import com.drinkool.entities.CustomerEntity; import jakarta.inject.Inject; @@ -10,12 +8,16 @@ import jakarta.transaction.Transactional; import jakarta.ws.rs.*; import jakarta.ws.rs.core.*; -@Path("") -public class AuthenticationService { +@Path(Role.Customer) +public class CustomerService extends BaseService { @Inject OtpService otpService; + public CustomerService() { + super(new CustomerEntity()); + } + @POST @Path(Url.Signup) @Transactional @@ -87,24 +89,4 @@ public class AuthenticationService { .header(InternalValue.role, Role.Customer) .build(); } - - @POST - @Path(Url.SmsOtp) - public Response smsOtp(SmsOtp input) { - CustomerEntity customer = CustomerEntity.find( - "phone", - input.phone - ).firstResult(); - - if (customer == null) return Response.status(Response.Status.BAD_REQUEST) - .entity("InvalidPhoneNumber") - .build(); - - String otp = otpService.generateAndSaveOtp(input.phone); - - // Ở đây bạn sẽ gọi Kafka để gửi SMS thực tế - System.out.println("OTP cho " + input.phone + " là: " + otp); - - return Response.accepted().build(); - } } diff --git a/account-service/src/main/java/com/drinkool/services/ManagerService.java b/account-service/src/main/java/com/drinkool/services/ManagerService.java new file mode 100644 index 0000000..f69f601 --- /dev/null +++ b/account-service/src/main/java/com/drinkool/services/ManagerService.java @@ -0,0 +1,55 @@ +package com.drinkool.services; + +import com.drinkool.*; +import com.drinkool.dtos.*; +import com.drinkool.entities.ManagerEntity; +import jakarta.transaction.Transactional; +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.*; + +@Path(Role.Manager) +public class ManagerService { + + @POST + @Path(Url.Signup) + @Transactional + public Response signup(ManagerSignup input) { + ManagerEntity newManager = new ManagerEntity(); + + newManager.signup( + input.name, + input.phone, + input.password, + input.eateryName + ); + + return Response.status(Response.Status.CREATED) + .header(InternalValue.userId, newManager.id.toString()) + .header(InternalValue.role, Role.Manager) + .build(); + } + + @POST + @Path(Url.Login) + public Response login(Login input) { + ManagerEntity customer = ManagerEntity.find( + "phone", + input.phone + ).firstResult(); + + if (customer == null) return Response.status(Response.Status.BAD_REQUEST) + .entity("InvalidPhoneNumber") + .build(); + + if (!customer.login(input.password)) return Response.status( + Response.Status.BAD_REQUEST + ) + .entity("InvalidPassword") + .build(); + + return Response.accepted() + .header(InternalValue.userId, customer.id.toString()) + .header(InternalValue.role, Role.Manager) + .build(); + } +} diff --git a/account-service/src/main/resources/application.properties b/account-service/src/main/resources/application.properties index 18cb5a4..4b0e734 100644 --- a/account-service/src/main/resources/application.properties +++ b/account-service/src/main/resources/application.properties @@ -25,4 +25,4 @@ quarkus.index-dependency.lib.artifact-id=lib # Build quarkus.native.container-build=false -quarkus.native.additional-build-args=--initialize-at-run-time=com.password4j.AlgorithmFinder \ No newline at end of file +quarkus.native.additional-build-args=--initialize-at-run-time=com.password4j.AlgorithmFinder,--future-defaults=all \ No newline at end of file diff --git a/account-service/src/test/java/com/drinkool/Utils.java b/account-service/src/test/java/com/drinkool/Utils.java new file mode 100644 index 0000000..a959fb2 --- /dev/null +++ b/account-service/src/test/java/com/drinkool/Utils.java @@ -0,0 +1,12 @@ +package com.drinkool; + +import java.util.Random; + +public class Utils { + + public static Random random = new Random(); + + public static String generateRandomPhone() { + return "+8477" + String.format("%07d", random.nextInt(10000000)); + } +} diff --git a/account-service/src/test/java/com/drinkool/entities/CustomerEntityTest.java b/account-service/src/test/java/com/drinkool/entities/CustomerEntityTest.java index a21454a..77dec4c 100644 --- a/account-service/src/test/java/com/drinkool/entities/CustomerEntityTest.java +++ b/account-service/src/test/java/com/drinkool/entities/CustomerEntityTest.java @@ -1,56 +1,29 @@ package com.drinkool.entities; +import static org.junit.jupiter.api.Assertions.*; + +import com.drinkool.*; import io.quarkus.test.junit.QuarkusTest; -import jakarta.inject.Inject; -import jakarta.persistence.EntityManager; import jakarta.transaction.Transactional; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.*; @QuarkusTest public class CustomerEntityTest { - @Inject - EntityManager entityManager; - @Test @Transactional - public void testCustomerPersistence() { - // 1. Khởi tạo đúng Entity (CustomerEntity chứ không phải CustomerEntityTest) - CustomerEntity customer = new CustomerEntity(); + public void testSignupOneParamSuccess() { + CustomerEntity user = new CustomerEntity(); + String phone = Utils.generateRandomPhone(); - // Gán đúng biến name, phone và hashedPassword (các trường kế thừa từ UserModel) - customer.name = "Nguyen Van A"; - customer.phone = "+84987654321"; - customer.hashedPassword = "dummy_hashed_password"; + user.signup(phone); - // 2. Lưu vào DB - entityManager.persist(customer); - entityManager.flush(); - entityManager.clear(); - - // 3. Truy vấn lại để kiểm tra (Sửa lại class map của query thành CustomerEntity) - var query = entityManager.createQuery( - "SELECT c FROM CustomerEntity c WHERE c.phone = :phone", - CustomerEntity.class + assertNotNull(user.id, "ID not null after persist"); + assertEquals(phone, user.name, "Tên mặc định phải là số điện thoại"); + assertEquals(phone, user.phone); + assertNotNull( + user.hashedPassword, + "Password tự động phải được tạo và hash" ); - query.setParameter("phone", "+84987654321"); - - // Nhận kết quả về đúng kiểu CustomerEntity - CustomerEntity savedCustomer = query.getSingleResult(); - - // 4. Assert (Kiểm chứng) - Assertions.assertNotNull(savedCustomer, "Customer không được null"); - Assertions.assertEquals( - "Nguyen Van A", - savedCustomer.name, - "Tên không khớp" - ); - Assertions.assertEquals( - "+84987654321", - savedCustomer.phone, - "Số điện thoại không khớp" - ); - Assertions.assertNotNull(savedCustomer.id, "ID chưa được sinh ra"); } } diff --git a/account-service/src/test/java/com/drinkool/models/UserModelTest.java b/account-service/src/test/java/com/drinkool/models/UserModelTest.java index 6073c7d..28f42db 100644 --- a/account-service/src/test/java/com/drinkool/models/UserModelTest.java +++ b/account-service/src/test/java/com/drinkool/models/UserModelTest.java @@ -44,24 +44,6 @@ public class UserModelTest { assertNotNull(savedUser, "Phải tìm thấy user trong database"); } - // 2. Test case: Đăng ký thành công (chỉ dùng số điện thoại) - @Test - @Transactional - public void testSignupOneParamSuccess() { - TestUserEntity user = new TestUserEntity(); - String phone = generateValidPhone(); - - user.signup(phone); - - assertNotNull(user.id, "ID not null after persist"); - assertEquals(phone, user.name, "Tên mặc định phải là số điện thoại"); - assertEquals(phone, user.phone); - assertNotNull( - user.hashedPassword, - "Password tự động phải được tạo và hash" - ); - } - // 3. Test case: Đăng ký thất bại do số điện thoại đã tồn tại @Test @Transactional diff --git a/account-service/src/test/java/com/drinkool/services/AccountServiceTest.java b/account-service/src/test/java/com/drinkool/services/AccountServiceTest.java new file mode 100644 index 0000000..c8880af --- /dev/null +++ b/account-service/src/test/java/com/drinkool/services/AccountServiceTest.java @@ -0,0 +1,40 @@ +package com.drinkool.services; + +import static io.restassured.RestAssured.*; + +import com.drinkool.*; +import com.drinkool.dtos.*; +import io.quarkus.test.junit.QuarkusTest; +import io.restassured.http.ContentType; +import org.junit.jupiter.api.Test; + +@QuarkusTest +public class AccountServiceTest { + + @Test + void testSmsOtp() { + String phone = Utils.generateRandomPhone(); + SmsOtp input = new SmsOtp(); + input.phone = phone; + + Signup signup = new Signup(); + signup.phone = phone; + signup.name = "sms user"; + signup.password = "password123"; + + given() + .contentType(ContentType.JSON) + .body(signup) + .when() + .post(Role.Customer + Url.Signup) + .then(); + + given() + .contentType(ContentType.JSON) + .body(input) + .when() + .post(Url.SmsOtp) + .then() + .statusCode(202); + } +} diff --git a/account-service/src/test/java/com/drinkool/services/UserServiceTest.java b/account-service/src/test/java/com/drinkool/services/BaseServiceTest.java similarity index 71% rename from account-service/src/test/java/com/drinkool/services/UserServiceTest.java rename to account-service/src/test/java/com/drinkool/services/BaseServiceTest.java index eb8c5ea..8a832e3 100644 --- a/account-service/src/test/java/com/drinkool/services/UserServiceTest.java +++ b/account-service/src/test/java/com/drinkool/services/BaseServiceTest.java @@ -3,19 +3,18 @@ package com.drinkool.services; import static io.restassured.RestAssured.*; import static org.hamcrest.CoreMatchers.*; -import com.drinkool.InternalValue; -import com.drinkool.Url; -import com.drinkool.dtos.QuickSignup; +import com.drinkool.*; +import com.drinkool.dtos.*; import io.quarkus.test.junit.QuarkusTest; import io.restassured.http.ContentType; import org.junit.jupiter.api.Test; @QuarkusTest -public class UserServiceTest { +public class BaseServiceTest { @Test public void testMeEndpointWithHeader() { - String phone = AuthenticationServiceTest.generateRandomPhone(); + String phone = Utils.generateRandomPhone(); QuickSignup input = new QuickSignup(); input.phone = phone; @@ -23,7 +22,7 @@ public class UserServiceTest { .contentType(ContentType.JSON) .body(input) .when() - .post(Url.QuickSignup) + .post(Role.Customer + Url.QuickSignup) .then() .extract() .header(InternalValue.userId); @@ -32,7 +31,7 @@ public class UserServiceTest { .header(InternalValue.userId, testUserId) .contentType(ContentType.JSON) .when() - .post(Url.Me) + .post(Role.Customer + Url.Me) .then() .statusCode(200) .body("id", is(testUserId)); @@ -40,6 +39,6 @@ public class UserServiceTest { @Test public void testMeEndpointWithoutHeader() { - given().when().post(Url.Me).then().statusCode(400); + given().when().post(Role.Customer + Url.Me).then().statusCode(400); } } diff --git a/account-service/src/test/java/com/drinkool/services/AuthenticationServiceTest.java b/account-service/src/test/java/com/drinkool/services/CustomerServiceTest.java similarity index 74% rename from account-service/src/test/java/com/drinkool/services/AuthenticationServiceTest.java rename to account-service/src/test/java/com/drinkool/services/CustomerServiceTest.java index e89655e..5bede45 100644 --- a/account-service/src/test/java/com/drinkool/services/AuthenticationServiceTest.java +++ b/account-service/src/test/java/com/drinkool/services/CustomerServiceTest.java @@ -4,28 +4,23 @@ import static io.restassured.RestAssured.*; import static org.hamcrest.CoreMatchers.*; import static org.junit.jupiter.api.Assertions.*; -import com.drinkool.InternalValue; -import com.drinkool.Role; -import com.drinkool.Url; +import com.drinkool.*; import com.drinkool.dtos.*; import com.drinkool.entities.CustomerEntity; import io.quarkus.test.junit.QuarkusTest; import io.restassured.http.ContentType; -import java.util.Random; +import jakarta.inject.Inject; import org.junit.jupiter.api.Test; @QuarkusTest -public class AuthenticationServiceTest { +public class CustomerServiceTest { - public static Random random = new Random(); - - public static String generateRandomPhone() { - return "+8477" + String.format("%07d", random.nextInt(10000000)); - } + @Inject + OtpService otpService; @Test void testSignup() { - String phone = generateRandomPhone(); + String phone = Utils.generateRandomPhone(); Signup input = new Signup(); input.name = "Test User"; input.phone = phone; @@ -35,7 +30,7 @@ public class AuthenticationServiceTest { .contentType(ContentType.JSON) .body(input) .when() - .post(Url.Signup) + .post(Role.Customer + Url.Signup) .then() .statusCode(201); @@ -45,7 +40,7 @@ public class AuthenticationServiceTest { @Test void testQuickSignup() { - String phone = generateRandomPhone(); + String phone = Utils.generateRandomPhone(); QuickSignup input = new QuickSignup(); input.phone = phone; @@ -53,7 +48,7 @@ public class AuthenticationServiceTest { .contentType(ContentType.JSON) .body(input) .when() - .post(Url.QuickSignup) + .post(Role.Customer + Url.QuickSignup) .then() .header(InternalValue.userId, notNullValue()) .header(InternalValue.role, is(Role.Customer)) @@ -65,7 +60,7 @@ public class AuthenticationServiceTest { @Test void testLoginSuccess() { // BƯỚC 1: Tạo user trước bằng signup - String phone = generateRandomPhone(); + String phone = Utils.generateRandomPhone(); Signup signupData = new Signup(); signupData.name = "Login User"; signupData.phone = phone; @@ -74,7 +69,7 @@ public class AuthenticationServiceTest { given() .contentType(ContentType.JSON) .body(signupData) - .post(Url.Signup) + .post(Role.Customer + Url.Signup) .then() .statusCode(201); @@ -87,14 +82,14 @@ public class AuthenticationServiceTest { .contentType(ContentType.JSON) .body(loginInput) .when() - .post(Url.Login) + .post(Role.Customer + Url.Login) .then() .statusCode(202); } @Test void testLoginFailWrongPassword() { - String phone = generateRandomPhone(); + String phone = Utils.generateRandomPhone(); Signup signupData = new Signup(); signupData.name = "Wrong Pass User"; signupData.phone = phone; @@ -103,7 +98,7 @@ public class AuthenticationServiceTest { given() .contentType(ContentType.JSON) .body(signupData) - .post(Url.Signup) + .post(Role.Customer + Url.Signup) .then() .statusCode(201); @@ -115,41 +110,41 @@ public class AuthenticationServiceTest { .contentType(ContentType.JSON) .body(loginInput) .when() - .post(Url.Login) + .post(Role.Customer + Url.Login) .then() .statusCode(400); // BadRequestException } @Test - void testSmsOtp() { - String phone = generateRandomPhone(); - SmsOtp input = new SmsOtp(); + public void testQuickLogin_Success() { + String phone = Utils.generateRandomPhone(); + + QuickSignup input = new QuickSignup(); input.phone = phone; - Signup signup = new Signup(); - signup.phone = phone; - signup.name = "sms user"; - signup.password = "password123"; - - given() - .contentType(ContentType.JSON) - .body(signup) - .when() - .post(Url.Signup) - .then(); - given() .contentType(ContentType.JSON) .body(input) .when() - .post(Url.SmsOtp) + .post(Role.Customer + Url.QuickSignup) + .then(); + + QuickLogin payload = new QuickLogin(); + payload.phone = phone; + payload.otp = otpService.generateAndSaveOtp(phone); + + given() + .contentType(ContentType.JSON) + .body(payload) + .when() + .post(Role.Customer + Url.QuickLogin) .then() .statusCode(202); } @Test void testQuickLoginFailInvalidOtp() { - String phone = generateRandomPhone(); + String phone = Utils.generateRandomPhone(); QuickLogin input = new QuickLogin(); input.phone = phone; input.otp = "000000"; // Giả sử mã này luôn sai vì chưa được tạo @@ -158,7 +153,7 @@ public class AuthenticationServiceTest { .contentType(ContentType.JSON) .body(input) .when() - .post(Url.QuickLogin) + .post(Role.Customer + Url.QuickLogin) .then() .statusCode(401); } diff --git a/eatery-service/pom.xml b/eatery-service/pom.xml index b1239a8..fa6b425 100644 --- a/eatery-service/pom.xml +++ b/eatery-service/pom.xml @@ -17,6 +17,9 @@ quarkus + false + false + true 3.15.0 25 UTF-8 @@ -43,6 +46,11 @@ + + io.quarkus + quarkus-jacoco + test + com.drinkool lib @@ -66,10 +74,6 @@ io.quarkus quarkus-jackson - - io.quarkus - quarkus-messaging-kafka - io.quarkus quarkus-jdbc-postgresql @@ -86,6 +90,10 @@ io.quarkus quarkus-rest-jackson + + io.quarkus + quarkus-container-image-docker + io.quarkus quarkus-junit @@ -144,20 +152,4 @@ - - - - native - - - native - - - - false - false - true - - - diff --git a/eatery-service/src/main/resources/application.properties b/eatery-service/src/main/resources/application.properties index 88f3d6f..a60a673 100644 --- a/eatery-service/src/main/resources/application.properties +++ b/eatery-service/src/main/resources/application.properties @@ -1,6 +1,3 @@ -# Kafka -kafka.bootstrap.servers=localhost:9092 - # Postgress ## Cấu hình Database quarkus.datasource.db-kind=postgresql @@ -11,6 +8,19 @@ quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/eatery ## Tự động tạo bảng từ Entity (chỉ dùng cho môi trường dev) quarkus.hibernate-orm.database.generation=update +# Docker +quarkus.container-image.registry=git.demonkernel.io.vn +quarkus.container-image.group=foodsurf +quarkus.container-image.name=eatery-service +quarkus.container-image.push=true +quarkus.container-image.build=true +quarkus.container-image.builder=docker +quarkus.container-image.additional-tags=latest + # Dependency quarkus.index-dependency.lib.group-id=com.drinkool -quarkus.index-dependency.lib.artifact-id=lib \ No newline at end of file +quarkus.index-dependency.lib.artifact-id=lib + +# Build +quarkus.native.container-build=false +quarkus.native.additional-build-args=--future-defaults=all \ No newline at end of file diff --git a/gateway-service/pom.xml b/gateway-service/pom.xml index 50cda20..8830e15 100644 --- a/gateway-service/pom.xml +++ b/gateway-service/pom.xml @@ -46,6 +46,11 @@ + + io.quarkus + quarkus-jacoco + test + org.bitbucket.b_c jose4j diff --git a/gateway-service/src/main/java/com/drinkool/CustomerGatewayResource.java b/gateway-service/src/main/java/com/drinkool/GatewayResource.java similarity index 81% rename from gateway-service/src/main/java/com/drinkool/CustomerGatewayResource.java rename to gateway-service/src/main/java/com/drinkool/GatewayResource.java index 28ebcc0..2ce8b3d 100644 --- a/gateway-service/src/main/java/com/drinkool/CustomerGatewayResource.java +++ b/gateway-service/src/main/java/com/drinkool/GatewayResource.java @@ -8,8 +8,8 @@ import jakarta.ws.rs.*; import jakarta.ws.rs.core.Response; import org.eclipse.microprofile.rest.client.inject.RestClient; -@Path("/api/v1/customers") -public class CustomerGatewayResource { +@Path("/api/" + Role.Customer) +class CustomerGatewayResource { @Inject @RestClient @@ -26,4 +26,9 @@ public class CustomerGatewayResource { public Uni proxyLogin(Login input) { return accountService.login(input); } + + @GET + public Uni me() { + return accountService.me(); + } } diff --git a/gateway-service/src/main/java/com/drinkool/services/AccountService.java b/gateway-service/src/main/java/com/drinkool/services/AccountService.java index b58b552..c1210c4 100644 --- a/gateway-service/src/main/java/com/drinkool/services/AccountService.java +++ b/gateway-service/src/main/java/com/drinkool/services/AccountService.java @@ -1,5 +1,6 @@ package com.drinkool.services; +import com.drinkool.Role; import com.drinkool.Url; import com.drinkool.dtos.*; import io.smallrye.mutiny.Uni; @@ -8,7 +9,7 @@ import jakarta.ws.rs.core.Response; import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; @RegisterRestClient(configKey = "account") -@Path("") +@Path(Role.Customer) public interface AccountService { @POST @Path(Url.Signup) @@ -29,4 +30,7 @@ public interface AccountService { @POST @Path(Url.SmsOtp) Uni smsOtp(SmsOtp input); + + @GET + Uni me(); } diff --git a/gateway-service/src/main/resources/application.properties b/gateway-service/src/main/resources/application.properties index dffba85..2046ccb 100644 --- a/gateway-service/src/main/resources/application.properties +++ b/gateway-service/src/main/resources/application.properties @@ -8,4 +8,5 @@ quarkus.container-image.builder=docker quarkus.container-image.additional-tags=latest # Build -quarkus.native.container-build=false \ No newline at end of file +quarkus.native.container-build=false +quarkus.native.additional-build-args=--future-defaults=all \ No newline at end of file diff --git a/k8s.yaml b/k8s.yaml index 4b2fde8..8d7ace5 100644 --- a/k8s.yaml +++ b/k8s.yaml @@ -38,12 +38,12 @@ spec: name: postgres-credentials key: url resources: - limits: - cpu: "500m" - memory: "512Mi" requests: - cpu: "100m" - memory: "256Mi" + memory: "32Mi" + cpu: "50m" + limits: + memory: "64Mi" + cpu: "250m" --- apiVersion: v1 kind: Service @@ -56,7 +56,63 @@ spec: - port: 80 targetPort: 8080 --- -# 2. GATEWAY SERVICE +# 2. EATERY SERVICE +apiVersion: apps/v1 +kind: Deployment +metadata: + name: eatery-deploy +spec: + replicas: 1 + selector: + matchLabels: + app: eatery + template: + metadata: + labels: + app: eatery + spec: + containers: + - name: eatery-pod + image: git.demonkernel.io.vn/foodsurf/eatery-service:1.4.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8080 + env: + - name: QUARKUS_DATASOURCE_PASSWORD + valueFrom: + secretKeyRef: + name: postgres-credentials + key: password + - name: QUARKUS_DATASOURCE_USERNAME + valueFrom: + secretKeyRef: + name: postgres-credentials + key: username + - name: QUARKUS_DATASOURCE_JDBC_URL + valueFrom: + secretKeyRef: + name: postgres-credentials + key: url + resources: + requests: + memory: "32Mi" + cpu: "50m" + limits: + memory: "64Mi" + cpu: "250m" +--- +apiVersion: v1 +kind: Service +metadata: + name: eatery-service +spec: + selector: + app: eatery + ports: + - port: 80 + targetPort: 8080 +--- +# 3. GATEWAY SERVICE apiVersion: apps/v1 kind: Deployment metadata: @@ -86,12 +142,12 @@ spec: name: jwt-secret key: secret resources: - limits: - cpu: "500m" - memory: "512Mi" requests: - cpu: "100m" - memory: "256Mi" + memory: "32Mi" + cpu: "50m" + limits: + memory: "64Mi" + cpu: "250m" --- apiVersion: v1 kind: Service @@ -106,7 +162,7 @@ spec: targetPort: 8080 nodePort: 32080 --- -# 3. REDIS +# 4. REDIS apiVersion: apps/v1 kind: Deployment metadata: diff --git a/lib/src/main/java/com/drinkool/Role.java b/lib/src/main/java/com/drinkool/Role.java index 4155aa3..ee2e5e6 100644 --- a/lib/src/main/java/com/drinkool/Role.java +++ b/lib/src/main/java/com/drinkool/Role.java @@ -3,4 +3,5 @@ package com.drinkool; public class Role { public static final String Customer = "customer"; + public static final String Manager = "manager"; } diff --git a/lib/src/main/java/com/drinkool/dtos/ManagerSignup.java b/lib/src/main/java/com/drinkool/dtos/ManagerSignup.java new file mode 100644 index 0000000..7cf55ad --- /dev/null +++ b/lib/src/main/java/com/drinkool/dtos/ManagerSignup.java @@ -0,0 +1,5 @@ +package com.drinkool.dtos; + +public class ManagerSignup extends Signup { + public String eateryName; +} diff --git a/pom.xml b/pom.xml index 7dbca5e..6e56f62 100644 --- a/pom.xml +++ b/pom.xml @@ -1,8 +1,8 @@ - + 4.0.0 com.drinkool @@ -30,6 +30,26 @@ pom import + + io.quarkus + quarkus-jacoco + test + ${quarkus.platform.version} + - + + + + maven-surefire-plugin + + + ${maven.multiModuleProjectDirectory}/target/jacoco.exec + true + ${maven.multiModuleProjectDirectory}/target/coverage + + + + + + \ No newline at end of file