diff --git a/.vscode/settings.json b/.vscode/settings.json
index 1aa396c..3e30470 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -7,7 +7,8 @@
"**/Thumbs.db": true,
"**/target": true,
"**/docker": true,
- "node_modules": true
+ "node_modules": true,
+ "**/.mvn": true
},
"explorerExclude.backup": {},
"java.compile.nullAnalysis.mode": "automatic",
diff --git a/account-service/pom.xml b/account-service/pom.xml
index 3d8bd51..b941572 100644
--- a/account-service/pom.xml
+++ b/account-service/pom.xml
@@ -54,6 +54,12 @@
jose4j
0.9.3
+
+ net.datafaker
+ datafaker
+ 2.0.2
+ test
+
io.quarkus
quarkus-messaging-kafka
diff --git a/account-service/src/main/java/com/drinkool/entities/ManagerEntity.java b/account-service/src/main/java/com/drinkool/entities/ManagerEntity.java
index 6d4691d..8b08ce8 100644
--- a/account-service/src/main/java/com/drinkool/entities/ManagerEntity.java
+++ b/account-service/src/main/java/com/drinkool/entities/ManagerEntity.java
@@ -3,11 +3,20 @@ package com.drinkool.entities;
import com.drinkool.Role;
import com.drinkool.models.UserModel;
import jakarta.persistence.*;
+import java.util.ArrayList;
+import java.util.List;
@Entity
@Table(name = Role.Manager)
public class ManagerEntity extends UserModel {
+ @OneToMany(
+ mappedBy = "serve",
+ cascade = CascadeType.ALL,
+ orphanRemoval = true
+ )
+ public List staffs = new ArrayList<>();
+
public ManagerEntity() {
super(Role.Manager);
}
diff --git a/account-service/src/main/java/com/drinkool/entities/StaffEntity.java b/account-service/src/main/java/com/drinkool/entities/StaffEntity.java
new file mode 100644
index 0000000..7ba98b8
--- /dev/null
+++ b/account-service/src/main/java/com/drinkool/entities/StaffEntity.java
@@ -0,0 +1,30 @@
+package com.drinkool.entities;
+
+import com.drinkool.Role;
+import com.drinkool.models.UserModel;
+import jakarta.persistence.Entity;
+import jakarta.persistence.FetchType;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.Table;
+import jakarta.transaction.Transactional;
+
+@Entity
+@Table(name = Role.Staff)
+public class StaffEntity extends UserModel {
+
+ @Transactional
+ public void signup(
+ String name,
+ String phone,
+ String rawPassword,
+ ManagerEntity serve
+ ) {
+ this.serve = serve;
+ super.signup(name, phone, rawPassword);
+ }
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "managerId")
+ public ManagerEntity serve;
+}
diff --git a/account-service/src/main/java/com/drinkool/filters/HeaderRolesFilter.java b/account-service/src/main/java/com/drinkool/filters/HeaderRolesFilter.java
new file mode 100644
index 0000000..618b711
--- /dev/null
+++ b/account-service/src/main/java/com/drinkool/filters/HeaderRolesFilter.java
@@ -0,0 +1,7 @@
+package com.drinkool.filters;
+
+import com.drinkool.lib.utils.BaseHeaderAuthentication;
+import jakarta.enterprise.context.ApplicationScoped;
+
+@ApplicationScoped
+public class HeaderRolesFilter extends BaseHeaderAuthentication {}
diff --git a/account-service/src/main/java/com/drinkool/services/AccountService.java b/account-service/src/main/java/com/drinkool/services/AccountService.java
index caf12fd..b5843a1 100644
--- a/account-service/src/main/java/com/drinkool/services/AccountService.java
+++ b/account-service/src/main/java/com/drinkool/services/AccountService.java
@@ -3,6 +3,7 @@ package com.drinkool.services;
import com.drinkool.Role;
import com.drinkool.Url;
import com.drinkool.entities.ManagerEntity;
+import com.drinkool.entities.StaffEntity;
import com.drinkool.lib.dtos.SmsOtp;
import com.drinkool.models.UserModel;
import jakarta.inject.Inject;
@@ -28,6 +29,10 @@ public class AccountService {
ManagerEntity.find("phone", input.phone).firstResult() != null
) return Response.accepted().entity(Role.Manager).build();
+ if (
+ StaffEntity.find("phone", input.phone).firstResult() != null
+ ) return Response.accepted().entity(Role.Staff).build();
+
String otp = otpService.generateAndSaveOtp(input.phone);
System.out.println("OTP cho " + input.phone + " là: " + otp);
diff --git a/account-service/src/main/java/com/drinkool/services/ManagerService.java b/account-service/src/main/java/com/drinkool/services/ManagerService.java
index 5e76b17..b9ef5f9 100644
--- a/account-service/src/main/java/com/drinkool/services/ManagerService.java
+++ b/account-service/src/main/java/com/drinkool/services/ManagerService.java
@@ -44,25 +44,25 @@ public class ManagerService extends BaseService {
@POST
@Path(Url.Login)
public Response login(Login input) {
- ManagerEntity customer = ManagerEntity.find(
+ ManagerEntity manager = ManagerEntity.find(
"phone",
input.phone
).firstResult();
- if (customer == null) return Response.status(Response.Status.BAD_REQUEST)
+ if (manager == null) return Response.status(Response.Status.BAD_REQUEST)
.entity("InvalidPhoneNumber")
.build();
- if (!customer.login(input.password)) return Response.status(
+ if (!manager.login(input.password)) return Response.status(
Response.Status.BAD_REQUEST
)
.entity("InvalidPassword")
.build();
return Response.accepted()
- .header(InternalValue.userId, customer.id.toString())
+ .header(InternalValue.userId, manager.id.toString())
.header(InternalValue.role, Role.Manager)
- .entity(customer)
+ .entity(manager)
.build();
}
}
diff --git a/account-service/src/main/java/com/drinkool/services/StaffService.java b/account-service/src/main/java/com/drinkool/services/StaffService.java
new file mode 100644
index 0000000..1a6c27c
--- /dev/null
+++ b/account-service/src/main/java/com/drinkool/services/StaffService.java
@@ -0,0 +1,71 @@
+package com.drinkool.services;
+
+import com.drinkool.InternalValue;
+import com.drinkool.Role;
+import com.drinkool.Url;
+import com.drinkool.entities.ManagerEntity;
+import com.drinkool.entities.StaffEntity;
+import com.drinkool.lib.dtos.Login;
+import com.drinkool.lib.dtos.Signup;
+import io.vertx.core.http.HttpServerRequest;
+import jakarta.annotation.security.RolesAllowed;
+import jakarta.inject.Inject;
+import jakarta.transaction.Transactional;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.core.Response;
+import java.util.UUID;
+
+@Path(Role.Staff)
+public class StaffService extends BaseService {
+
+ @Inject
+ HttpServerRequest request;
+
+ public StaffService() {
+ super(StaffEntity.class);
+ }
+
+ @POST
+ @Path(Url.Signup)
+ @RolesAllowed(Role.Manager)
+ @Transactional
+ public Response signup(Signup input) {
+ UUID managerId = UUID.fromString(request.getHeader(InternalValue.userId));
+ ManagerEntity manager = ManagerEntity.findById(managerId);
+
+ if (manager == null) return Response.status(Response.Status.BAD_REQUEST)
+ .entity("InvalidManager")
+ .build();
+
+ StaffEntity staff = new StaffEntity();
+ staff.signup(input.name, input.phone, input.password, manager);
+
+ return Response.status(Response.Status.CREATED)
+ .header(InternalValue.userId, staff.id.toString())
+ .header(InternalValue.role, Role.Staff)
+ .build();
+ }
+
+ @POST
+ @Path(Url.Login)
+ public Response login(Login input) {
+ StaffEntity staff = StaffEntity.find("phone", input.phone).firstResult();
+
+ if (staff == null) return Response.status(Response.Status.BAD_REQUEST)
+ .entity("InvalidPhoneNumber")
+ .build();
+
+ if (!staff.login(input.password)) return Response.status(
+ Response.Status.BAD_REQUEST
+ )
+ .entity("InvalidPassword")
+ .build();
+
+ return Response.accepted()
+ .header(InternalValue.userId, staff.id.toString())
+ .header(InternalValue.role, Role.Staff)
+ .entity(staff)
+ .build();
+ }
+}
diff --git a/account-service/src/test/java/com/drinkool/services/StaffServiceTest.java b/account-service/src/test/java/com/drinkool/services/StaffServiceTest.java
new file mode 100644
index 0000000..5cce294
--- /dev/null
+++ b/account-service/src/test/java/com/drinkool/services/StaffServiceTest.java
@@ -0,0 +1,120 @@
+package com.drinkool.services;
+
+import static io.restassured.RestAssured.*;
+import static org.junit.jupiter.api.Assertions.*;
+
+import com.drinkool.*;
+import com.drinkool.entities.StaffEntity;
+import com.drinkool.lib.dtos.*;
+import io.quarkus.test.common.QuarkusTestResource;
+import io.quarkus.test.junit.QuarkusTest;
+import io.quarkus.test.kafka.*;
+import io.restassured.http.ContentType;
+import io.smallrye.reactive.messaging.kafka.companion.ConsumerTask;
+import io.smallrye.reactive.messaging.kafka.companion.KafkaCompanion;
+import jakarta.ws.rs.core.Response;
+import java.time.Duration;
+import net.datafaker.Faker;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+@QuarkusTest
+@QuarkusTestResource(KafkaCompanionResource.class)
+public class StaffServiceTest {
+
+ private final Faker faker = new Faker();
+
+ private String managerId;
+
+ @BeforeEach
+ void setup() {
+ ManagerSignup input = new ManagerSignup();
+ input.name = "Ho Van Quan";
+ input.phone = Utils.generateRandomPhone();
+ input.password = "strong_password";
+ input.eateryName = "Quan Com Ngon";
+
+ var response = given()
+ .contentType("application/json")
+ .body(input)
+ .when()
+ .post(Role.Manager + Url.Signup)
+ .then()
+ .statusCode(201)
+ .header(InternalValue.userId, org.hamcrest.Matchers.notNullValue())
+ .header(InternalValue.role, Role.Manager)
+ .extract();
+
+ managerId = response.header(InternalValue.userId);
+ }
+
+ @Test
+ void signup_Success() {
+ String staffName = faker.name().fullName();
+ String staffPhone = Utils.generateRandomPhone();
+
+ Signup signup = new Signup(
+ staffName,
+ staffPhone,
+ faker.famousLastWords().lastWords()
+ );
+
+ given()
+ .contentType(ContentType.JSON)
+ .header(InternalValue.role, Role.Manager)
+ .header(InternalValue.userId, managerId)
+ .body(signup)
+ .when()
+ .post(Role.Staff + Url.Signup)
+ .then()
+ .statusCode(Response.Status.CREATED.getStatusCode())
+ .header(InternalValue.userId, org.hamcrest.Matchers.notNullValue())
+ .header(InternalValue.role, Role.Staff);
+
+ StaffEntity staff = StaffEntity.find("phone", staffPhone).firstResult();
+
+ assertEquals(managerId, staff.serve.id.toString());
+ }
+
+ @Test
+ void signup_FailedDueToInvalidRole() {
+ given()
+ .contentType(ContentType.JSON)
+ .header(InternalValue.role, Role.Customer)
+ .header(InternalValue.userId, managerId)
+ .body("")
+ .when()
+ .post(Role.Staff + Url.Signup)
+ .then()
+ .statusCode(Response.Status.FORBIDDEN.getStatusCode());
+ }
+
+ @Test
+ void testLoginSuccess() {
+ String staffName = faker.name().fullName();
+ String staffPhone = Utils.generateRandomPhone();
+ String password = faker.famousLastWords().lastWords();
+
+ Signup signup = new Signup(staffName, staffPhone, password);
+
+ given()
+ .contentType(ContentType.JSON)
+ .header(InternalValue.role, Role.Manager)
+ .header(InternalValue.userId, managerId)
+ .body(signup)
+ .when()
+ .post(Role.Staff + Url.Signup)
+ .then();
+
+ Login loginInput = new Login(staffPhone, password);
+
+ given()
+ .contentType(ContentType.JSON)
+ .body(loginInput)
+ .when()
+ .post(Role.Staff + Url.Login)
+ .then()
+ .statusCode(Response.Status.ACCEPTED.getStatusCode());
+ }
+}
diff --git a/cart-service/pom.xml b/cart-service/pom.xml
index 9d6d072..8c4f4c4 100644
--- a/cart-service/pom.xml
+++ b/cart-service/pom.xml
@@ -181,6 +181,7 @@
+ false
false
true
diff --git a/gateway-service/src/main/java/com/drinkool/controller/EateryController.java b/gateway-service/src/main/java/com/drinkool/controller/EateryController.java
index 4b67108..53e718b 100644
--- a/gateway-service/src/main/java/com/drinkool/controller/EateryController.java
+++ b/gateway-service/src/main/java/com/drinkool/controller/EateryController.java
@@ -1,5 +1,6 @@
package com.drinkool.controller;
+import com.drinkool.InternalValue;
import com.drinkool.Url;
import com.drinkool.enums.SortBy;
import com.drinkool.lib.dtos.GraphqlDto;
@@ -9,6 +10,7 @@ import io.smallrye.mutiny.Uni;
import jakarta.inject.Inject;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
+import jakarta.ws.rs.HeaderParam;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
@@ -43,8 +45,12 @@ public class EateryController extends GraphqlBase {
@POST
@Path(Url.Review)
- public Uni receiveReview(SendReview input) {
- return reviewService.receiveReview(input);
+ public Uni receiveReview(
+ SendReview input,
+ @HeaderParam(InternalValue.userId) UUID userId,
+ @HeaderParam(InternalValue.role) String role
+ ) {
+ return reviewService.receiveReview(input, userId, role);
}
@POST
diff --git a/gateway-service/src/main/java/com/drinkool/services/ReviewService.java b/gateway-service/src/main/java/com/drinkool/services/ReviewService.java
index 47d4a61..8cee0e2 100644
--- a/gateway-service/src/main/java/com/drinkool/services/ReviewService.java
+++ b/gateway-service/src/main/java/com/drinkool/services/ReviewService.java
@@ -1,11 +1,13 @@
package com.drinkool.services;
+import com.drinkool.InternalValue;
import com.drinkool.Url;
import com.drinkool.enums.SortBy;
import com.drinkool.lib.dtos.SendReview;
import io.smallrye.mutiny.Uni;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
+import jakarta.ws.rs.HeaderParam;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
@@ -25,5 +27,9 @@ public interface ReviewService {
);
@POST
- public Uni receiveReview(SendReview input);
+ public Uni receiveReview(
+ SendReview input,
+ @HeaderParam(InternalValue.userId) UUID userId,
+ @HeaderParam(InternalValue.role) String role
+ );
}
diff --git a/lib/src/main/java/com/drinkool/Role.java b/lib/src/main/java/com/drinkool/Role.java
index ee2e5e6..4cdeac9 100644
--- a/lib/src/main/java/com/drinkool/Role.java
+++ b/lib/src/main/java/com/drinkool/Role.java
@@ -4,4 +4,5 @@ public class Role {
public static final String Customer = "customer";
public static final String Manager = "manager";
+ public static final String Staff = "Staff";
}
diff --git a/lib/src/main/java/com/drinkool/lib/dtos/Login.java b/lib/src/main/java/com/drinkool/lib/dtos/Login.java
index e87f3d8..9719e11 100644
--- a/lib/src/main/java/com/drinkool/lib/dtos/Login.java
+++ b/lib/src/main/java/com/drinkool/lib/dtos/Login.java
@@ -1,5 +1,10 @@
package com.drinkool.lib.dtos;
+import lombok.AllArgsConstructor;
+import lombok.NoArgsConstructor;
+
+@AllArgsConstructor
+@NoArgsConstructor
public class Login {
public String phone;
diff --git a/lib/src/main/java/com/drinkool/lib/dtos/Signup.java b/lib/src/main/java/com/drinkool/lib/dtos/Signup.java
index 0db754a..3d2af07 100644
--- a/lib/src/main/java/com/drinkool/lib/dtos/Signup.java
+++ b/lib/src/main/java/com/drinkool/lib/dtos/Signup.java
@@ -1,5 +1,10 @@
package com.drinkool.lib.dtos;
+import lombok.AllArgsConstructor;
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor
+@AllArgsConstructor
public class Signup {
public String name;