diff --git a/.gitea/workflows/test.yaml b/.gitea/workflows/test.yaml index c2644e2..f1b7150 100644 --- a/.gitea/workflows/test.yaml +++ b/.gitea/workflows/test.yaml @@ -15,18 +15,40 @@ permissions: checks: write jobs: - build-and-test: + build: runs-on: ubuntu-latest - steps: - uses: actions/checkout@v6 - with: - fetch-depth: 0 - - name: Install dependencies with Proxy - env: - http_proxy: "http://host.docker.internal:3142" - https_proxy: "http://host.docker.internal:3142" + - name: Install JDK and Maven + run: | + # Kiểm tra proxy có hoạt động không + echo "Acquire::http::Proxy \"$http_proxy\";" > /etc/apt/apt.conf.d/80proxy + apt-get update + apt-get install -y --no-install-recommends --no-install-suggests \ + openjdk-25-jdk-headless docker-cli docker-buildx zstd maven + + - name: Cache Maven packages + uses: actions/cache@v4 + with: + path: | + ~/.m2/repository + **/target/native-image-cache + **/target/reports + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: ${{ runner.os }}-maven- + + - name: Build native with Maven + run: | + mvn -B clean install -DskipTests -Pnative \ + -Dquarkus.container-image.push=false + + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - name: Install JDK and Maven run: | # Kiểm tra proxy có hoạt động không echo "Acquire::http::Proxy \"$http_proxy\";" > /etc/apt/apt.conf.d/80proxy @@ -46,16 +68,13 @@ jobs: **/target/native-image-cache **/target/reports key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven- + restore-keys: ${{ runner.os }}-maven- - - name: Build and Test all module + - name: Run Tests env: TESTCONTAINERS_RYUK_DISABLED: true run: | - mvn -B clean install -Pnative \ - -Dquarkus.container-image.push=false \ - -Dquarkus.container-image.registry=git.demonkernel.io.vn + mvn clean test -Dquarkus.main.run-tests=true - name: Publish Test Report uses: dorny/test-reporter@v3 diff --git a/account-service/src/main/java/com/drinkool/services/StaffService.java b/account-service/src/main/java/com/drinkool/services/StaffService.java index 1a6c27c..e948890 100644 --- a/account-service/src/main/java/com/drinkool/services/StaffService.java +++ b/account-service/src/main/java/com/drinkool/services/StaffService.java @@ -43,6 +43,7 @@ public class StaffService extends BaseService { return Response.status(Response.Status.CREATED) .header(InternalValue.userId, staff.id.toString()) + .header(InternalValue.managerId, manager.id.toString()) .header(InternalValue.role, Role.Staff) .build(); } @@ -64,6 +65,7 @@ public class StaffService extends BaseService { return Response.accepted() .header(InternalValue.userId, staff.id.toString()) + .header(InternalValue.managerId, staff.serve.id.toString()) .header(InternalValue.role, Role.Staff) .entity(staff) .build(); diff --git a/eatery-service/src/main/java/com/drinkool/dtos/CreateShift.java b/eatery-service/src/main/java/com/drinkool/dtos/CreateShift.java index f2c3b43..222287a 100644 --- a/eatery-service/src/main/java/com/drinkool/dtos/CreateShift.java +++ b/eatery-service/src/main/java/com/drinkool/dtos/CreateShift.java @@ -3,6 +3,9 @@ package com.drinkool.dtos; import java.time.LocalTime; import org.eclipse.microprofile.graphql.NonNull; +import lombok.NoArgsConstructor; + +@NoArgsConstructor public class CreateShift { @NonNull diff --git a/eatery-service/src/main/java/com/drinkool/entities/EateryEntity.java b/eatery-service/src/main/java/com/drinkool/entities/EateryEntity.java index f60ff5f..f9a04d1 100644 --- a/eatery-service/src/main/java/com/drinkool/entities/EateryEntity.java +++ b/eatery-service/src/main/java/com/drinkool/entities/EateryEntity.java @@ -27,6 +27,13 @@ public class EateryEntity extends BaseEntity { ) public List menuItems = new ArrayList<>(); + @OneToMany( + mappedBy = "eatery", + cascade = CascadeType.ALL, + orphanRemoval = true + ) + public List shifts = new ArrayList<>(); + public EateryEntity() {} @Transactional diff --git a/eatery-service/src/main/java/com/drinkool/entities/ShiftEntity.java b/eatery-service/src/main/java/com/drinkool/entities/ShiftEntity.java index c04f39c..5738ced 100644 --- a/eatery-service/src/main/java/com/drinkool/entities/ShiftEntity.java +++ b/eatery-service/src/main/java/com/drinkool/entities/ShiftEntity.java @@ -3,13 +3,21 @@ package com.drinkool.entities; import com.drinkool.lib.entities.BaseEntity; import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; import java.time.LocalTime; +import java.util.UUID; @Entity @Table public class ShiftEntity extends BaseEntity { + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "eatery_id") + public EateryEntity eatery; + @Column(nullable = false) public String name; diff --git a/eatery-service/src/main/java/com/drinkool/services/ShiftService.java b/eatery-service/src/main/java/com/drinkool/services/ShiftService.java index 6cf1267..1d8cf4c 100644 --- a/eatery-service/src/main/java/com/drinkool/services/ShiftService.java +++ b/eatery-service/src/main/java/com/drinkool/services/ShiftService.java @@ -4,9 +4,9 @@ import com.drinkool.InternalValue; import com.drinkool.Role; import com.drinkool.dtos.CreateShift; import com.drinkool.dtos.RegisterShift; +import com.drinkool.entities.EateryEntity; import com.drinkool.entities.ShiftEntity; import com.drinkool.entities.ShiftRegistrationEntity; - import io.vertx.core.http.HttpServerRequest; import jakarta.annotation.security.RolesAllowed; import jakarta.enterprise.context.ApplicationScoped; @@ -58,9 +58,17 @@ public class ShiftService { @Name("registration") RegisterShift registration ) throws GraphQLException { String userIdStr = request.getHeader(InternalValue.userId); + String managerIdStr = request.getHeader(InternalValue.managerId); UUID staffId = UUID.fromString(userIdStr); - ShiftEntity shift = ShiftEntity.findById(registration.shiftId); + EateryEntity eatery = EateryEntity.findByOwnerId(managerIdStr); + if (eatery == null) throw new GraphQLException("NotFoundEatery"); + + ShiftEntity shift = ShiftEntity.find( + "id = ?1 and eatery.id = ?2", + registration.shiftId, + eatery.id + ).firstResult(); if (shift == null) throw new GraphQLException("NotFoundShift"); List overlappingShifts = @@ -94,8 +102,13 @@ public class ShiftService { @Transactional public ShiftEntity createShift(@Name("shiftInput") CreateShift input) throws GraphQLException { + String ownerId = request.getHeader(InternalValue.userId); + + EateryEntity eatery = EateryEntity.findByOwnerId(ownerId); + if (eatery == null) return null; ShiftEntity shift = new ShiftEntity(); + shift.eatery = eatery; shift.name = input.name; shift.startTime = input.startTime; shift.endTime = input.endTime; @@ -120,6 +133,11 @@ public class ShiftService { ShiftEntity shift = ShiftEntity.findById(id); if (shift == null) throw new GraphQLException("NotFoundShift"); + String ownerId = request.getHeader(InternalValue.userId); + if ( + !shift.eatery.ownerId.toString().equals(ownerId) + ) throw new GraphQLException("InvalidShiftId"); + shift.name = input.name; shift.startTime = input.startTime; shift.endTime = input.endTime; @@ -137,6 +155,22 @@ public class ShiftService { @RolesAllowed(Role.Manager) @Transactional public boolean deleteShift(@Name("id") Long id) throws GraphQLException { + String ownerId = request.getHeader(InternalValue.userId); + + EateryEntity eatery = EateryEntity.findByOwnerId(ownerId); + if (eatery == null) { + throw new GraphQLException("NotFoundEatery"); + } + + ShiftEntity shift = ShiftEntity.find( + "id = ?1 and eatery = ?2", + id, + eatery + ).firstResult(); + if (shift == null) { + throw new GraphQLException("NotFoundShiftOrAccessDenied"); + } + long count = ShiftRegistrationEntity.count("shift.id", id); if (count > 0) throw new GraphQLException( "CannotDeleteShiftWithRegistrations" diff --git a/eatery-service/src/test/java/com/drinkool/services/ShiftServiceTest.java b/eatery-service/src/test/java/com/drinkool/services/ShiftServiceTest.java index 83edd6a..a3d0cf8 100644 --- a/eatery-service/src/test/java/com/drinkool/services/ShiftServiceTest.java +++ b/eatery-service/src/test/java/com/drinkool/services/ShiftServiceTest.java @@ -4,11 +4,15 @@ import static io.restassured.RestAssured.given; import static org.hamcrest.Matchers.*; import com.drinkool.InternalValue; +import com.drinkool.Role; +import com.drinkool.entities.EateryEntity; import com.drinkool.entities.ShiftEntity; import com.drinkool.entities.ShiftRegistrationEntity; import io.quarkus.test.junit.QuarkusTest; import jakarta.transaction.Transactional; import java.time.LocalTime; +import java.util.HashMap; +import java.util.Map; import java.util.UUID; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -44,16 +48,28 @@ public class ShiftServiceTest { @Test void testCreateShift_AsManager() { - String mutation = - "mutation { createShift(shiftInput: { " + - "name: \"Ca Chiều\", " + - "startTime: \"13:00:00\", " + - "endTime: \"17:00:00\", " + - "maxStaff: 3 }) { id name } }"; + String query = """ + mutation Create($input: CreateShiftInput!) + { createShift(shiftInput: $input) { id name } }"""; + + Map input = new HashMap<>(); + input.put("name", "Ca Sáng"); + input.put("startTime", "08:00:00"); + input.put("endTime", "12:00:00"); + input.put("maxStaff", 5); + + Map body = new HashMap<>(); + body.put("query", query); + body.put("variables", Map.of("input", input)); + + UUID ownerId = createMockOwner(); + createMockEatery(ownerId); given() .contentType("application/json") - .body("{ \"query\": \"" + mutation + "\" }") + .header(InternalValue.role, Role.Manager) + .header(InternalValue.userId, ownerId) + .body(body) .when() .post("/graphql") .then() @@ -136,7 +152,6 @@ public class ShiftServiceTest { @Transactional ShiftEntity createMockShift(String name, String start, String end) { ShiftEntity shift = new ShiftEntity(); - shift.id = UUID.randomUUID(); shift.name = name; shift.startTime = LocalTime.parse(start); shift.endTime = LocalTime.parse(end); @@ -148,9 +163,24 @@ public class ShiftServiceTest { @Transactional void registerStaffToShift(UUID staffId, ShiftEntity shift) { ShiftRegistrationEntity reg = new ShiftRegistrationEntity(); - reg.id = UUID.randomUUID(); reg.staffId = staffId; reg.shift = shift; reg.persist(); } + + @Transactional + public UUID createMockOwner() { + return UUID.randomUUID(); + } + + @Transactional + public EateryEntity createMockEatery(UUID ownerId) { + EateryEntity eatery = new EateryEntity(); + eatery.name = "Nhà hàng " + ownerId.toString().substring(0, 5); + eatery.ownerId = ownerId; + eatery.persist(); + + EateryEntity.getEntityManager().flush(); + return eatery; + } } diff --git a/lib/src/main/java/com/drinkool/InternalValue.java b/lib/src/main/java/com/drinkool/InternalValue.java index f0865a4..685289d 100644 --- a/lib/src/main/java/com/drinkool/InternalValue.java +++ b/lib/src/main/java/com/drinkool/InternalValue.java @@ -6,4 +6,5 @@ public class InternalValue { public static final String headerId = "X-Internal-"; public static final String userId = headerId + "UserId"; public static final String role = headerId + "Role"; + public static final String managerId = headerId + "ManagerId"; }