222 lines
6.7 KiB
Go
222 lines
6.7 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
"with_you/internal/dto"
|
|
"with_you/internal/model"
|
|
"with_you/internal/pkg/cursor"
|
|
"with_you/internal/repository"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type TradeService interface {
|
|
Create(ctx context.Context, userID string, req dto.CreateTradeItemRequest) (*model.TradeItem, error)
|
|
GetByID(ctx context.Context, id string, currentUserID *string) (*dto.TradeItemDetailResponse, error)
|
|
Update(ctx context.Context, userID string, id string, req dto.UpdateTradeItemRequest) error
|
|
Delete(ctx context.Context, userID string, id string) error
|
|
UpdateStatus(ctx context.Context, userID string, id string, status model.TradeItemStatus) error
|
|
List(ctx context.Context, tradeType *model.TradeType, category *model.TradeCategory, cursorStr string, pageSize int, currentUserID *string) (*dto.TradeCursorPageResponse, error)
|
|
Search(ctx context.Context, keyword string, tradeType *model.TradeType, category *model.TradeCategory, cursorStr string, pageSize int, currentUserID *string) (*dto.TradeCursorPageResponse, error)
|
|
RecordView(ctx context.Context, id string) error
|
|
Favorite(ctx context.Context, userID string, id string) error
|
|
Unfavorite(ctx context.Context, userID string, id string) error
|
|
}
|
|
|
|
type tradeService struct {
|
|
tradeRepo repository.TradeRepository
|
|
}
|
|
|
|
func NewTradeService(tradeRepo repository.TradeRepository) TradeService {
|
|
return &tradeService{tradeRepo: tradeRepo}
|
|
}
|
|
|
|
func (s *tradeService) Create(ctx context.Context, userID string, req dto.CreateTradeItemRequest) (*model.TradeItem, error) {
|
|
item := &model.TradeItem{
|
|
UserID: userID,
|
|
TradeType: model.TradeType(req.TradeType),
|
|
Category: model.TradeCategory(req.Category),
|
|
Title: req.Title,
|
|
Content: req.Content,
|
|
Segments: req.Segments,
|
|
Price: req.Price,
|
|
Condition: req.Condition,
|
|
Status: model.TradeItemActive,
|
|
}
|
|
if item.Content == "" {
|
|
item.Content = item.Title
|
|
}
|
|
|
|
images := req.Images
|
|
if images == nil {
|
|
images = []string{}
|
|
}
|
|
if err := s.tradeRepo.Create(ctx, item, images); err != nil {
|
|
return nil, fmt.Errorf("create trade item: %w", err)
|
|
}
|
|
return item, nil
|
|
}
|
|
|
|
func (s *tradeService) GetByID(ctx context.Context, id string, currentUserID *string) (*dto.TradeItemDetailResponse, error) {
|
|
item, err := s.tradeRepo.GetByID(ctx, id)
|
|
if err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, fmt.Errorf("trade item not found")
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
isFavorited := false
|
|
if currentUserID != nil {
|
|
fav, err := s.tradeRepo.IsFavorited(ctx, id, *currentUserID)
|
|
if err == nil {
|
|
isFavorited = fav
|
|
}
|
|
}
|
|
|
|
_ = s.tradeRepo.IncrementViews(ctx, id)
|
|
|
|
return dto.ConvertTradeItemToDetailResponse(item, isFavorited), nil
|
|
}
|
|
|
|
func (s *tradeService) Update(ctx context.Context, userID string, id string, req dto.UpdateTradeItemRequest) error {
|
|
item, err := s.tradeRepo.GetByID(ctx, id)
|
|
if err != nil {
|
|
return fmt.Errorf("trade item not found")
|
|
}
|
|
if item.UserID != userID {
|
|
return fmt.Errorf("not authorized")
|
|
}
|
|
|
|
if req.TradeType != nil {
|
|
item.TradeType = model.TradeType(*req.TradeType)
|
|
}
|
|
if req.Category != nil {
|
|
item.Category = model.TradeCategory(*req.Category)
|
|
}
|
|
if req.Title != nil {
|
|
item.Title = *req.Title
|
|
}
|
|
if req.Content != nil {
|
|
item.Content = *req.Content
|
|
}
|
|
if req.Segments != nil {
|
|
item.Segments = req.Segments
|
|
}
|
|
if req.Price != nil {
|
|
item.Price = req.Price
|
|
}
|
|
if req.Condition != nil {
|
|
item.Condition = *req.Condition
|
|
}
|
|
item.UpdatedAt = time.Now()
|
|
|
|
if req.Images != nil {
|
|
return s.tradeRepo.UpdateWithImages(ctx, item, &req.Images)
|
|
}
|
|
return s.tradeRepo.Update(ctx, item)
|
|
}
|
|
|
|
func (s *tradeService) Delete(ctx context.Context, userID string, id string) error {
|
|
item, err := s.tradeRepo.GetByID(ctx, id)
|
|
if err != nil {
|
|
return fmt.Errorf("trade item not found")
|
|
}
|
|
if item.UserID != userID {
|
|
return fmt.Errorf("not authorized")
|
|
}
|
|
return s.tradeRepo.Delete(ctx, id)
|
|
}
|
|
|
|
func (s *tradeService) UpdateStatus(ctx context.Context, userID string, id string, status model.TradeItemStatus) error {
|
|
item, err := s.tradeRepo.GetByID(ctx, id)
|
|
if err != nil {
|
|
return fmt.Errorf("trade item not found")
|
|
}
|
|
if item.UserID != userID {
|
|
return fmt.Errorf("not authorized")
|
|
}
|
|
return s.tradeRepo.UpdateStatus(ctx, id, status)
|
|
}
|
|
|
|
func (s *tradeService) List(ctx context.Context, tradeType *model.TradeType, category *model.TradeCategory, cursorStr string, pageSize int, currentUserID *string) (*dto.TradeCursorPageResponse, error) {
|
|
req := cursor.NewPageRequest(cursorStr, cursor.Forward, pageSize)
|
|
result, err := s.tradeRepo.ListByCursor(ctx, tradeType, category, nil, req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return s.buildCursorResponse(ctx, result, currentUserID)
|
|
}
|
|
|
|
func (s *tradeService) Search(ctx context.Context, keyword string, tradeType *model.TradeType, category *model.TradeCategory, cursorStr string, pageSize int, currentUserID *string) (*dto.TradeCursorPageResponse, error) {
|
|
req := cursor.NewPageRequest(cursorStr, cursor.Forward, pageSize)
|
|
result, err := s.tradeRepo.SearchByCursor(ctx, keyword, tradeType, category, req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return s.buildCursorResponse(ctx, result, currentUserID)
|
|
}
|
|
|
|
func (s *tradeService) buildCursorResponse(ctx context.Context, result *cursor.CursorPageResult[*model.TradeItem], currentUserID *string) (*dto.TradeCursorPageResponse, error) {
|
|
favoriteMap := make(map[string]bool)
|
|
if currentUserID != nil && len(result.Items) > 0 {
|
|
ids := make([]string, 0, len(result.Items))
|
|
for _, item := range result.Items {
|
|
ids = append(ids, item.ID)
|
|
}
|
|
fm, err := s.tradeRepo.IsFavoritedBatch(ctx, ids, *currentUserID)
|
|
if err == nil {
|
|
favoriteMap = fm
|
|
}
|
|
}
|
|
|
|
resp := &dto.TradeCursorPageResponse{
|
|
Items: dto.ConvertTradeItemsToResponse(result.Items, favoriteMap),
|
|
NextCursor: result.NextCursor,
|
|
PrevCursor: result.PrevCursor,
|
|
HasMore: result.HasMore,
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
func (s *tradeService) RecordView(ctx context.Context, id string) error {
|
|
return s.tradeRepo.IncrementViews(ctx, id)
|
|
}
|
|
|
|
func (s *tradeService) Favorite(ctx context.Context, userID string, id string) error {
|
|
_, err := s.tradeRepo.GetByID(ctx, id)
|
|
if err != nil {
|
|
return fmt.Errorf("trade item not found")
|
|
}
|
|
exists, err := s.tradeRepo.IsFavorited(ctx, id, userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if exists {
|
|
return nil
|
|
}
|
|
if err := s.tradeRepo.CreateFavorite(ctx, id, userID); err != nil {
|
|
return err
|
|
}
|
|
_ = s.tradeRepo.IncrementFavorites(ctx, id)
|
|
return nil
|
|
}
|
|
|
|
func (s *tradeService) Unfavorite(ctx context.Context, userID string, id string) error {
|
|
exists, err := s.tradeRepo.IsFavorited(ctx, id, userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !exists {
|
|
return nil
|
|
}
|
|
if err := s.tradeRepo.DeleteFavorite(ctx, id, userID); err != nil {
|
|
return err
|
|
}
|
|
_ = s.tradeRepo.DecrementFavorites(ctx, id)
|
|
return nil
|
|
} |