2823fb45f5
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>
133 lines
4.1 KiB
Go
133 lines
4.1 KiB
Go
package database
|
|
|
|
import (
|
|
"log"
|
|
|
|
"gorm.io/driver/postgres"
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/logger"
|
|
|
|
"dating-app/internal/config"
|
|
"dating-app/internal/models"
|
|
)
|
|
|
|
// Connect به دیتابیس پستگرس وصل میشود
|
|
func Connect(cfg *config.Config) (*gorm.DB, error) {
|
|
logLevel := logger.Warn
|
|
if cfg.AppEnv == "development" {
|
|
logLevel = logger.Info
|
|
}
|
|
|
|
db, err := gorm.Open(postgres.Open(cfg.DSN()), &gorm.Config{
|
|
Logger: logger.Default.LogMode(logLevel),
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return db, nil
|
|
}
|
|
|
|
// AutoMigrate جدولهای مورد نیاز را میسازد/بهروزرسانی میکند
|
|
func AutoMigrate(db *gorm.DB) error {
|
|
return db.AutoMigrate(
|
|
&models.User{},
|
|
&models.Category{},
|
|
&models.Option{},
|
|
&models.UserOptionSelection{},
|
|
&models.ProfileQuestion{},
|
|
&models.UserProfileAnswer{},
|
|
&models.Photo{},
|
|
&models.Swipe{},
|
|
&models.Match{},
|
|
&models.Message{},
|
|
)
|
|
}
|
|
|
|
// SeedCategories دستههای ثابت لیستهای انتخابی را در صورت نبود میسازد.
|
|
// خودِ گزینههای داخل هر دسته (بهجز looking_for که صراحتاً در نیازمندی
|
|
// پروژه مشخص شده) باید از پنل ادمین اضافه شوند.
|
|
func SeedCategories(db *gorm.DB) error {
|
|
defaults := []models.Category{
|
|
{Key: models.CategoryEducationLevel, Title: "سطح تحصیلات", MinSelect: 1, MaxSelect: 1},
|
|
{Key: models.CategoryFieldOfStudy, Title: "رشته تحصیلی", MinSelect: 1, MaxSelect: 1},
|
|
{Key: models.CategoryOccupation, Title: "کارهایی که انجام میدهید", MinSelect: 1, MaxSelect: 0},
|
|
{Key: models.CategoryImportantInRelationship, Title: "برات توی یک رابطه مهمه", MinSelect: 3, MaxSelect: 3},
|
|
{Key: models.CategoryInterest, Title: "علاقهمندیها", MinSelect: 5, MaxSelect: 5},
|
|
{Key: models.CategoryLookingFor, Title: "دنبال چی میگردی", MinSelect: 1, MaxSelect: 1},
|
|
}
|
|
|
|
for _, c := range defaults {
|
|
var existing models.Category
|
|
err := db.Where("key = ?", c.Key).First(&existing).Error
|
|
if err == gorm.ErrRecordNotFound {
|
|
if err := db.Create(&c).Error; err != nil {
|
|
return err
|
|
}
|
|
log.Printf("دستهی «%s» ساخته شد", c.Title)
|
|
} else if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// گزینههای "دنبال چی میگردی" مطابق چیزی که در نیازمندی مشخص شده seed میشن
|
|
var lookingFor models.Category
|
|
if err := db.Where("key = ?", models.CategoryLookingFor).First(&lookingFor).Error; err == nil {
|
|
var count int64
|
|
db.Model(&models.Option{}).Where("category_id = ?", lookingFor.ID).Count(&count)
|
|
if count == 0 {
|
|
titles := []string{
|
|
"رابطه بلندمدت",
|
|
"همسر زندگی",
|
|
"قرارهای تفریحی",
|
|
"آشنایی با افراد جدید",
|
|
"ازدواج",
|
|
"دوست ساده",
|
|
}
|
|
for i, t := range titles {
|
|
db.Create(&models.Option{
|
|
CategoryID: lookingFor.ID,
|
|
Title: t,
|
|
SortOrder: i,
|
|
IsActive: true,
|
|
})
|
|
}
|
|
log.Println("گزینههای «دنبال چی میگردی» seed شدند")
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// BootstrapAdmin اگر شمارهای برای ادمین اولیه مشخص شده باشد،
|
|
// یک کاربر ادمین با آن شماره میسازد (در صورت نبود).
|
|
func BootstrapAdmin(db *gorm.DB, phone string) error {
|
|
if phone == "" {
|
|
return nil
|
|
}
|
|
var user models.User
|
|
err := db.Where("phone = ?", phone).First(&user).Error
|
|
if err == gorm.ErrRecordNotFound {
|
|
user = models.User{
|
|
Phone: phone,
|
|
State: models.UserStateActive,
|
|
IsAdmin: true,
|
|
IsActive: true,
|
|
ApprovalStatus: models.ApprovalApproved,
|
|
}
|
|
if err := db.Create(&user).Error; err != nil {
|
|
return err
|
|
}
|
|
log.Printf("کاربر ادمین اولیه با شماره %s ساخته شد", phone)
|
|
return nil
|
|
} else if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !user.IsAdmin {
|
|
user.IsAdmin = true
|
|
db.Save(&user)
|
|
log.Printf("کاربر %s به ادمین ارتقا یافت", phone)
|
|
}
|
|
return nil
|
|
}
|