main.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. // Ниже реализован сервис бронирования номеров в отеле. В предметной области
  2. // выделены два понятия: Order — заказ, который включает в себя даты бронирования
  3. // и контакты пользователя, и RoomAvailability — количество свободных номеров на
  4. // конкретный день.
  5. //
  6. // Задание:
  7. // - провести рефакторинг кода с выделением слоев и абстракций
  8. // - применить best-practices там где это имеет смысл
  9. // - исправить имеющиеся в реализации логические и технические ошибки и неточности
  10. package main
  11. import (
  12. "encoding/json"
  13. "errors"
  14. "fmt"
  15. "log"
  16. "net/http"
  17. "os"
  18. "time"
  19. )
  20. type Order struct {
  21. HotelID string `json:"hotel_id"`
  22. RoomID string `json:"room_id"`
  23. UserEmail string `json:"email"`
  24. From time.Time `json:"from"`
  25. To time.Time `json:"to"`
  26. }
  27. var Orders = []Order{}
  28. type RoomAvailability struct {
  29. HotelID string `json:"hotel_id"`
  30. RoomID string `json:"room_id"`
  31. Date time.Time `json:"date"`
  32. Quota int `json:"quota"`
  33. }
  34. var Availability = []RoomAvailability{
  35. {"reddison", "lux", date(2024, 1, 1), 1},
  36. {"reddison", "lux", date(2024, 1, 2), 1},
  37. {"reddison", "lux", date(2024, 1, 3), 1},
  38. {"reddison", "lux", date(2024, 1, 4), 1},
  39. {"reddison", "lux", date(2024, 1, 5), 0},
  40. }
  41. func main() {
  42. mux := http.NewServeMux()
  43. mux.HandleFunc("/orders", createOrder)
  44. LogInfo("Server listening on localhost:8080")
  45. err := http.ListenAndServe(":8080", mux)
  46. if errors.Is(err, http.ErrServerClosed) {
  47. LogInfo("Server closed")
  48. } else if err != nil {
  49. LogErrorf("Server failed: %s", err)
  50. os.Exit(1)
  51. }
  52. }
  53. func createOrder(w http.ResponseWriter, r *http.Request) {
  54. var newOrder Order
  55. json.NewDecoder(r.Body).Decode(&newOrder)
  56. daysToBook := daysBetween(newOrder.From, newOrder.To)
  57. unavailableDays := make(map[time.Time]struct{})
  58. for _, day := range daysToBook {
  59. unavailableDays[day] = struct{}{}
  60. }
  61. for _, dayToBook := range daysToBook {
  62. for i, availability := range Availability {
  63. if !availability.Date.Equal(dayToBook) || availability.Quota < 1 {
  64. continue
  65. }
  66. availability.Quota -= 1
  67. Availability[i] = availability
  68. delete(unavailableDays, dayToBook)
  69. }
  70. }
  71. if len(unavailableDays) != 0 {
  72. http.Error(w, "Hotel room is not available for selected dates", http.StatusInternalServerError)
  73. LogErrorf("Hotel room is not available for selected dates:\n%v\n%v", newOrder, unavailableDays)
  74. return
  75. }
  76. Orders = append(Orders, newOrder)
  77. w.Header().Set("Content-Type", "application/json")
  78. w.WriteHeader(http.StatusCreated)
  79. json.NewEncoder(w).Encode(newOrder)
  80. LogInfo("Order successfully created: %v", newOrder)
  81. }
  82. func daysBetween(from time.Time, to time.Time) []time.Time {
  83. if from.After(to) {
  84. return nil
  85. }
  86. days := make([]time.Time, 0)
  87. for d := toDay(from); !d.After(toDay(to)); d = d.AddDate(0, 0, 1) {
  88. days = append(days, d)
  89. }
  90. return days
  91. }
  92. func toDay(timestamp time.Time) time.Time {
  93. return time.Date(timestamp.Year(), timestamp.Month(), timestamp.Day(), 0, 0, 0, 0, time.UTC)
  94. }
  95. func date(year, month, day int) time.Time {
  96. return time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC)
  97. }
  98. var logger = log.Default()
  99. func LogErrorf(format string, v ...any) {
  100. msg := fmt.Sprintf(format, v...)
  101. logger.Printf("[Error]: %s\n", msg)
  102. }
  103. func LogInfo(format string, v ...any) {
  104. msg := fmt.Sprintf(format, v...)
  105. logger.Printf("[Info]: %s\n", msg)
  106. }