From a6954c20134f6d257945700d19dce7bee199e033 Mon Sep 17 00:00:00 2001 From: ci-bot Date: Mon, 24 Nov 2025 17:17:06 +0000 Subject: [PATCH 1/4] Update .gitea/workflows/workflow.yml --- .gitea/workflows/workflow.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/workflow.yml b/.gitea/workflows/workflow.yml index 20fe015..5690186 100644 --- a/.gitea/workflows/workflow.yml +++ b/.gitea/workflows/workflow.yml @@ -23,7 +23,7 @@ jobs: GITEA_HEAD_REF: ${{ gitea.event.pull_request.head.ref }} - name: Checkout tests - run: python3 /opt/scripts/copy-tests.py --repo-url "Olympic/NTO-2025-Android-TeamTask-tests" --branch "main" --task-type "spring" + run: python3 /opt/scripts/copy-tests.py --repo-url "Olympic/NTO-2025-Backend-TeamTask-tests" --branch "main" --task-type "spring" - name: Run tests run: mvn test -- 2.34.1 From 5865cb5a2815b8045e5ebe49d0d84b2f3782a40b Mon Sep 17 00:00:00 2001 From: artem <208artems208@gmail.com> Date: Thu, 11 Dec 2025 20:16:29 +0300 Subject: [PATCH 2/4] app, entity and repo --- src/main/java/com/example/nto/App.java | 11 +++++------ .../java/com/example/nto/entity/Booking.java | 10 +++++++--- .../java/com/example/nto/entity/Employee.java | 5 +++++ src/main/java/com/example/nto/entity/Place.java | 7 ++++--- .../nto/repository/BookingRepository.java | 16 +++++++++++++++- .../nto/repository/EmployeeRepository.java | 11 ++++++++++- .../example/nto/repository/PlaceRepository.java | 7 ++++++- 7 files changed, 52 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/example/nto/App.java b/src/main/java/com/example/nto/App.java index e453f89..d4add94 100644 --- a/src/main/java/com/example/nto/App.java +++ b/src/main/java/com/example/nto/App.java @@ -1,12 +1,11 @@ package com.example.nto; -/** - * TODO: ДОРАБОТАТЬ в рамках задания - * ================================= - * МОЖНО: Добавлять методы, аннотации, зависимости - * НЕЛЬЗЯ: Изменять название класса и пакета - */ +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication public class App { public static void main(String[] args) { + SpringApplication.run(App.class, args); } } diff --git a/src/main/java/com/example/nto/entity/Booking.java b/src/main/java/com/example/nto/entity/Booking.java index 21c1981..0a864e9 100644 --- a/src/main/java/com/example/nto/entity/Booking.java +++ b/src/main/java/com/example/nto/entity/Booking.java @@ -1,8 +1,6 @@ package com.example.nto.entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; +import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -21,8 +19,12 @@ import java.time.LocalDate; @Builder @NoArgsConstructor @AllArgsConstructor +@Entity +@Table(name = "booking") public class Booking { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; private LocalDate date; @@ -31,5 +33,7 @@ public class Booking { @JoinColumn(name = "place_id") private Place place; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "employee_id") 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..ed04d17 100644 --- a/src/main/java/com/example/nto/entity/Employee.java +++ b/src/main/java/com/example/nto/entity/Employee.java @@ -19,14 +19,19 @@ import java.util.List; @Builder @NoArgsConstructor @AllArgsConstructor +@Entity +@Table(name = "employee") public class Employee { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; private String name; private String code; + @Column(name = "photo_url") private String photoUrl; @OneToMany(mappedBy = "employee", cascade = CascadeType.ALL, fetch = FetchType.LAZY) diff --git a/src/main/java/com/example/nto/entity/Place.java b/src/main/java/com/example/nto/entity/Place.java index 00c253b..1f2f50e 100644 --- a/src/main/java/com/example/nto/entity/Place.java +++ b/src/main/java/com/example/nto/entity/Place.java @@ -1,8 +1,6 @@ package com.example.nto.entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; +import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -19,11 +17,14 @@ import lombok.NoArgsConstructor; @Builder @NoArgsConstructor @AllArgsConstructor +@Entity +@Table(name = "place") public class Place { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; + @Column(name = "place_name") private String place; } diff --git a/src/main/java/com/example/nto/repository/BookingRepository.java b/src/main/java/com/example/nto/repository/BookingRepository.java index 303bb54..567f48a 100644 --- a/src/main/java/com/example/nto/repository/BookingRepository.java +++ b/src/main/java/com/example/nto/repository/BookingRepository.java @@ -1,10 +1,24 @@ 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; +import java.util.Optional; + /** * TODO: ДОРАБОТАТЬ в рамках задания * ================================= * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ -public interface BookingRepository { +@Repository +public interface BookingRepository extends JpaRepository { + List findByDateBetween(LocalDate startDate, LocalDate endDate); + List findByEmployeeIdAndDateBetween(Long employeeId, LocalDate startDate, LocalDate endDate); + Optional findByDateAndPlaceId(LocalDate date, Long placeId); + boolean existsByEmployeeIdAndDate(Long employeeId, LocalDate date); + List findByDate(LocalDate date); } diff --git a/src/main/java/com/example/nto/repository/EmployeeRepository.java b/src/main/java/com/example/nto/repository/EmployeeRepository.java index 210d29c..570f873 100644 --- a/src/main/java/com/example/nto/repository/EmployeeRepository.java +++ b/src/main/java/com/example/nto/repository/EmployeeRepository.java @@ -1,10 +1,19 @@ package com.example.nto.repository; +import com.example.nto.entity.Employee; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + /** * TODO: ДОРАБОТАТЬ в рамках задания * ================================= * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ -public interface EmployeeRepository { +@Repository +public interface EmployeeRepository extends JpaRepository { + Optional findByCode(String code); + boolean existsByCode(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..425dacb 100644 --- a/src/main/java/com/example/nto/repository/PlaceRepository.java +++ b/src/main/java/com/example/nto/repository/PlaceRepository.java @@ -1,10 +1,15 @@ 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 { } -- 2.34.1 From 6e83eb0cbbc0490ad8dd0439ec3d8d8f2c0d0adf Mon Sep 17 00:00:00 2001 From: artem <208artems208@gmail.com> Date: Thu, 11 Dec 2025 20:46:54 +0300 Subject: [PATCH 3/4] controllers and services --- .../nto/controller/BookingController.java | 51 +++++++++ .../nto/controller/EmployeeController.java | 36 +++++++ .../example/nto/service/BookingService.java | 5 + .../example/nto/service/EmployeeService.java | 5 + .../nto/service/impl/BookingServiceImpl.java | 101 ++++++++++++++++++ .../nto/service/impl/EmployeeServiceImpl.java | 48 +++++++++ 6 files changed, 246 insertions(+) diff --git a/src/main/java/com/example/nto/controller/BookingController.java b/src/main/java/com/example/nto/controller/BookingController.java index 9885f84..03c9937 100644 --- a/src/main/java/com/example/nto/controller/BookingController.java +++ b/src/main/java/com/example/nto/controller/BookingController.java @@ -1,10 +1,61 @@ package com.example.nto.controller; +import com.example.nto.service.BookingService; +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.util.Map; /** * TODO: ДОРАБОТАТЬ в рамках задания * ================================= * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ +@RestController +@RequestMapping("/api/{code}") public class BookingController { + + @Autowired + private BookingService bookingService; + + @GetMapping("/booking") + public ResponseEntity getAvailablePlaces(@PathVariable String code) { + try { + if (!bookingService.employeeExists(code)) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); + } + + Map availablePlaces = bookingService.getAvailablePlaces(); + return ResponseEntity.ok(availablePlaces); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).build(); + } + } + + @PostMapping("/book") + public ResponseEntity bookPlace(@PathVariable String code, @RequestBody Map request) { + try { + if (!bookingService.employeeExists(code)) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); + } + + String date = (String) request.get("date"); + Integer placeId = (Integer) request.get("placeId"); + + if (date == null || placeId == null) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).build(); + } + + boolean success = bookingService.createBooking(code, date, placeId); + if (!success) { + return ResponseEntity.status(HttpStatus.CONFLICT).build(); + } + + return ResponseEntity.status(HttpStatus.CREATED).build(); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).build(); + } + } } diff --git a/src/main/java/com/example/nto/controller/EmployeeController.java b/src/main/java/com/example/nto/controller/EmployeeController.java index 47658f9..ea23a53 100644 --- a/src/main/java/com/example/nto/controller/EmployeeController.java +++ b/src/main/java/com/example/nto/controller/EmployeeController.java @@ -1,10 +1,46 @@ package com.example.nto.controller; +import com.example.nto.service.EmployeeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + /** * TODO: ДОРАБОТАТЬ в рамках задания * ================================= * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ + +@RestController +@RequestMapping("/api/{code}") public class EmployeeController { + + @Autowired + private EmployeeService employeeService; + + @GetMapping("/auth") + public ResponseEntity auth(@PathVariable String code) { + try { + boolean exists = employeeService.existsByCode(code); + if (!exists) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); + } + return ResponseEntity.ok().build(); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).build(); + } + } + + @GetMapping("/info") + public ResponseEntity getInfo(@PathVariable String code) { + try { + return employeeService.getEmployeeInfo(code) + .map(ResponseEntity::ok) + .orElse(ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).build(); + } + } } diff --git a/src/main/java/com/example/nto/service/BookingService.java b/src/main/java/com/example/nto/service/BookingService.java index 31ec148..aa185b4 100644 --- a/src/main/java/com/example/nto/service/BookingService.java +++ b/src/main/java/com/example/nto/service/BookingService.java @@ -1,5 +1,7 @@ package com.example.nto.service; +import java.util.Map; + /** * TODO: ДОРАБОТАТЬ в рамках задания * ================================= @@ -7,4 +9,7 @@ package com.example.nto.service; * НЕЛЬЗЯ: Изменять название класса и пакета */ public interface BookingService { + boolean employeeExists(String code); + Map getAvailablePlaces(); + boolean createBooking(String code, String date, Integer placeId); } diff --git a/src/main/java/com/example/nto/service/EmployeeService.java b/src/main/java/com/example/nto/service/EmployeeService.java index cccd209..b240899 100644 --- a/src/main/java/com/example/nto/service/EmployeeService.java +++ b/src/main/java/com/example/nto/service/EmployeeService.java @@ -1,5 +1,8 @@ package com.example.nto.service; +import java.util.Map; +import java.util.Optional; + /** * TODO: ДОРАБОТАТЬ в рамках задания * ================================= @@ -7,4 +10,6 @@ package com.example.nto.service; * НЕЛЬЗЯ: Изменять название класса и пакета */ public interface EmployeeService { + boolean existsByCode(String code); + Optional> getEmployeeInfo(String code); } diff --git a/src/main/java/com/example/nto/service/impl/BookingServiceImpl.java b/src/main/java/com/example/nto/service/impl/BookingServiceImpl.java index d24b244..9ad3f20 100644 --- a/src/main/java/com/example/nto/service/impl/BookingServiceImpl.java +++ b/src/main/java/com/example/nto/service/impl/BookingServiceImpl.java @@ -1,6 +1,22 @@ package com.example.nto.service.impl; import com.example.nto.service.BookingService; +import com.example.nto.entity.Booking; +import com.example.nto.entity.Employee; +import com.example.nto.entity.Place; +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.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; /** * TODO: ДОРАБОТАТЬ в рамках задания @@ -8,5 +24,90 @@ import com.example.nto.service.BookingService; * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ +@Service public class BookingServiceImpl implements BookingService { + + @Autowired + private BookingRepository bookingRepository; + + @Autowired + private EmployeeRepository employeeRepository; + + @Autowired + private PlaceRepository placeRepository; + + @Override + public boolean employeeExists(String code) { + return employeeRepository.findByCode(code).isPresent(); + } + + @Override + public Map getAvailablePlaces() { + Map result = new HashMap<>(); + LocalDate today = LocalDate.now(); + + List allPlaces = placeRepository.findAll(); + + for (int i = 0; i < 4; i++) { + LocalDate date = today.plusDays(i); + String dateStr = date.toString(); + + List bookingsOnDate = bookingRepository.findByDate(date); + + List bookedPlaceIds = new ArrayList<>(); + for (Booking booking : bookingsOnDate) { + bookedPlaceIds.add(booking.getPlace().getId()); + } + + List> availablePlaces = new ArrayList<>(); + for (Place place : allPlaces) { + if (!bookedPlaceIds.contains(place.getId())) { + Map placeInfo = new HashMap<>(); + placeInfo.put("id", place.getId()); + placeInfo.put("place", place.getPlace()); + availablePlaces.add(placeInfo); + } + } + + result.put(dateStr, availablePlaces); + } + + return result; + } + + @Override + @Transactional + public boolean createBooking(String code, String date, Integer placeId) { + try { + Optional employeeOpt = employeeRepository.findByCode(code); + if (employeeOpt.isEmpty()) { + return false; + } + + Optional placeOpt = placeRepository.findById(placeId.longValue()); + if (placeOpt.isEmpty()) { + return false; + } + + LocalDate bookingDate = LocalDate.parse(date); + Place place = placeOpt.get(); + Employee employee = employeeOpt.get(); + + Optional existingBooking = bookingRepository.findByDateAndPlaceId(bookingDate, place.getId()); + if (existingBooking.isPresent()) { + return false; + } + + Booking booking = new Booking(); + booking.setDate(bookingDate); + booking.setPlace(place); + booking.setEmployee(employee); + + bookingRepository.save(booking); + return true; + + } catch (Exception e) { + return false; + } + } } diff --git a/src/main/java/com/example/nto/service/impl/EmployeeServiceImpl.java b/src/main/java/com/example/nto/service/impl/EmployeeServiceImpl.java index f8125e5..2307946 100644 --- a/src/main/java/com/example/nto/service/impl/EmployeeServiceImpl.java +++ b/src/main/java/com/example/nto/service/impl/EmployeeServiceImpl.java @@ -1,6 +1,15 @@ package com.example.nto.service.impl; +import com.example.nto.entity.Booking; +import com.example.nto.entity.Employee; +import com.example.nto.repository.EmployeeRepository; import com.example.nto.service.EmployeeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; /** * TODO: ДОРАБОТАТЬ в рамках задания @@ -8,5 +17,44 @@ import com.example.nto.service.EmployeeService; * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ +@Service public class EmployeeServiceImpl implements EmployeeService { + + @Autowired + private EmployeeRepository employeeRepository; + + @Override + public boolean existsByCode(String code) { + return employeeRepository.findByCode(code).isPresent(); + } + + @Override + public Optional> getEmployeeInfo(String code) { + Optional employeeOpt = employeeRepository.findByCode(code); + + if (employeeOpt.isEmpty()) { + return Optional.empty(); + } + + Employee employee = employeeOpt.get(); + Map info = new HashMap<>(); + info.put("name", employee.getName()); + info.put("photoUrl", employee.getPhotoUrl()); + + Map> bookingsMap = new HashMap<>(); + + // Используем bookingList вместо bookings + if (employee.getBookingList() != null) { + for (Booking booking : employee.getBookingList()) { + Map bookingInfo = new HashMap<>(); + bookingInfo.put("id", booking.getId()); + bookingInfo.put("place", booking.getPlace()); + + bookingsMap.put(booking.getDate().toString(), bookingInfo); + } + } + + info.put("booking", bookingsMap); + return Optional.of(info); + } } -- 2.34.1 From cd9bde664172eb94ff8190fe2708e74726e29bc5 Mon Sep 17 00:00:00 2001 From: artem <208artems208@gmail.com> Date: Thu, 11 Dec 2025 21:16:40 +0300 Subject: [PATCH 4/4] fix --- .../nto/service/impl/EmployeeServiceImpl.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/nto/service/impl/EmployeeServiceImpl.java b/src/main/java/com/example/nto/service/impl/EmployeeServiceImpl.java index 2307946..e5b581a 100644 --- a/src/main/java/com/example/nto/service/impl/EmployeeServiceImpl.java +++ b/src/main/java/com/example/nto/service/impl/EmployeeServiceImpl.java @@ -2,8 +2,10 @@ package com.example.nto.service.impl; import com.example.nto.entity.Booking; import com.example.nto.entity.Employee; +import com.example.nto.entity.Place; import com.example.nto.repository.EmployeeRepository; import com.example.nto.service.EmployeeService; +import jakarta.transaction.Transactional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -29,6 +31,7 @@ public class EmployeeServiceImpl implements EmployeeService { } @Override + @Transactional public Optional> getEmployeeInfo(String code) { Optional employeeOpt = employeeRepository.findByCode(code); @@ -43,12 +46,17 @@ public class EmployeeServiceImpl implements EmployeeService { Map> bookingsMap = new HashMap<>(); - // Используем bookingList вместо bookings if (employee.getBookingList() != null) { for (Booking booking : employee.getBookingList()) { Map bookingInfo = new HashMap<>(); bookingInfo.put("id", booking.getId()); - bookingInfo.put("place", booking.getPlace()); + + Place place = booking.getPlace(); + String placeName = ""; + if (place != null) { + placeName = place.getPlace(); + } + bookingInfo.put("place", placeName); bookingsMap.put(booking.getDate().toString(), bookingInfo); } -- 2.34.1