places.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. package services
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "gogs.fxtmmsk.ru/foxtime/photoplaces/backend/internal/models"
  7. "gogs.fxtmmsk.ru/foxtime/photoplaces/backend/internal/repository"
  8. )
  9. var (
  10. ErrNotYourPlace = errors.New("not your place")
  11. ErrPlaceNotFound = errors.New("place not found")
  12. )
  13. type PlaceRepo interface {
  14. Create(ctx context.Context, place *models.Place) error
  15. GetByID(ctx context.Context, id string) (*models.Place, error)
  16. List(ctx context.Context, filter models.PlaceFilter) ([]*models.Place, error)
  17. Update(ctx context.Context, place *models.Place) error
  18. UpdateStatus(ctx context.Context, id, status, comment string) error
  19. SoftDelete(ctx context.Context, id string) error
  20. SetTags(ctx context.Context, placeID string, tags []models.Tag) error
  21. SetFeatures(ctx context.Context, placeID string, features []models.Feature) error
  22. GetTags(ctx context.Context, placeID string) ([]models.Tag, error)
  23. GetFeatures(ctx context.Context, placeID string) ([]models.Feature, error)
  24. }
  25. type PlaceService struct {
  26. placeRepo PlaceRepo
  27. }
  28. func NewPlaceService(placeRepo PlaceRepo) *PlaceService {
  29. return &PlaceService{placeRepo: placeRepo}
  30. }
  31. type CreatePlaceInput struct {
  32. OwnerID string
  33. Type string
  34. Title string
  35. Description *string
  36. Address *string
  37. Lat float64
  38. Lng float64
  39. CoverImage *string
  40. AccessInfo *string
  41. HourlyRate *int
  42. Currency string
  43. MinHours int
  44. Tags []models.Tag
  45. Features []models.Feature
  46. }
  47. func (s *PlaceService) Create(ctx context.Context, input CreatePlaceInput) (*models.Place, error) {
  48. place := &models.Place{
  49. Type: input.Type,
  50. OwnerID: input.OwnerID,
  51. Title: input.Title,
  52. Description: input.Description,
  53. Address: input.Address,
  54. Lat: input.Lat,
  55. Lng: input.Lng,
  56. CoverImage: input.CoverImage,
  57. AccessInfo: input.AccessInfo,
  58. Status: "pending_moderation",
  59. HourlyRate: input.HourlyRate,
  60. Currency: input.Currency,
  61. MinHours: input.MinHours,
  62. Tags: input.Tags,
  63. Features: input.Features,
  64. }
  65. if err := s.placeRepo.Create(ctx, place); err != nil {
  66. return nil, fmt.Errorf("create place: %w", err)
  67. }
  68. return place, nil
  69. }
  70. func (s *PlaceService) GetByID(ctx context.Context, id string, fetchTags bool) (*models.Place, error) {
  71. place, err := s.placeRepo.GetByID(ctx, id)
  72. if err != nil {
  73. return nil, err
  74. }
  75. if place == nil {
  76. return nil, nil
  77. }
  78. if fetchTags {
  79. tags, err := s.placeRepo.GetTags(ctx, id)
  80. if err != nil {
  81. return nil, err
  82. }
  83. place.Tags = tags
  84. features, err := s.placeRepo.GetFeatures(ctx, id)
  85. if err != nil {
  86. return nil, err
  87. }
  88. place.Features = features
  89. }
  90. return place, nil
  91. }
  92. func (s *PlaceService) List(ctx context.Context, filter models.PlaceFilter) ([]*models.Place, error) {
  93. return s.placeRepo.List(ctx, filter)
  94. }
  95. type UpdatePlaceInput struct {
  96. ID string
  97. OwnerID string
  98. Title *string
  99. Description *string
  100. Address *string
  101. Lat *float64
  102. Lng *float64
  103. CoverImage *string
  104. AccessInfo *string
  105. HourlyRate *int
  106. Currency *string
  107. MinHours *int
  108. }
  109. func (s *PlaceService) Update(ctx context.Context, input UpdatePlaceInput, isModerator bool) (*models.Place, error) {
  110. place, err := s.placeRepo.GetByID(ctx, input.ID)
  111. if err != nil {
  112. return nil, err
  113. }
  114. if place == nil {
  115. return nil, nil
  116. }
  117. if !isModerator && place.OwnerID != input.OwnerID {
  118. return nil, fmt.Errorf("%w: user %s tried to update place %s", ErrNotYourPlace, input.OwnerID, input.ID)
  119. }
  120. if input.Title != nil { place.Title = *input.Title }
  121. if input.Description != nil { place.Description = input.Description }
  122. if input.Address != nil { place.Address = input.Address }
  123. if input.Lat != nil { place.Lat = *input.Lat }
  124. if input.Lng != nil { place.Lng = *input.Lng }
  125. if input.CoverImage != nil { place.CoverImage = input.CoverImage }
  126. if input.AccessInfo != nil { place.AccessInfo = input.AccessInfo }
  127. if input.HourlyRate != nil { place.HourlyRate = input.HourlyRate }
  128. if input.Currency != nil { place.Currency = *input.Currency }
  129. if input.MinHours != nil { place.MinHours = *input.MinHours }
  130. if !isModerator {
  131. place.Status = "pending_moderation"
  132. }
  133. if err := s.placeRepo.Update(ctx, place); err != nil {
  134. return nil, err
  135. }
  136. return place, nil
  137. }
  138. func (s *PlaceService) Moderate(ctx context.Context, id, action, comment, moderatorID string) error {
  139. var status string
  140. switch action {
  141. case "approve":
  142. status = "published"
  143. case "reject":
  144. status = "rejected"
  145. default:
  146. return fmt.Errorf("unknown action: %s", action)
  147. }
  148. return s.placeRepo.UpdateStatus(ctx, id, status, comment)
  149. }
  150. func (s *PlaceService) Delete(ctx context.Context, id string) error {
  151. return s.placeRepo.SoftDelete(ctx, id)
  152. }