minimal registeration implementation
This commit is contained in:
parent
19ac718526
commit
6002b594c6
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
|
|
@ -20,4 +20,5 @@
|
|||
"**/internal/ports/**/*.go": "${filename}.ports",
|
||||
"**/internal/web_server/handlers/**/*.go": "${filename}.handlers",
|
||||
},
|
||||
"makefile.configureOnOpen": false,
|
||||
}
|
||||
|
|
@ -5,6 +5,13 @@ FROM users
|
|||
WHERE user_name = $1
|
||||
LIMIT 1;
|
||||
|
||||
-- name: IsProfileCompleted :one
|
||||
SELECT
|
||||
CASE WHEN profile_completed = true THEN true ELSE false END AS is_pending
|
||||
FROM users
|
||||
WHERE id = $1
|
||||
LIMIT 1;
|
||||
|
||||
-- name: IsUserNameUnique :one
|
||||
SELECT
|
||||
CASE WHEN COUNT(*) = 0 THEN true ELSE false END AS is_unique
|
||||
|
|
|
|||
|
|
@ -652,6 +652,21 @@ func (q *Queries) GetUserByUserName(ctx context.Context, userName string) (GetUs
|
|||
return i, err
|
||||
}
|
||||
|
||||
const IsProfileCompleted = `-- name: IsProfileCompleted :one
|
||||
SELECT
|
||||
CASE WHEN profile_completed = true THEN true ELSE false END AS is_pending
|
||||
FROM users
|
||||
WHERE id = $1
|
||||
LIMIT 1
|
||||
`
|
||||
|
||||
func (q *Queries) IsProfileCompleted(ctx context.Context, id int64) (bool, error) {
|
||||
row := q.db.QueryRow(ctx, IsProfileCompleted, id)
|
||||
var is_pending bool
|
||||
err := row.Scan(&is_pending)
|
||||
return is_pending, err
|
||||
}
|
||||
|
||||
const IsUserNameUnique = `-- name: IsUserNameUnique :one
|
||||
SELECT
|
||||
CASE WHEN COUNT(*) = 0 THEN true ELSE false END AS is_unique
|
||||
|
|
|
|||
|
|
@ -125,18 +125,18 @@ type RegisterUserReq struct {
|
|||
|
||||
OtpMedium OtpMedium `json:"otp_medium"`
|
||||
|
||||
NickName string `json:"nick_name,omitempty"`
|
||||
Occupation string `json:"occupation,omitempty"`
|
||||
LearningGoal string `json:"learning_goal,omitempty"`
|
||||
LanguageGoal string `json:"language_goal,omitempty"`
|
||||
LanguageChallange string `json:"language_challange,omitempty"`
|
||||
FavoutiteTopic string `json:"favoutite_topic,omitempty"`
|
||||
// NickName string `json:"nick_name,omitempty"`
|
||||
// Occupation string `json:"occupation,omitempty"`
|
||||
// LearningGoal string `json:"learning_goal,omitempty"`
|
||||
// LanguageGoal string `json:"language_goal,omitempty"`
|
||||
// LanguageChallange string `json:"language_challange,omitempty"`
|
||||
// FavoutiteTopic string `json:"favoutite_topic,omitempty"`
|
||||
|
||||
Age int `json:"age,omitempty"`
|
||||
EducationLevel string `json:"education_level,omitempty"`
|
||||
Country string `json:"country,omitempty"`
|
||||
Region string `json:"region,omitempty"`
|
||||
PreferredLanguage string `json:"preferred_language,omitempty"`
|
||||
// Age int `json:"age,omitempty"`
|
||||
// EducationLevel string `json:"education_level,omitempty"`
|
||||
// Country string `json:"country,omitempty"`
|
||||
// Region string `json:"region,omitempty"`
|
||||
// PreferredLanguage string `json:"preferred_language,omitempty"`
|
||||
}
|
||||
|
||||
type CreateUserReq struct {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
)
|
||||
|
||||
type UserStore interface {
|
||||
IsProfileCompleted(ctx context.Context, userId int64) (bool, error)
|
||||
UpdateUserStatus(ctx context.Context, user domain.UpdateUserReq) error
|
||||
// GetCorrectOptionForQuestion(
|
||||
// ctx context.Context,
|
||||
|
|
|
|||
|
|
@ -16,6 +16,17 @@ import (
|
|||
|
||||
func NewUserStore(s *Store) ports.UserStore { return s }
|
||||
|
||||
func (s *Store) IsProfileCompleted(ctx context.Context, userId int64) (bool, error) {
|
||||
IsProfileCompleted, err := s.queries.IsProfileCompleted(ctx, userId)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return false, authentication.ErrUserNotFound
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
return IsProfileCompleted, nil
|
||||
}
|
||||
|
||||
func (s *Store) UpdateUserKnowledgeLevel(ctx context.Context, userID int64, knowledgeLevel string) error {
|
||||
return s.queries.UpdateUserKnowledgeLevel(ctx, dbgen.UpdateUserKnowledgeLevelParams{
|
||||
ID: userID,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
)
|
||||
|
||||
type UserStore interface {
|
||||
IsProfileCompleted(ctx context.Context, userId int64) (bool, error)
|
||||
UpdateUserKnowledgeLevel(ctx context.Context, userID int64, knowledgeLevel string) error
|
||||
IsUserPending(ctx context.Context, userName string) (bool, error)
|
||||
GetUserByUserName(
|
||||
|
|
|
|||
|
|
@ -63,21 +63,21 @@ func (s *Service) RegisterUser(ctx context.Context, registerReq domain.RegisterU
|
|||
Role: domain.RoleStudent,
|
||||
EmailVerified: false,
|
||||
PhoneVerified: false,
|
||||
EducationLevel: registerReq.EducationLevel,
|
||||
Age: registerReq.Age,
|
||||
Country: registerReq.Country,
|
||||
Region: registerReq.Region,
|
||||
// EducationLevel: registerReq.EducationLevel,
|
||||
// Age: registerReq.Age,
|
||||
// Country: registerReq.Country,
|
||||
// Region: registerReq.Region,
|
||||
Status: domain.UserStatusPending,
|
||||
ProfileCompleted: false,
|
||||
PreferredLanguage: registerReq.PreferredLanguage,
|
||||
// PreferredLanguage: registerReq.PreferredLanguage,
|
||||
|
||||
// Optional fields
|
||||
NickName: registerReq.NickName,
|
||||
Occupation: registerReq.Occupation,
|
||||
LearningGoal: registerReq.LearningGoal,
|
||||
LanguageGoal: registerReq.LanguageGoal,
|
||||
LanguageChallange: registerReq.LanguageChallange,
|
||||
FavoutiteTopic: registerReq.FavoutiteTopic,
|
||||
// NickName: registerReq.NickName,
|
||||
// Occupation: registerReq.Occupation,
|
||||
// LearningGoal: registerReq.LearningGoal,
|
||||
// LanguageGoal: registerReq.LanguageGoal,
|
||||
// LanguageChallange: registerReq.LanguageChallange,
|
||||
// FavoutiteTopic: registerReq.FavoutiteTopic,
|
||||
// ProfilePictureURL: registerReq.ProfilePictureURL,
|
||||
|
||||
CreatedAt: time.Now(),
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@ func (s *Service) IsUserPending(ctx context.Context, userName string) (bool, err
|
|||
return s.userStore.IsUserPending(ctx, userName)
|
||||
}
|
||||
|
||||
func (s *Service) IsProfileCompleted(ctx context.Context, userId int64) (bool, error) {
|
||||
return s.userStore.IsProfileCompleted(ctx, userId)
|
||||
}
|
||||
|
||||
func (s *Service) IsUserNameUnique(ctx context.Context, userName string) (bool, error) {
|
||||
return s.userStore.IsUserNameUnique(ctx, userName)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,58 @@ import (
|
|||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// CheckProfileCompleted godoc
|
||||
// @Summary Check if user profile is completed
|
||||
// @Description Returns whether the specified user's profile is completed
|
||||
// @Tags user
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param user_id path int true "User ID"
|
||||
// @Success 200 {object} domain.Response
|
||||
// @Failure 400 {object} domain.ErrorResponse
|
||||
// @Failure 404 {object} domain.ErrorResponse
|
||||
// @Failure 500 {object} domain.ErrorResponse
|
||||
// @Router /api/v1/user/{user_id}/is-profile-completed [get]
|
||||
func (h *Handler) CheckProfileCompleted(c *fiber.Ctx) error {
|
||||
userIDParam := c.Params("user_id")
|
||||
if userIDParam == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
||||
Message: "Invalid user id",
|
||||
Error: "User id cannot be empty",
|
||||
})
|
||||
}
|
||||
|
||||
userID, err := strconv.ParseInt(userIDParam, 10, 64)
|
||||
if err != nil || userID <= 0 {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
||||
Message: "Invalid user id",
|
||||
Error: "User id must be a valid positive integer",
|
||||
})
|
||||
}
|
||||
|
||||
isCompleted, err := h.userSvc.IsProfileCompleted(c.Context(), userID)
|
||||
if err != nil {
|
||||
if errors.Is(err, authentication.ErrUserNotFound) {
|
||||
return c.Status(fiber.StatusNotFound).JSON(domain.ErrorResponse{
|
||||
Message: "User not found",
|
||||
Error: err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
||||
Message: "Failed to check profile completion status",
|
||||
Error: err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(domain.Response{
|
||||
Message: "Profile completion status fetched successfully",
|
||||
Data: map[string]bool{
|
||||
"is_profile_completed": isCompleted,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateUser godoc
|
||||
// @Summary Update user profile
|
||||
// @Description Updates user profile information (partial updates supported)
|
||||
|
|
@ -741,26 +793,26 @@ func (h *Handler) RegisterUser(c *fiber.Ctx) error {
|
|||
}
|
||||
|
||||
user := domain.RegisterUserReq{
|
||||
FirstName: req.FirstName,
|
||||
LastName: req.LastName,
|
||||
UserName: req.UserName,
|
||||
Email: req.Email,
|
||||
PhoneNumber: req.PhoneNumber,
|
||||
Password: req.Password,
|
||||
OtpMedium: domain.OtpMediumEmail,
|
||||
Role: string(domain.RoleStudent),
|
||||
Age: req.Age,
|
||||
EducationLevel: req.EducationLevel,
|
||||
Country: req.Country,
|
||||
Region: req.Region,
|
||||
PreferredLanguage: req.PreferredLanguage,
|
||||
FirstName: req.FirstName,
|
||||
LastName: req.LastName,
|
||||
UserName: req.UserName,
|
||||
Email: req.Email,
|
||||
PhoneNumber: req.PhoneNumber,
|
||||
Password: req.Password,
|
||||
OtpMedium: domain.OtpMediumEmail,
|
||||
// Role: string(domain.RoleStudent),
|
||||
// Age: req.Age,
|
||||
// EducationLevel: req.EducationLevel,
|
||||
// Country: req.Country,
|
||||
// Region: req.Region,
|
||||
// PreferredLanguage: req.PreferredLanguage,
|
||||
|
||||
NickName: req.NickName,
|
||||
Occupation: req.Occupation,
|
||||
LearningGoal: req.LearningGoal,
|
||||
LanguageGoal: req.LanguageGoal,
|
||||
LanguageChallange: req.LanguageChallange,
|
||||
FavoutiteTopic: req.FavoutiteTopic,
|
||||
// NickName: req.NickName,
|
||||
// Occupation: req.Occupation,
|
||||
// LearningGoal: req.LearningGoal,
|
||||
// LanguageGoal: req.LanguageGoal,
|
||||
// LanguageChallange: req.LanguageChallange,
|
||||
// FavoutiteTopic: req.FavoutiteTopic,
|
||||
}
|
||||
|
||||
medium, err := getMedium(req.Email, req.PhoneNumber)
|
||||
|
|
@ -803,25 +855,25 @@ func (h *Handler) RegisterUser(c *fiber.Ctx) error {
|
|||
|
||||
func MapRegisterReqToUser(req domain.RegisterUserReq) domain.User {
|
||||
return domain.User{
|
||||
FirstName: req.FirstName,
|
||||
LastName: req.LastName,
|
||||
UserName: req.UserName,
|
||||
Email: req.Email,
|
||||
PhoneNumber: req.PhoneNumber,
|
||||
Password: []byte(req.Password), // or hashed password
|
||||
Role: domain.Role(req.Role),
|
||||
Age: req.Age,
|
||||
EducationLevel: req.EducationLevel,
|
||||
Country: req.Country,
|
||||
Region: req.Region,
|
||||
PreferredLanguage: req.PreferredLanguage,
|
||||
FirstName: req.FirstName,
|
||||
LastName: req.LastName,
|
||||
UserName: req.UserName,
|
||||
Email: req.Email,
|
||||
PhoneNumber: req.PhoneNumber,
|
||||
Password: []byte(req.Password), // or hashed password
|
||||
Role: domain.Role(req.Role),
|
||||
// Age: req.Age,
|
||||
// EducationLevel: req.EducationLevel,
|
||||
// Country: req.Country,
|
||||
// Region: req.Region,
|
||||
// PreferredLanguage: req.PreferredLanguage,
|
||||
|
||||
NickName: req.NickName,
|
||||
Occupation: req.Occupation,
|
||||
LearningGoal: req.LearningGoal,
|
||||
LanguageGoal: req.LanguageGoal,
|
||||
LanguageChallange: req.LanguageChallange,
|
||||
FavoutiteTopic: req.FavoutiteTopic,
|
||||
// NickName: req.NickName,
|
||||
// Occupation: req.Occupation,
|
||||
// LearningGoal: req.LearningGoal,
|
||||
// LanguageGoal: req.LanguageGoal,
|
||||
// LanguageChallange: req.LanguageChallange,
|
||||
// FavoutiteTopic: req.FavoutiteTopic,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -194,6 +194,7 @@ func (a *App) initAppRoutes() {
|
|||
// groupV1.Get("/arifpay/payment-methods", a.authMiddleware, h.GetArifpayPaymentMethodsHandler
|
||||
|
||||
// User Routes
|
||||
groupV1.Get("/user/:user_id/is-profile-completed", a.authMiddleware, h.CheckProfileCompleted)
|
||||
groupV1.Get("/users", a.authMiddleware, h.GetAllUsers)
|
||||
groupV1.Put("/user", a.authMiddleware, h.UpdateUser)
|
||||
groupV1.Put("/user/knowledge-level", h.UpdateUserKnowledgeLevel)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user