Initial commit: dating app backend (Go/Gin/GORM/Postgres)
Phone+OTP auth, staged onboarding, admin approval workflow, and a full discovery/swipe/match/chat system with photo upload and approximate distance (haversine) based on user location. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"dating-app/internal/dto"
|
||||
"dating-app/internal/models"
|
||||
"dating-app/internal/repository"
|
||||
)
|
||||
|
||||
var ErrNotMatchMember = errors.New("این گفتگو مال تو نیست")
|
||||
|
||||
type ChatService struct {
|
||||
matchRepo *repository.MatchRepository
|
||||
messageRepo *repository.MessageRepository
|
||||
userRepo *repository.UserRepository
|
||||
photoRepo *repository.PhotoRepository
|
||||
}
|
||||
|
||||
func NewChatService(
|
||||
matchRepo *repository.MatchRepository,
|
||||
messageRepo *repository.MessageRepository,
|
||||
userRepo *repository.UserRepository,
|
||||
photoRepo *repository.PhotoRepository,
|
||||
) *ChatService {
|
||||
return &ChatService{
|
||||
matchRepo: matchRepo,
|
||||
messageRepo: messageRepo,
|
||||
userRepo: userRepo,
|
||||
photoRepo: photoRepo,
|
||||
}
|
||||
}
|
||||
|
||||
// ListMatches همهی مچهای کاربر رو همراه با اطلاعات طرف مقابل و آخرین پیام برمیگردونه
|
||||
func (s *ChatService) ListMatches(userID uint) ([]dto.MatchView, error) {
|
||||
matches, err := s.matchRepo.ListByUser(userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
views := make([]dto.MatchView, 0, len(matches))
|
||||
for _, m := range matches {
|
||||
otherID := repository.OtherUserID(&m, userID)
|
||||
other, err := s.userRepo.FindByID(otherID)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
photos, _ := s.photoRepo.ListByUser(otherID)
|
||||
urls := make([]string, len(photos))
|
||||
for i, p := range photos {
|
||||
urls[i] = p.URL
|
||||
}
|
||||
|
||||
view := dto.MatchView{
|
||||
ID: m.ID,
|
||||
UserID: other.ID,
|
||||
FirstName: other.FirstName,
|
||||
Photos: urls,
|
||||
CreatedAt: m.CreatedAt.Format(time.RFC3339),
|
||||
}
|
||||
if last, err := s.messageRepo.LastMessage(m.ID); err == nil {
|
||||
text := last.Text
|
||||
at := last.CreatedAt.Format(time.RFC3339)
|
||||
view.LastMessage = &text
|
||||
view.LastAt = &at
|
||||
}
|
||||
views = append(views, view)
|
||||
}
|
||||
return views, nil
|
||||
}
|
||||
|
||||
func (s *ChatService) getAuthorizedMatch(userID, matchID uint) (uint, error) {
|
||||
match, err := s.matchRepo.FindByID(matchID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if !repository.IsMember(match, userID) {
|
||||
return 0, ErrNotMatchMember
|
||||
}
|
||||
return match.ID, nil
|
||||
}
|
||||
|
||||
// ListMessages پیامهای یک مچ رو برمیگردونه؛ فقط اگه کاربر عضو اون مچ باشه.
|
||||
func (s *ChatService) ListMessages(userID, matchID uint) ([]dto.MessageView, error) {
|
||||
if _, err := s.getAuthorizedMatch(userID, matchID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
messages, err := s.messageRepo.ListByMatch(matchID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
views := make([]dto.MessageView, 0, len(messages))
|
||||
for _, m := range messages {
|
||||
views = append(views, dto.MessageView{
|
||||
ID: m.ID,
|
||||
MatchID: m.MatchID,
|
||||
SenderID: m.SenderID,
|
||||
Text: m.Text,
|
||||
CreatedAt: m.CreatedAt.Format(time.RFC3339),
|
||||
IsMine: m.SenderID == userID,
|
||||
})
|
||||
}
|
||||
return views, nil
|
||||
}
|
||||
|
||||
// SendMessage یک پیام جدید توی یک مچ ثبت میکنه؛ فقط اگه کاربر عضو اون مچ باشه.
|
||||
func (s *ChatService) SendMessage(userID, matchID uint, text string) (*dto.MessageView, error) {
|
||||
if _, err := s.getAuthorizedMatch(userID, matchID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msg := &models.Message{MatchID: matchID, SenderID: userID, Text: text}
|
||||
if err := s.messageRepo.Create(msg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dto.MessageView{
|
||||
ID: msg.ID,
|
||||
MatchID: msg.MatchID,
|
||||
SenderID: msg.SenderID,
|
||||
Text: msg.Text,
|
||||
CreatedAt: msg.CreatedAt.Format(time.RFC3339),
|
||||
IsMine: true,
|
||||
}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user