123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- // Ниже реализован сервис бронирования номеров в отеле. В предметной области
- // выделены два понятия: Order — заказ, который включает в себя даты бронирования
- // и контакты пользователя, и RoomAvailability — количество свободных номеров на
- // конкретный день.
- //
- // Задание:
- // - провести рефакторинг кода с выделением слоев и абстракций
- // - применить best-practices там где это имеет смысл
- // - исправить имеющиеся в реализации логические и технические ошибки и неточности
- package main
- import (
- "encoding/json"
- "errors"
- "fmt"
- "log"
- "net/http"
- "os"
- "time"
- )
- type Order struct {
- HotelID string `json:"hotel_id"`
- RoomID string `json:"room_id"`
- UserEmail string `json:"email"`
- From time.Time `json:"from"`
- To time.Time `json:"to"`
- }
- var Orders = []Order{}
- type RoomAvailability struct {
- HotelID string `json:"hotel_id"`
- RoomID string `json:"room_id"`
- Date time.Time `json:"date"`
- Quota int `json:"quota"`
- }
- var Availability = []RoomAvailability{
- {"reddison", "lux", date(2024, 1, 1), 1},
- {"reddison", "lux", date(2024, 1, 2), 1},
- {"reddison", "lux", date(2024, 1, 3), 1},
- {"reddison", "lux", date(2024, 1, 4), 1},
- {"reddison", "lux", date(2024, 1, 5), 0},
- }
- func main() {
- mux := http.NewServeMux()
- mux.HandleFunc("/orders", createOrder)
- LogInfo("Server listening on localhost:8080")
- err := http.ListenAndServe(":8080", mux)
- if errors.Is(err, http.ErrServerClosed) {
- LogInfo("Server closed")
- } else if err != nil {
- LogErrorf("Server failed: %s", err)
- os.Exit(1)
- }
- }
- func createOrder(w http.ResponseWriter, r *http.Request) {
- var newOrder Order
- json.NewDecoder(r.Body).Decode(&newOrder)
- daysToBook := daysBetween(newOrder.From, newOrder.To)
- unavailableDays := make(map[time.Time]struct{})
- for _, day := range daysToBook {
- unavailableDays[day] = struct{}{}
- }
- for _, dayToBook := range daysToBook {
- for i, availability := range Availability {
- if !availability.Date.Equal(dayToBook) || availability.Quota < 1 {
- continue
- }
- availability.Quota -= 1
- Availability[i] = availability
- delete(unavailableDays, dayToBook)
- }
- }
- if len(unavailableDays) != 0 {
- http.Error(w, "Hotel room is not available for selected dates", http.StatusInternalServerError)
- LogErrorf("Hotel room is not available for selected dates:\n%v\n%v", newOrder, unavailableDays)
- return
- }
- Orders = append(Orders, newOrder)
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(http.StatusCreated)
- json.NewEncoder(w).Encode(newOrder)
- LogInfo("Order successfully created: %v", newOrder)
- }
- func daysBetween(from time.Time, to time.Time) []time.Time {
- if from.After(to) {
- return nil
- }
- days := make([]time.Time, 0)
- for d := toDay(from); !d.After(toDay(to)); d = d.AddDate(0, 0, 1) {
- days = append(days, d)
- }
- return days
- }
- func toDay(timestamp time.Time) time.Time {
- return time.Date(timestamp.Year(), timestamp.Month(), timestamp.Day(), 0, 0, 0, 0, time.UTC)
- }
- func date(year, month, day int) time.Time {
- return time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC)
- }
- var logger = log.Default()
- func LogErrorf(format string, v ...any) {
- msg := fmt.Sprintf(format, v...)
- logger.Printf("[Error]: %s\n", msg)
- }
- func LogInfo(format string, v ...any) {
- msg := fmt.Sprintf(format, v...)
- logger.Printf("[Info]: %s\n", msg)
- }
|