diff --git a/lib/src/main/java/com/drinkool/lib/dtos/CreateShift.java b/eatery-service/src/main/java/com/drinkool/dtos/CreateShift.java similarity index 59% rename from lib/src/main/java/com/drinkool/lib/dtos/CreateShift.java rename to eatery-service/src/main/java/com/drinkool/dtos/CreateShift.java index 1568451..f2c3b43 100644 --- a/lib/src/main/java/com/drinkool/lib/dtos/CreateShift.java +++ b/eatery-service/src/main/java/com/drinkool/dtos/CreateShift.java @@ -1,11 +1,18 @@ -package com.drinkool.lib.dtos; +package com.drinkool.dtos; import java.time.LocalTime; +import org.eclipse.microprofile.graphql.NonNull; public class CreateShift { + @NonNull public String name; + + @NonNull public LocalTime startTime; + + @NonNull public LocalTime endTime; + public Integer maxStaff; } diff --git a/eatery-service/src/main/java/com/drinkool/dtos/RegisterShift.java b/eatery-service/src/main/java/com/drinkool/dtos/RegisterShift.java new file mode 100644 index 0000000..5c4776a --- /dev/null +++ b/eatery-service/src/main/java/com/drinkool/dtos/RegisterShift.java @@ -0,0 +1,10 @@ +package com.drinkool.dtos; + +import java.util.UUID; +import org.eclipse.microprofile.graphql.NonNull; + +public class RegisterShift { + + @NonNull + public UUID shiftId; +} 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 7c2f2d7..6cf1267 100644 --- a/eatery-service/src/main/java/com/drinkool/services/ShiftService.java +++ b/eatery-service/src/main/java/com/drinkool/services/ShiftService.java @@ -2,64 +2,82 @@ package com.drinkool.services; import com.drinkool.InternalValue; import com.drinkool.Role; -import com.drinkool.Url; +import com.drinkool.dtos.CreateShift; +import com.drinkool.dtos.RegisterShift; import com.drinkool.entities.ShiftEntity; import com.drinkool.entities.ShiftRegistrationEntity; -import com.drinkool.lib.dtos.CreateShift; -import com.drinkool.lib.dtos.RegisterShift; + import io.vertx.core.http.HttpServerRequest; import jakarta.annotation.security.RolesAllowed; +import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.transaction.Transactional; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.POST; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.core.Response; import java.util.List; import java.util.UUID; import java.util.stream.Collectors; +import org.eclipse.microprofile.graphql.*; -@Path(Url.Shift) +@GraphQLApi +@ApplicationScoped public class ShiftService { @Inject HttpServerRequest request; - @POST - @Path("/me") + // --- QUERIES --- + + @Query("allShifts") + @Description("Lấy danh sách tất cả các loại ca trực") + @RolesAllowed({ Role.Staff, Role.Manager }) + public List getAllShifts() { + return ShiftEntity.listAll(); + } + + @Query("myRegistrations") + @Description("Lấy danh sách ca trực mà nhân viên hiện tại đã đăng ký") + @RolesAllowed(Role.Staff) + public List getMyShifts() { + String userId = request.getHeader(InternalValue.userId); + return ShiftRegistrationEntity.list("staffId", UUID.fromString(userId)); + } + + @Query("allRegistrations") + @Description("Manager xem toàn bộ danh sách đăng ký của tất cả nhân viên") + @RolesAllowed(Role.Manager) + public List getAllRegistrations() { + return ShiftRegistrationEntity.listAll(); + } + + // --- MUTATIONS --- + + @Mutation("registerShift") + @Description("Nhân viên đăng ký vào một ca trực cụ thể") @RolesAllowed(Role.Staff) @Transactional - public Response registerShift(RegisterShift registration) { + public ShiftRegistrationEntity registerShift( + @Name("registration") RegisterShift registration + ) throws GraphQLException { String userIdStr = request.getHeader(InternalValue.userId); - UUID staffId = UUID.fromString(userIdStr); ShiftEntity shift = ShiftEntity.findById(registration.shiftId); - if (shift == null) { - return Response.status(Response.Status.NOT_FOUND) - .entity("NotFoundShift") - .build(); - } + if (shift == null) throw new GraphQLException("NotFoundShift"); List overlappingShifts = ShiftRegistrationEntity.findOverlappingShifts(staffId, shift); + if (!overlappingShifts.isEmpty()) { - String overlappingNames = overlappingShifts + String ids = overlappingShifts .stream() .map(reg -> reg.shift.id.toString()) .distinct() .collect(Collectors.joining(", ")); - - return Response.status(Response.Status.CONFLICT) - .entity(overlappingNames) - .build(); + throw new GraphQLException("OverlappingShift: " + ids); } long currentStaffCount = ShiftRegistrationEntity.countByShift(shift.id); if (shift.maxStaff != null && currentStaffCount >= shift.maxStaff) { - return Response.status(Response.Status.BAD_REQUEST) - .entity("FulledShift") - .build(); + throw new GraphQLException("FulledShift"); } ShiftRegistrationEntity record = new ShiftRegistrationEntity(); @@ -67,51 +85,81 @@ public class ShiftService { record.shift = shift; record.persist(); - return Response.ok(record).build(); + return record; } - @GET - @Path("/me") - @RolesAllowed(Role.Staff) - public List getMyShifts() { - String userId = request.getHeader(InternalValue.userId); - return ShiftRegistrationEntity.list("staffId", UUID.fromString(userId)); - } - - @GET - @RolesAllowed({ Role.Staff, Role.Manager }) - public List getShift() { - return ShiftEntity.listAll(); - } - - @POST + @Mutation("createShift") + @Description("Quản lý tạo mới một loại ca trực") + @RolesAllowed(Role.Manager) @Transactional - public Response createShift(CreateShift request) { - if ( - request.name == null || - request.name.isEmpty() || - request.startTime == null || - request.endTime == null - ) { - return Response.status(Response.Status.BAD_REQUEST) - .entity("BadInput") - .build(); - } + public ShiftEntity createShift(@Name("shiftInput") CreateShift input) + throws GraphQLException { ShiftEntity shift = new ShiftEntity(); - shift.name = request.name; - shift.startTime = request.startTime; - shift.endTime = request.endTime; - shift.maxStaff = request.maxStaff; + shift.name = input.name; + shift.startTime = input.startTime; + shift.endTime = input.endTime; + shift.maxStaff = input.maxStaff; if (shift.endTime.isBefore(shift.startTime)) { - return Response.status(Response.Status.BAD_REQUEST) - .entity("InvalidEndTime") - .build(); + throw new GraphQLException("InvalidEndTime"); } shift.persist(); + return shift; + } - return Response.status(Response.Status.CREATED).entity(shift).build(); + @Mutation("updateShift") + @Description("Quản lý cập nhật thông tin ca trực") + @RolesAllowed(Role.Manager) + @Transactional + public ShiftEntity updateShift( + @Name("id") UUID id, + @Name("shiftInput") CreateShift input + ) throws GraphQLException { + ShiftEntity shift = ShiftEntity.findById(id); + if (shift == null) throw new GraphQLException("NotFoundShift"); + + shift.name = input.name; + shift.startTime = input.startTime; + shift.endTime = input.endTime; + shift.maxStaff = input.maxStaff; + + if (shift.endTime.isBefore(shift.startTime)) { + throw new GraphQLException("InvalidEndTime"); + } + + return shift; + } + + @Mutation("deleteShift") + @Description("Quản lý xóa một ca trực") + @RolesAllowed(Role.Manager) + @Transactional + public boolean deleteShift(@Name("id") Long id) throws GraphQLException { + long count = ShiftRegistrationEntity.count("shift.id", id); + if (count > 0) throw new GraphQLException( + "CannotDeleteShiftWithRegistrations" + ); + + return ShiftEntity.deleteById(id); + } + + @Mutation("cancelRegistration") + @Description("Nhân viên hủy ca đã đăng ký") + @RolesAllowed(Role.Staff) + @Transactional + public boolean cancelRegistration(@Name("registrationId") UUID id) + throws GraphQLException { + String userId = request.getHeader(InternalValue.userId); + ShiftRegistrationEntity reg = ShiftRegistrationEntity.findById(id); + + if (reg == null) throw new GraphQLException("RegistrationNotFound"); + if (!reg.staffId.equals(UUID.fromString(userId))) { + throw new GraphQLException("NotYourRegistration"); + } + + reg.delete(); + return true; } } diff --git a/eatery-service/src/test/java/com/drinkool/services/ShiftServiceTest.java b/eatery-service/src/test/java/com/drinkool/services/ShiftServiceTest.java new file mode 100644 index 0000000..a1071e5 --- /dev/null +++ b/eatery-service/src/test/java/com/drinkool/services/ShiftServiceTest.java @@ -0,0 +1,5 @@ +package com.drinkool.services; + +public class ShiftServiceTest { + +} diff --git a/lib/src/main/java/com/drinkool/lib/dtos/RegisterShift.java b/lib/src/main/java/com/drinkool/lib/dtos/RegisterShift.java deleted file mode 100644 index d547637..0000000 --- a/lib/src/main/java/com/drinkool/lib/dtos/RegisterShift.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.drinkool.lib.dtos; - -import java.util.UUID; - -public class RegisterShift { - - public UUID shiftId; -}