diff --git a/src/main/java/com/example/nto/App.java b/src/main/java/com/example/nto/App.java index e453f89..5eefc45 100644 --- a/src/main/java/com/example/nto/App.java +++ b/src/main/java/com/example/nto/App.java @@ -1,12 +1,16 @@ package com.example.nto; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; /** * TODO: ДОРАБОТАТЬ в рамках задания * ================================= * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ +@SpringBootApplication public class App { public static void main(String[] args) { + SpringApplication.run(App.class, args); } } diff --git a/src/main/java/com/example/nto/GlobalExceptionHandler.java b/src/main/java/com/example/nto/GlobalExceptionHandler.java new file mode 100644 index 0000000..d21afe4 --- /dev/null +++ b/src/main/java/com/example/nto/GlobalExceptionHandler.java @@ -0,0 +1,35 @@ +package com.example.nto; + +import com.example.nto.exception.AlreadyBookedException; +import com.example.nto.exception.CodeNotFoundException; +import com.example.nto.exception.InvalidRequestException; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +@ControllerAdvice +public class GlobalExceptionHandler { + + @ExceptionHandler(InvalidRequestException.class) + public ResponseEntity handleInvalidRequest(InvalidRequestException ex) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ex.getMessage()); + } + + @ExceptionHandler(CodeNotFoundException.class) + public ResponseEntity handleCodeNotFound(CodeNotFoundException ex) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(ex.getMessage()); + } + + @ExceptionHandler(AlreadyBookedException.class) + public ResponseEntity handleAlreadyBooked(AlreadyBookedException ex) { + return ResponseEntity.status(HttpStatus.CONFLICT).body(ex.getMessage()); + } + + // Обработка ошибок парсинга JSON + @ExceptionHandler(HttpMessageNotReadableException.class) + public ResponseEntity handleJsonParseError(HttpMessageNotReadableException ex) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("что-то пошло не так"); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/nto/controller/BookingController.java b/src/main/java/com/example/nto/controller/BookingController.java index 9885f84..7577691 100644 --- a/src/main/java/com/example/nto/controller/BookingController.java +++ b/src/main/java/com/example/nto/controller/BookingController.java @@ -1,10 +1,113 @@ package com.example.nto.controller; +import com.example.nto.entity.Booking; +import com.example.nto.entity.Employee; +import com.example.nto.entity.Place; +import com.example.nto.exception.AlreadyBookedException; +import com.example.nto.exception.CodeNotFoundException; +import com.example.nto.exception.InvalidRequestException; +import com.example.nto.repository.BookingRepository; +import com.example.nto.repository.EmployeeRepository; +import com.example.nto.repository.PlaceRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDate; +import java.time.temporal.ChronoUnit; +import java.util.*; +import java.util.stream.Collectors; + /** * TODO: ДОРАБОТАТЬ в рамках задания * ================================= * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ + +@RestController +@RequestMapping("/api/{code}") public class BookingController { + @Autowired + private EmployeeRepository employeeRepository; + + @Autowired + private PlaceRepository placeRepository; + + @Autowired + private BookingRepository bookingRepository; + + static class BookingRequest { + public LocalDate date; + public Long placeID; + } + + @GetMapping("/booking") + public ResponseEntity getAvailablePlaces(@PathVariable String code) { + Employee employee = employeeRepository.findByCode(code); + if (code == null || code.trim().isEmpty()) { + return ResponseEntity + .badRequest() + .body("что-то пошло не так"); + } + if (employeeRepository.findByCode(code.trim()) == null) { + return ResponseEntity + .status(HttpStatus.UNAUTHORIZED) + .body("кода не существует"); + } + LocalDate today = LocalDate.now(); + Map>> result = new LinkedHashMap<>(); + + for (int i = 0; i <= 3; i++) { + LocalDate date = today.plusDays(i); + String dateKey = date.toString(); + List allPlaces = placeRepository.findAll(); + List> freePlaces = new ArrayList<>(); + for (Place place : allPlaces) { + if (!bookingRepository.existsByDateAndPlace_Id(date, place.getId())) { + Map placeInfo = new LinkedHashMap<>(); + placeInfo.put("id", place.getId()); + placeInfo.put("place", place.getPlaceName()); + freePlaces.add(placeInfo); + } + } + + result.put(dateKey, freePlaces); + } + + return ResponseEntity.ok(result); + } + + @PostMapping("/book") + public ResponseEntity book(@PathVariable String code, @RequestBody BookingRequest req) { + if (req == null || req.date == null || req.placeID == null) { + throw new InvalidRequestException(); + } + + Employee employee = employeeRepository.findByCode(code.trim()); + if (employee == null) { + throw new CodeNotFoundException(); + } + + Place place = placeRepository.findById(req.placeID).orElse(null); + if (place == null) { + throw new InvalidRequestException(); + } + + if (bookingRepository.existsByDateAndPlace_Id(req.date, req.placeID)) { + throw new AlreadyBookedException(); + } + + Booking booking = new Booking(); + booking.setDate(req.date); + booking.setPlace(place); + booking.setEmployee(employee); + + bookingRepository.save(booking); + + return ResponseEntity + .status(HttpStatus.CREATED) + .body("бронирование успешно создано"); + } } diff --git a/src/main/java/com/example/nto/controller/EmployeeController.java b/src/main/java/com/example/nto/controller/EmployeeController.java index 47658f9..2282857 100644 --- a/src/main/java/com/example/nto/controller/EmployeeController.java +++ b/src/main/java/com/example/nto/controller/EmployeeController.java @@ -1,10 +1,87 @@ package com.example.nto.controller; +import com.example.nto.entity.Booking; +import com.example.nto.entity.Employee; +import com.example.nto.exception.CodeNotFoundException; +import com.example.nto.exception.InvalidRequestException; +import com.example.nto.repository.BookingRepository; +import com.example.nto.repository.EmployeeRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + /** * TODO: ДОРАБОТАТЬ в рамках задания * ================================= * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ +@RestController +@RequestMapping("/api/{code}") public class EmployeeController { + @Autowired + private EmployeeRepository employeeRepository; + + @Autowired + private BookingRepository bookingRepository; + + @GetMapping("/auth") + public ResponseEntity checkAuth(@PathVariable String code) { + if (code == null || code.trim().isEmpty()) { + throw new InvalidRequestException(); + } + if (employeeRepository.findByCode(code.trim()) == null) { + throw new CodeNotFoundException(); + } + return ResponseEntity.status(200).body("данный код существует - можно пользоваться приложением"); + } + + @GetMapping("/info") + public ResponseEntity getInfo(@PathVariable String code) { + if (code == null || code.trim().isEmpty()) { + throw new InvalidRequestException(); + } + if (employeeRepository.findByCode(code.trim()) == null) { + throw new CodeNotFoundException(); + } + + String cleanCode = code.trim(); + Employee employee = employeeRepository.findByCode(cleanCode); + + if (employee == null) { + return ResponseEntity + .status(HttpStatus.UNAUTHORIZED) + .body("кода не существует"); + } + List bookings = bookingRepository.findByEmployee_Code(code); + Map response = getStringObjectMap(employee, bookings); + return ResponseEntity.ok(response); + } + + private Map getStringObjectMap(Employee employee, List bookings) { + Map response = new LinkedHashMap<>(); + response.put("name", employee.getName()); + response.put("photoUrl", employee.getPhotoUrl()); + + Map bookingMap = new HashMap<>(); + for (Booking b : bookings) { + String dateStr = b.getDate().toString(); + Map placeInfo = new HashMap<>(); + placeInfo.put("id", b.getPlace().getId()); + placeInfo.put("place", b.getPlace().getPlaceName()); + bookingMap.put(dateStr, placeInfo); + } + + response.put("booking", bookingMap); + return response; + } } diff --git a/src/main/java/com/example/nto/entity/Booking.java b/src/main/java/com/example/nto/entity/Booking.java index 21c1981..bea37b9 100644 --- a/src/main/java/com/example/nto/entity/Booking.java +++ b/src/main/java/com/example/nto/entity/Booking.java @@ -1,12 +1,7 @@ package com.example.nto.entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; +import jakarta.persistence.*; +import lombok.*; import java.time.LocalDate; @@ -17,19 +12,54 @@ import java.time.LocalDate; * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ -@Data -@Builder +@Entity +@Table(name = "booking") +@Getter +@Setter @NoArgsConstructor @AllArgsConstructor public class Booking { + public void setId(Long id) { + this.id = id; + } - private long id; + public void setDate(LocalDate date) { + this.date = date; + } + public void setPlace(Place place) { + this.place = place; + } + + public void setEmployee(Employee employee) { + this.employee = employee; + } + + public LocalDate getDate() { + return date; + } + + public Place getPlace() { + return place; + } + + public Employee getEmployee() { + return employee; + } + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "date", nullable = false) private LocalDate date; - @ManyToOne(targetEntity = Place.class, fetch = FetchType.LAZY) - @JoinColumn(name = "place_id") + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "place_id", nullable = false) private Place place; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "employee_id", nullable = false) private Employee employee; + } diff --git a/src/main/java/com/example/nto/entity/Employee.java b/src/main/java/com/example/nto/entity/Employee.java index a52102b..9950d3e 100644 --- a/src/main/java/com/example/nto/entity/Employee.java +++ b/src/main/java/com/example/nto/entity/Employee.java @@ -1,10 +1,7 @@ package com.example.nto.entity; import jakarta.persistence.*; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; +import lombok.*; import java.util.List; @@ -15,20 +12,59 @@ import java.util.List; * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ -@Data -@Builder +@Entity +@Table(name = "employee") +@Getter +@Setter @NoArgsConstructor @AllArgsConstructor public class Employee { - private long id; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name = "name", nullable = false) private String name; + @Column(name = "code", nullable = false, unique = true) private String code; + @Column(name = "photo_url") private String photoUrl; @OneToMany(mappedBy = "employee", cascade = CascadeType.ALL, fetch = FetchType.LAZY) private List bookingList; + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public String getCode() { + return code; + } + + public String getPhotoUrl() { + return photoUrl; + } + + public void setId(Long id) { + this.id = id; + } + + public void setName(String name) { + this.name = name; + } + + public void setCode(String code) { + this.code = code; + } + + public void setPhotoUrl(String photoUrl) { + this.photoUrl = photoUrl; + } } diff --git a/src/main/java/com/example/nto/entity/Place.java b/src/main/java/com/example/nto/entity/Place.java index 00c253b..1463d90 100644 --- a/src/main/java/com/example/nto/entity/Place.java +++ b/src/main/java/com/example/nto/entity/Place.java @@ -1,12 +1,7 @@ package com.example.nto.entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; +import jakarta.persistence.*; +import lombok.*; /** @@ -15,15 +10,29 @@ import lombok.NoArgsConstructor; * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor +@Entity +@Table(name = "place") public class Place { + public Long getId() { + return id; + } + @Column(name = "place_name", nullable = false, unique = true) + public String getPlaceName() { + return place; + } + + public void setPlaceName(String place) { + this.place = place; + } + + public void setId(Long id) { + this.id = id; + } @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - private long id; + private Long id; + @Column(name = "place_name", nullable = false, unique = true) private String place; } diff --git a/src/main/java/com/example/nto/exception/AlreadyBookedException.java b/src/main/java/com/example/nto/exception/AlreadyBookedException.java new file mode 100644 index 0000000..9d303a1 --- /dev/null +++ b/src/main/java/com/example/nto/exception/AlreadyBookedException.java @@ -0,0 +1,7 @@ +package com.example.nto.exception; + +public class AlreadyBookedException extends RuntimeException { + public AlreadyBookedException() { + super("уже забронировано"); + } +} diff --git a/src/main/java/com/example/nto/exception/CodeNotFoundException.java b/src/main/java/com/example/nto/exception/CodeNotFoundException.java new file mode 100644 index 0000000..ca0dbb2 --- /dev/null +++ b/src/main/java/com/example/nto/exception/CodeNotFoundException.java @@ -0,0 +1,7 @@ +package com.example.nto.exception; + +public class CodeNotFoundException extends RuntimeException { + public CodeNotFoundException() { + super("кода не существует"); + } +} diff --git a/src/main/java/com/example/nto/exception/InvalidRequestException.java b/src/main/java/com/example/nto/exception/InvalidRequestException.java new file mode 100644 index 0000000..9edb43d --- /dev/null +++ b/src/main/java/com/example/nto/exception/InvalidRequestException.java @@ -0,0 +1,7 @@ +package com.example.nto.exception; + +public class InvalidRequestException extends RuntimeException { + public InvalidRequestException() { + super("что-то пошло не так"); + } +} diff --git a/src/main/java/com/example/nto/repository/BookingRepository.java b/src/main/java/com/example/nto/repository/BookingRepository.java index 303bb54..dc467d5 100644 --- a/src/main/java/com/example/nto/repository/BookingRepository.java +++ b/src/main/java/com/example/nto/repository/BookingRepository.java @@ -1,10 +1,21 @@ package com.example.nto.repository; +import com.example.nto.entity.Booking; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.time.LocalDate; +import java.util.List; + /** * TODO: ДОРАБОТАТЬ в рамках задания * ================================= * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ -public interface BookingRepository { +@Repository +public interface BookingRepository extends JpaRepository { + List findByEmployee_Code(String code); + List findByDate(LocalDate date); + boolean existsByDateAndPlace_Id(LocalDate date, Long placeId); } diff --git a/src/main/java/com/example/nto/repository/EmployeeRepository.java b/src/main/java/com/example/nto/repository/EmployeeRepository.java index 210d29c..b0e5b28 100644 --- a/src/main/java/com/example/nto/repository/EmployeeRepository.java +++ b/src/main/java/com/example/nto/repository/EmployeeRepository.java @@ -1,10 +1,16 @@ package com.example.nto.repository; +import com.example.nto.entity.Employee; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + /** * TODO: ДОРАБОТАТЬ в рамках задания * ================================= * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ -public interface EmployeeRepository { +@Repository +public interface EmployeeRepository extends JpaRepository { + Employee findByCode(String code); } diff --git a/src/main/java/com/example/nto/repository/PlaceRepository.java b/src/main/java/com/example/nto/repository/PlaceRepository.java index d3bea1d..3006aab 100644 --- a/src/main/java/com/example/nto/repository/PlaceRepository.java +++ b/src/main/java/com/example/nto/repository/PlaceRepository.java @@ -1,10 +1,16 @@ package com.example.nto.repository; +import com.example.nto.entity.Place; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + /** * TODO: ДОРАБОТАТЬ в рамках задания * ================================= * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ -public interface PlaceRepository { +@Repository +public interface PlaceRepository extends JpaRepository { + } diff --git a/src/main/java/com/example/nto/service/BookingService.java b/src/main/java/com/example/nto/service/BookingService.java index 31ec148..bd69750 100644 --- a/src/main/java/com/example/nto/service/BookingService.java +++ b/src/main/java/com/example/nto/service/BookingService.java @@ -8,3 +8,4 @@ package com.example.nto.service; */ public interface BookingService { } +