places.go 4.5 KB

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