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,201 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"dating-app/internal/dto"
|
||||
"dating-app/internal/models"
|
||||
"dating-app/internal/repository"
|
||||
)
|
||||
|
||||
var ErrUserNotOnboarded = errors.New("کاربر هنوز آنبوردینگ را تکمیل نکرده است")
|
||||
|
||||
type AdminService struct {
|
||||
optionRepo *repository.OptionRepository
|
||||
questionRepo *repository.QuestionRepository
|
||||
userRepo *repository.UserRepository
|
||||
}
|
||||
|
||||
func NewAdminService(
|
||||
optionRepo *repository.OptionRepository,
|
||||
questionRepo *repository.QuestionRepository,
|
||||
userRepo *repository.UserRepository,
|
||||
) *AdminService {
|
||||
return &AdminService{optionRepo: optionRepo, questionRepo: questionRepo, userRepo: userRepo}
|
||||
}
|
||||
|
||||
// ---------------- بررسی و تایید کاربران ----------------
|
||||
|
||||
// GetUser یک کاربر رو برای نمایش به ادمین (بررسی درخواست) برمیگردونه
|
||||
func (s *AdminService) GetUser(id uint) (*models.User, error) {
|
||||
return s.userRepo.FindByID(id)
|
||||
}
|
||||
|
||||
// ListPendingUsers کاربرانی که آنبوردینگ رو تکمیل کردن و منتظر بررسیاند
|
||||
func (s *AdminService) ListPendingUsers() ([]models.User, error) {
|
||||
return s.userRepo.ListPendingApproval()
|
||||
}
|
||||
|
||||
// ApproveUser کاربر رو تایید میکنه تا بتونه وارد صفحهی دوستیابی بشه
|
||||
func (s *AdminService) ApproveUser(id uint) (*models.User, error) {
|
||||
user, err := s.userRepo.FindByID(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !user.IsOnboarded {
|
||||
return nil, ErrUserNotOnboarded
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
updates := map[string]interface{}{
|
||||
"approval_status": models.ApprovalApproved,
|
||||
"rejection_reason": nil,
|
||||
"reviewed_at": now,
|
||||
}
|
||||
if err := s.userRepo.UpdateFields(user, updates); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user.ApprovalStatus = models.ApprovalApproved
|
||||
user.RejectionReason = nil
|
||||
user.ReviewedAt = &now
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// RejectUser درخواست عضویت کاربر رو با یک دلیل مشخص رد میکنه
|
||||
func (s *AdminService) RejectUser(id uint, reason string) (*models.User, error) {
|
||||
user, err := s.userRepo.FindByID(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !user.IsOnboarded {
|
||||
return nil, ErrUserNotOnboarded
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
updates := map[string]interface{}{
|
||||
"approval_status": models.ApprovalRejected,
|
||||
"rejection_reason": reason,
|
||||
"reviewed_at": now,
|
||||
}
|
||||
if err := s.userRepo.UpdateFields(user, updates); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user.ApprovalStatus = models.ApprovalRejected
|
||||
user.RejectionReason = &reason
|
||||
user.ReviewedAt = &now
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// ---------------- دستهها و گزینهها ----------------
|
||||
|
||||
func (s *AdminService) GetCategory(key models.CategoryKey) (*models.Category, error) {
|
||||
return s.optionRepo.GetCategoryByKey(key)
|
||||
}
|
||||
|
||||
func (s *AdminService) UpdateCategory(key models.CategoryKey, req dto.UpdateCategoryRequest) (*models.Category, error) {
|
||||
cat, err := s.optionRepo.GetCategoryByKey(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if req.Title != nil {
|
||||
cat.Title = *req.Title
|
||||
}
|
||||
if req.MinSelect != nil {
|
||||
cat.MinSelect = *req.MinSelect
|
||||
}
|
||||
if req.MaxSelect != nil {
|
||||
cat.MaxSelect = *req.MaxSelect
|
||||
}
|
||||
if err := s.optionRepo.UpdateCategory(cat); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cat, nil
|
||||
}
|
||||
|
||||
func (s *AdminService) ListOptions(key models.CategoryKey) ([]models.Option, error) {
|
||||
return s.optionRepo.ListOptionsByCategoryKeyAdmin(key)
|
||||
}
|
||||
|
||||
func (s *AdminService) CreateOption(key models.CategoryKey, req dto.CreateOptionRequest) (*models.Option, error) {
|
||||
cat, err := s.optionRepo.GetCategoryByKey(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opt := &models.Option{
|
||||
CategoryID: cat.ID,
|
||||
Title: req.Title,
|
||||
SortOrder: req.SortOrder,
|
||||
IsActive: true,
|
||||
}
|
||||
if err := s.optionRepo.CreateOption(opt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return opt, nil
|
||||
}
|
||||
|
||||
func (s *AdminService) UpdateOption(id uint, req dto.UpdateOptionRequest) (*models.Option, error) {
|
||||
opt, err := s.optionRepo.FindOptionByID(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if req.Title != nil {
|
||||
opt.Title = *req.Title
|
||||
}
|
||||
if req.SortOrder != nil {
|
||||
opt.SortOrder = *req.SortOrder
|
||||
}
|
||||
if req.IsActive != nil {
|
||||
opt.IsActive = *req.IsActive
|
||||
}
|
||||
if err := s.optionRepo.UpdateOption(opt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return opt, nil
|
||||
}
|
||||
|
||||
func (s *AdminService) DeleteOption(id uint) error {
|
||||
return s.optionRepo.DeleteOption(id)
|
||||
}
|
||||
|
||||
// ---------------- سوالات پروفایل ----------------
|
||||
|
||||
func (s *AdminService) ListQuestions() ([]models.ProfileQuestion, error) {
|
||||
return s.questionRepo.ListAllAdmin()
|
||||
}
|
||||
|
||||
func (s *AdminService) CreateQuestion(req dto.CreateProfileQuestionRequest) (*models.ProfileQuestion, error) {
|
||||
q := &models.ProfileQuestion{
|
||||
Text: req.Text,
|
||||
SortOrder: req.SortOrder,
|
||||
IsActive: true,
|
||||
}
|
||||
if err := s.questionRepo.Create(q); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func (s *AdminService) UpdateQuestion(id uint, req dto.UpdateProfileQuestionRequest) (*models.ProfileQuestion, error) {
|
||||
q, err := s.questionRepo.FindByID(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if req.Text != nil {
|
||||
q.Text = *req.Text
|
||||
}
|
||||
if req.SortOrder != nil {
|
||||
q.SortOrder = *req.SortOrder
|
||||
}
|
||||
if req.IsActive != nil {
|
||||
q.IsActive = *req.IsActive
|
||||
}
|
||||
if err := s.questionRepo.Update(q); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func (s *AdminService) DeleteQuestion(id uint) error {
|
||||
return s.questionRepo.Delete(id)
|
||||
}
|
||||
Reference in New Issue
Block a user