2026-09-15 23:23:47 +03:30
|
|
|
package handler
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"errors"
|
|
|
|
|
"net/http"
|
|
|
|
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
|
|
|
|
|
|
"dating-app/internal/dto"
|
|
|
|
|
"dating-app/internal/models"
|
|
|
|
|
"dating-app/internal/repository"
|
|
|
|
|
"dating-app/internal/service"
|
|
|
|
|
"dating-app/internal/utils"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type OnboardingHandler struct {
|
|
|
|
|
onboardingService *service.OnboardingService
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewOnboardingHandler(onboardingService *service.OnboardingService) *OnboardingHandler {
|
|
|
|
|
return &OnboardingHandler{onboardingService: onboardingService}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (h *OnboardingHandler) handleStepError(c *gin.Context, err error) {
|
|
|
|
|
switch {
|
|
|
|
|
case errors.Is(err, service.ErrStepOutOfOrder):
|
|
|
|
|
utils.Fail(c, http.StatusConflict, err.Error(), nil)
|
|
|
|
|
case errors.Is(err, service.ErrInvalidBirthDate),
|
|
|
|
|
errors.Is(err, service.ErrOptionsNotFound),
|
|
|
|
|
errors.Is(err, service.ErrQuestionsInvalid),
|
|
|
|
|
errors.Is(err, service.ErrDuplicateQuestion):
|
|
|
|
|
utils.Fail(c, http.StatusBadRequest, err.Error(), nil)
|
|
|
|
|
case errors.Is(err, repository.ErrCategoryNotFound):
|
|
|
|
|
utils.Fail(c, http.StatusInternalServerError, "دستهی موردنیاز در سیستم تعریف نشده است", nil)
|
|
|
|
|
case errors.Is(err, service.ErrSelectionCount):
|
|
|
|
|
utils.Fail(c, http.StatusBadRequest, err.Error(), nil)
|
|
|
|
|
default:
|
|
|
|
|
utils.Fail(c, http.StatusBadRequest, err.Error(), nil)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Status GET /onboarding/status
|
|
|
|
|
func (h *OnboardingHandler) Status(c *gin.Context) {
|
|
|
|
|
user, ok := currentUser(c)
|
|
|
|
|
if !ok {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
utils.Success(c, http.StatusOK, "", h.onboardingService.GetStatus(user))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// BasicInfo POST /onboarding/basic-info
|
|
|
|
|
func (h *OnboardingHandler) BasicInfo(c *gin.Context) {
|
|
|
|
|
user, ok := currentUser(c)
|
|
|
|
|
if !ok {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
var req dto.BasicInfoRequest
|
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
|
|
|
utils.Fail(c, http.StatusBadRequest, "ورودی نامعتبر است", err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if err := h.onboardingService.SetBasicInfo(user, req); err != nil {
|
|
|
|
|
h.handleStepError(c, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
utils.Success(c, http.StatusOK, "اطلاعات پایه ثبت شد", h.onboardingService.GetStatus(user))
|
2026-09-16 09:21:50 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Photos POST /onboarding/photos — تایید مرحلهی عکسها (خودِ آپلود از /profile/photos انجام میشه)
|
|
|
|
|
func (h *OnboardingHandler) Photos(c *gin.Context) {
|
|
|
|
|
user, ok := currentUser(c)
|
|
|
|
|
if !ok {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if err := h.onboardingService.ConfirmPhotos(user); err != nil {
|
|
|
|
|
h.handleStepError(c, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
utils.Success(c, http.StatusOK, "عکسها ثبت شد", h.onboardingService.GetStatus(user))
|
2026-09-15 23:23:47 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// BodyInfo POST /onboarding/body-info
|
|
|
|
|
func (h *OnboardingHandler) BodyInfo(c *gin.Context) {
|
|
|
|
|
user, ok := currentUser(c)
|
|
|
|
|
if !ok {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
var req dto.BodyInfoRequest
|
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
|
|
|
utils.Fail(c, http.StatusBadRequest, "ورودی نامعتبر است", err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if err := h.onboardingService.SetBodyInfo(user, req); err != nil {
|
|
|
|
|
h.handleStepError(c, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
utils.Success(c, http.StatusOK, "قد و وزن ثبت شد", h.onboardingService.GetStatus(user))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AvailableQuestions GET /onboarding/profile-questions
|
|
|
|
|
func (h *OnboardingHandler) AvailableQuestions(c *gin.Context) {
|
|
|
|
|
questions, err := h.onboardingService.GetAvailableQuestions()
|
|
|
|
|
if err != nil {
|
|
|
|
|
utils.Fail(c, http.StatusInternalServerError, "خطا در دریافت سوالات", nil)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
utils.Success(c, http.StatusOK, "", questions)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetProfileQuestions POST /onboarding/profile-questions
|
|
|
|
|
func (h *OnboardingHandler) SetProfileQuestions(c *gin.Context) {
|
|
|
|
|
user, ok := currentUser(c)
|
|
|
|
|
if !ok {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
var req dto.ProfileQuestionsRequest
|
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
|
|
|
utils.Fail(c, http.StatusBadRequest, "ورودی نامعتبر است (باید دقیقاً ۳ سوال با پاسخ ارسال شود)", err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if err := h.onboardingService.SetProfileQuestions(user, req); err != nil {
|
|
|
|
|
h.handleStepError(c, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
utils.Success(c, http.StatusOK, "پاسخها ثبت شد", h.onboardingService.GetStatus(user))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Education POST /onboarding/education
|
|
|
|
|
func (h *OnboardingHandler) Education(c *gin.Context) {
|
|
|
|
|
user, ok := currentUser(c)
|
|
|
|
|
if !ok {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
var req dto.EducationRequest
|
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
|
|
|
utils.Fail(c, http.StatusBadRequest, "ورودی نامعتبر است", err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if err := h.onboardingService.SetEducation(user, req); err != nil {
|
|
|
|
|
h.handleStepError(c, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
utils.Success(c, http.StatusOK, "اطلاعات تحصیلی ثبت شد", h.onboardingService.GetStatus(user))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Occupations POST /onboarding/occupations
|
|
|
|
|
func (h *OnboardingHandler) Occupations(c *gin.Context) {
|
|
|
|
|
user, ok := currentUser(c)
|
|
|
|
|
if !ok {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
var req dto.OptionSelectionRequest
|
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
|
|
|
utils.Fail(c, http.StatusBadRequest, "ورودی نامعتبر است", err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if err := h.onboardingService.SetOccupations(user, req.OptionIDs); err != nil {
|
|
|
|
|
h.handleStepError(c, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
utils.Success(c, http.StatusOK, "فعالیتها ثبت شد", h.onboardingService.GetStatus(user))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// RelationshipImportance POST /onboarding/relationship-importance
|
|
|
|
|
func (h *OnboardingHandler) RelationshipImportance(c *gin.Context) {
|
|
|
|
|
user, ok := currentUser(c)
|
|
|
|
|
if !ok {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
var req dto.OptionSelectionRequest
|
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
|
|
|
utils.Fail(c, http.StatusBadRequest, "ورودی نامعتبر است", err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if err := h.onboardingService.SetRelationshipImportance(user, req.OptionIDs); err != nil {
|
|
|
|
|
h.handleStepError(c, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
utils.Success(c, http.StatusOK, "موارد مهم در رابطه ثبت شد", h.onboardingService.GetStatus(user))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Interests POST /onboarding/interests
|
|
|
|
|
func (h *OnboardingHandler) Interests(c *gin.Context) {
|
|
|
|
|
user, ok := currentUser(c)
|
|
|
|
|
if !ok {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
var req dto.OptionSelectionRequest
|
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
|
|
|
utils.Fail(c, http.StatusBadRequest, "ورودی نامعتبر است", err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if err := h.onboardingService.SetInterests(user, req.OptionIDs); err != nil {
|
|
|
|
|
h.handleStepError(c, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
utils.Success(c, http.StatusOK, "علاقهمندیها ثبت شد", h.onboardingService.GetStatus(user))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// LookingFor POST /onboarding/looking-for
|
|
|
|
|
func (h *OnboardingHandler) LookingFor(c *gin.Context) {
|
|
|
|
|
user, ok := currentUser(c)
|
|
|
|
|
if !ok {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
var req dto.OptionSelectionRequest
|
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
|
|
|
utils.Fail(c, http.StatusBadRequest, "ورودی نامعتبر است", err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if err := h.onboardingService.SetLookingFor(user, req.OptionIDs); err != nil {
|
|
|
|
|
h.handleStepError(c, err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
utils.Success(c, http.StatusOK, "هدف شما ثبت شد", h.onboardingService.GetStatus(user))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Options GET /onboarding/options/:category
|
|
|
|
|
// category یکی از: education_level, field_of_study, occupation,
|
|
|
|
|
// important_in_relationship, interest, looking_for
|
|
|
|
|
func (h *OnboardingHandler) Options(c *gin.Context) {
|
|
|
|
|
key := models.CategoryKey(c.Param("category"))
|
|
|
|
|
valid := false
|
|
|
|
|
for _, k := range models.AllCategoryKeys {
|
|
|
|
|
if k == key {
|
|
|
|
|
valid = true
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if !valid {
|
|
|
|
|
utils.Fail(c, http.StatusNotFound, "دستهی نامعتبر است", nil)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
options, err := h.onboardingService.GetActiveOptions(key)
|
|
|
|
|
if err != nil {
|
|
|
|
|
utils.Fail(c, http.StatusInternalServerError, "خطا در دریافت گزینهها", nil)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
utils.Success(c, http.StatusOK, "", options)
|
|
|
|
|
}
|