original.go.old 3.6 KB

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