Compare commits
1 Commits
Author | SHA1 | Date |
---|---|---|
|
094a147489 |
|
@ -0,0 +1,144 @@
|
||||||
|
package admin
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// Request DTOs
|
||||||
|
type GetPendingUsersRequest struct {
|
||||||
|
Role string `query:"role" validate:"omitempty,oneof=pengelola pengepul"`
|
||||||
|
Status string `query:"status" validate:"omitempty,oneof=awaiting_approval pending"`
|
||||||
|
Page int `query:"page" validate:"min=1"`
|
||||||
|
Limit int `query:"limit" validate:"min=1,max=100"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ApprovalActionRequest struct {
|
||||||
|
UserID string `json:"user_id" validate:"required,uuid"`
|
||||||
|
Action string `json:"action" validate:"required,oneof=approve reject"`
|
||||||
|
Notes string `json:"notes" validate:"omitempty,max=500"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BulkApprovalRequest struct {
|
||||||
|
UserIDs []string `json:"user_ids" validate:"required,min=1,max=50,dive,uuid"`
|
||||||
|
Action string `json:"action" validate:"required,oneof=approve reject"`
|
||||||
|
Notes string `json:"notes" validate:"omitempty,max=500"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response DTOs
|
||||||
|
type PendingUserResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Phone string `json:"phone"`
|
||||||
|
Email string `json:"email,omitempty"`
|
||||||
|
Role RoleInfo `json:"role"`
|
||||||
|
RegistrationStatus string `json:"registration_status"`
|
||||||
|
RegistrationProgress int8 `json:"registration_progress"`
|
||||||
|
SubmittedAt time.Time `json:"submitted_at"`
|
||||||
|
IdentityCard *IdentityCardInfo `json:"identity_card,omitempty"`
|
||||||
|
CompanyProfile *CompanyProfileInfo `json:"company_profile,omitempty"`
|
||||||
|
RegistrationStepInfo *RegistrationStepResponse `json:"step_info"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RoleInfo struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
RoleName string `json:"role_name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type IdentityCardInfo struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
IdentificationNumber string `json:"identification_number"`
|
||||||
|
Fullname string `json:"fullname"`
|
||||||
|
Placeofbirth string `json:"place_of_birth"`
|
||||||
|
Dateofbirth string `json:"date_of_birth"`
|
||||||
|
Gender string `json:"gender"`
|
||||||
|
BloodType string `json:"blood_type"`
|
||||||
|
Province string `json:"province"`
|
||||||
|
District string `json:"district"`
|
||||||
|
SubDistrict string `json:"sub_district"`
|
||||||
|
Village string `json:"village"`
|
||||||
|
PostalCode string `json:"postal_code"`
|
||||||
|
Religion string `json:"religion"`
|
||||||
|
Maritalstatus string `json:"marital_status"`
|
||||||
|
Job string `json:"job"`
|
||||||
|
Citizenship string `json:"citizenship"`
|
||||||
|
Validuntil string `json:"valid_until"`
|
||||||
|
Cardphoto string `json:"card_photo"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CompanyProfileInfo struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
CompanyName string `json:"company_name"`
|
||||||
|
CompanyAddress string `json:"company_address"`
|
||||||
|
CompanyPhone string `json:"company_phone"`
|
||||||
|
CompanyEmail string `json:"company_email"`
|
||||||
|
CompanyLogo string `json:"company_logo"`
|
||||||
|
CompanyWebsite string `json:"company_website"`
|
||||||
|
TaxID string `json:"tax_id"`
|
||||||
|
FoundedDate string `json:"founded_date"`
|
||||||
|
CompanyType string `json:"company_type"`
|
||||||
|
CompanyDescription string `json:"company_description"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RegistrationStepResponse struct {
|
||||||
|
Step int `json:"step"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
RequiresAdminApproval bool `json:"requires_admin_approval"`
|
||||||
|
IsAccessible bool `json:"is_accessible"`
|
||||||
|
IsCompleted bool `json:"is_completed"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PendingUsersListResponse struct {
|
||||||
|
Users []PendingUserResponse `json:"users"`
|
||||||
|
Pagination PaginationInfo `json:"pagination"`
|
||||||
|
Summary ApprovalSummary `json:"summary"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PaginationInfo struct {
|
||||||
|
Page int `json:"page"`
|
||||||
|
Limit int `json:"limit"`
|
||||||
|
TotalPages int `json:"total_pages"`
|
||||||
|
TotalRecords int64 `json:"total_records"`
|
||||||
|
HasNext bool `json:"has_next"`
|
||||||
|
HasPrev bool `json:"has_prev"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ApprovalSummary struct {
|
||||||
|
TotalPending int64 `json:"total_pending"`
|
||||||
|
PengelolaPending int64 `json:"pengelola_pending"`
|
||||||
|
PengepulPending int64 `json:"pengepul_pending"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ApprovalActionResponse struct {
|
||||||
|
UserID string `json:"user_id"`
|
||||||
|
Action string `json:"action"`
|
||||||
|
PreviousStatus string `json:"previous_status"`
|
||||||
|
NewStatus string `json:"new_status"`
|
||||||
|
ProcessedAt time.Time `json:"processed_at"`
|
||||||
|
ProcessedBy string `json:"processed_by"`
|
||||||
|
Notes string `json:"notes,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BulkApprovalResponse struct {
|
||||||
|
SuccessCount int `json:"success_count"`
|
||||||
|
FailureCount int `json:"failure_count"`
|
||||||
|
Results []ApprovalActionResponse `json:"results"`
|
||||||
|
Failures []ApprovalFailure `json:"failures,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ApprovalFailure struct {
|
||||||
|
UserID string `json:"user_id"`
|
||||||
|
Error string `json:"error"`
|
||||||
|
Reason string `json:"reason"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validation helper
|
||||||
|
func (r *GetPendingUsersRequest) SetDefaults() {
|
||||||
|
if r.Page <= 0 {
|
||||||
|
r.Page = 1
|
||||||
|
}
|
||||||
|
if r.Limit <= 0 {
|
||||||
|
r.Limit = 20
|
||||||
|
}
|
||||||
|
if r.Status == "" {
|
||||||
|
r.Status = "awaiting_approval"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,293 @@
|
||||||
|
// internal/admin/approval_handler.go
|
||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"rijig/middleware"
|
||||||
|
"rijig/utils"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ApprovalHandler struct {
|
||||||
|
service ApprovalService
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewApprovalHandler(service ApprovalService) *ApprovalHandler {
|
||||||
|
return &ApprovalHandler{
|
||||||
|
service: service,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPendingUsers menampilkan daftar pengguna yang menunggu persetujuan
|
||||||
|
// @Summary Get pending users for approval
|
||||||
|
// @Description Retrieve list of users (pengelola/pengepul) waiting for admin approval with filtering and pagination
|
||||||
|
// @Tags Admin - User Approval
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param role query string false "Filter by role" Enums(pengelola, pengepul)
|
||||||
|
// @Param status query string false "Filter by status" Enums(awaiting_approval, pending) default(awaiting_approval)
|
||||||
|
// @Param page query int false "Page number" default(1) minimum(1)
|
||||||
|
// @Param limit query int false "Items per page" default(20) minimum(1) maximum(100)
|
||||||
|
// @Success 200 {object} utils.Response{data=PendingUsersListResponse} "List of pending users"
|
||||||
|
// @Failure 400 {object} utils.Response "Bad request"
|
||||||
|
// @Failure 401 {object} utils.Response "Unauthorized"
|
||||||
|
// @Failure 403 {object} utils.Response "Forbidden - Admin role required"
|
||||||
|
// @Failure 500 {object} utils.Response "Internal server error"
|
||||||
|
// @Security Bearer
|
||||||
|
// @Router /admin/users/pending [get]
|
||||||
|
func (h *ApprovalHandler) GetPendingUsers(c *fiber.Ctx) error {
|
||||||
|
// Parse query parameters
|
||||||
|
var req GetPendingUsersRequest
|
||||||
|
if err := c.QueryParser(&req); err != nil {
|
||||||
|
return utils.BadRequest(c, "Invalid query parameters: "+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate request
|
||||||
|
// if err := h.validator.Struct(&req); err != nil {
|
||||||
|
// return utils.ResponseErrorData(c, fiber.StatusBadRequest, "Validation failed", err.Error())
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Call service
|
||||||
|
result, err := h.service.GetPendingUsers(c.Context(), &req)
|
||||||
|
if err != nil {
|
||||||
|
return utils.InternalServerError(c, "Failed to get pending users: "+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return utils.SuccessWithData(c, "Pending users retrieved successfully", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserApprovalDetails menampilkan detail lengkap pengguna untuk approval
|
||||||
|
// @Summary Get user approval details
|
||||||
|
// @Description Get detailed information of a specific user for approval decision
|
||||||
|
// @Tags Admin - User Approval
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param user_id path string true "User ID" format(uuid)
|
||||||
|
// @Success 200 {object} utils.Response{data=PendingUserResponse} "User approval details"
|
||||||
|
// @Failure 400 {object} utils.Response "Bad request"
|
||||||
|
// @Failure 401 {object} utils.Response "Unauthorized"
|
||||||
|
// @Failure 403 {object} utils.Response "Forbidden - Admin role required"
|
||||||
|
// @Failure 404 {object} utils.Response "User not found"
|
||||||
|
// @Failure 500 {object} utils.Response "Internal server error"
|
||||||
|
// @Security Bearer
|
||||||
|
// @Router /admin/users/{user_id}/approval-details [get]
|
||||||
|
func (h *ApprovalHandler) GetUserApprovalDetails(c *fiber.Ctx) error {
|
||||||
|
userID := c.Params("user_id")
|
||||||
|
if userID == "" {
|
||||||
|
return utils.BadRequest(c, "User ID is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate UUID format
|
||||||
|
// if err := h.validator.Var(userID, "uuid"); err != nil {
|
||||||
|
// return utils.BadRequest(c, "Invalid user ID format")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Call service
|
||||||
|
result, err := h.service.GetUserApprovalDetails(c.Context(), userID)
|
||||||
|
if err != nil {
|
||||||
|
if err.Error() == "user not found" {
|
||||||
|
return utils.NotFound(c, "User not found")
|
||||||
|
}
|
||||||
|
return utils.InternalServerError(c, "Failed to get user details: "+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return utils.SuccessWithData(c, "User approval details retrieved successfully", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProcessApprovalAction memproses aksi approval (approve/reject) untuk satu user
|
||||||
|
// @Summary Process approval action
|
||||||
|
// @Description Approve or reject a user registration
|
||||||
|
// @Tags Admin - User Approval
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param request body ApprovalActionRequest true "Approval action request"
|
||||||
|
// @Success 200 {object} utils.Response{data=ApprovalActionResponse} "Approval processed successfully"
|
||||||
|
// @Failure 400 {object} utils.Response "Bad request"
|
||||||
|
// @Failure 401 {object} utils.Response "Unauthorized"
|
||||||
|
// @Failure 403 {object} utils.Response "Forbidden - Admin role required"
|
||||||
|
// @Failure 404 {object} utils.Response "User not found"
|
||||||
|
// @Failure 500 {object} utils.Response "Internal server error"
|
||||||
|
// @Security Bearer
|
||||||
|
// @Router /admin/users/approval-action [post]
|
||||||
|
func (h *ApprovalHandler) ProcessApprovalAction(c *fiber.Ctx) error {
|
||||||
|
// Get admin ID from context
|
||||||
|
adminClaims, err := middleware.GetUserFromContext(c)
|
||||||
|
if err != nil {
|
||||||
|
return utils.Unauthorized(c, "Admin authentication required")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse request body
|
||||||
|
var req ApprovalActionRequest
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
return utils.BadRequest(c, "Invalid request body: "+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate request
|
||||||
|
// if err := h.validator.Struct(&req); err != nil {
|
||||||
|
// return utils.ResponseErrorData(c, fiber.StatusBadRequest, "Validation failed", err.Error())
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Call service
|
||||||
|
result, err := h.service.ProcessApprovalAction(c.Context(), &req, adminClaims.UserID)
|
||||||
|
if err != nil {
|
||||||
|
if err.Error() == "user not found" {
|
||||||
|
return utils.NotFound(c, "User not found")
|
||||||
|
}
|
||||||
|
return utils.InternalServerError(c, "Failed to process approval: "+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
actionMessage := "User approved successfully"
|
||||||
|
if req.Action == "reject" {
|
||||||
|
actionMessage = "User rejected successfully"
|
||||||
|
}
|
||||||
|
|
||||||
|
return utils.SuccessWithData(c, actionMessage, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BulkProcessApproval memproses aksi approval untuk multiple users sekaligus
|
||||||
|
// @Summary Bulk process approval actions
|
||||||
|
// @Description Approve or reject multiple users at once
|
||||||
|
// @Tags Admin - User Approval
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param request body BulkApprovalRequest true "Bulk approval request"
|
||||||
|
// @Success 200 {object} utils.Response{data=BulkApprovalResponse} "Bulk approval processed"
|
||||||
|
// @Failure 400 {object} utils.Response "Bad request"
|
||||||
|
// @Failure 401 {object} utils.Response "Unauthorized"
|
||||||
|
// @Failure 403 {object} utils.Response "Forbidden - Admin role required"
|
||||||
|
// @Failure 500 {object} utils.Response "Internal server error"
|
||||||
|
// @Security Bearer
|
||||||
|
// @Router /admin/users/bulk-approval [post]
|
||||||
|
func (h *ApprovalHandler) BulkProcessApproval(c *fiber.Ctx) error {
|
||||||
|
// Get admin ID from context
|
||||||
|
adminClaims, err := middleware.GetUserFromContext(c)
|
||||||
|
if err != nil {
|
||||||
|
return utils.Unauthorized(c, "Admin authentication required")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse request body
|
||||||
|
var req BulkApprovalRequest
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
return utils.BadRequest(c, "Invalid request body: "+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate request
|
||||||
|
// if err := h.validator.Struct(&req); err != nil {
|
||||||
|
// return utils.ResponseErrorData(c, fiber.StatusBadRequest, "Validation failed", err.Error())
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Call service
|
||||||
|
result, err := h.service.BulkProcessApproval(c.Context(), &req, adminClaims.UserID)
|
||||||
|
if err != nil {
|
||||||
|
return utils.InternalServerError(c, "Failed to process bulk approval: "+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
actionMessage := "Bulk approval processed successfully"
|
||||||
|
if req.Action == "reject" {
|
||||||
|
actionMessage = "Bulk rejection processed successfully"
|
||||||
|
}
|
||||||
|
|
||||||
|
return utils.SuccessWithData(c, actionMessage, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApproveUser endpoint khusus untuk approve satu user (shortcut)
|
||||||
|
// @Summary Approve user
|
||||||
|
// @Description Approve a user registration (shortcut endpoint)
|
||||||
|
// @Tags Admin - User Approval
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param user_id path string true "User ID" format(uuid)
|
||||||
|
// @Param notes body string false "Optional approval notes"
|
||||||
|
// @Success 200 {object} utils.Response{data=ApprovalActionResponse} "User approved successfully"
|
||||||
|
// @Failure 400 {object} utils.Response "Bad request"
|
||||||
|
// @Failure 401 {object} utils.Response "Unauthorized"
|
||||||
|
// @Failure 403 {object} utils.Response "Forbidden - Admin role required"
|
||||||
|
// @Failure 404 {object} utils.Response "User not found"
|
||||||
|
// @Failure 500 {object} utils.Response "Internal server error"
|
||||||
|
// @Security Bearer
|
||||||
|
// @Router /admin/users/{user_id}/approve [post]
|
||||||
|
func (h *ApprovalHandler) ApproveUser(c *fiber.Ctx) error {
|
||||||
|
userID := c.Params("user_id")
|
||||||
|
if userID == "" {
|
||||||
|
return utils.BadRequest(c, "User ID is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate UUID format
|
||||||
|
// if err := h.validator.Var(userID, "uuid"); err != nil {
|
||||||
|
// return utils.BadRequest(c, "Invalid user ID format")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Get admin ID from context
|
||||||
|
adminClaims, err := middleware.GetUserFromContext(c)
|
||||||
|
if err != nil {
|
||||||
|
return utils.Unauthorized(c, "Admin authentication required")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse optional notes from body
|
||||||
|
var body struct {
|
||||||
|
Notes string `json:"notes"`
|
||||||
|
}
|
||||||
|
c.BodyParser(&body) // Ignore error as notes are optional
|
||||||
|
|
||||||
|
// Call service
|
||||||
|
result, err := h.service.ApproveUser(c.Context(), userID, adminClaims.UserID, body.Notes)
|
||||||
|
if err != nil {
|
||||||
|
if err.Error() == "user not found" {
|
||||||
|
return utils.NotFound(c, "User not found")
|
||||||
|
}
|
||||||
|
return utils.InternalServerError(c, "Failed to approve user: "+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return utils.SuccessWithData(c, "User approved successfully", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RejectUser endpoint khusus untuk reject satu user (shortcut)
|
||||||
|
// @Summary Reject user
|
||||||
|
// @Description Reject a user registration (shortcut endpoint)
|
||||||
|
// @Tags Admin - User Approval
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param user_id path string true "User ID" format(uuid)
|
||||||
|
// @Param notes body string false "Optional rejection notes"
|
||||||
|
// @Success 200 {object} utils.Response{data=ApprovalActionResponse} "User rejected successfully"
|
||||||
|
// @Failure 400 {object} utils.Response "Bad request"
|
||||||
|
// @Failure 401 {object} utils.Response "Unauthorized"
|
||||||
|
// @Failure 403 {object} utils.Response "Forbidden - Admin role required"
|
||||||
|
// @Failure 404 {object} utils.Response "User not found"
|
||||||
|
// @Failure 500 {object} utils.Response "Internal server error"
|
||||||
|
// @Security Bearer
|
||||||
|
// @Router /admin/users/{user_id}/reject [post]
|
||||||
|
func (h *ApprovalHandler) RejectUser(c *fiber.Ctx) error {
|
||||||
|
userID := c.Params("user_id")
|
||||||
|
if userID == "" {
|
||||||
|
return utils.BadRequest(c, "User ID is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate UUID format
|
||||||
|
// if err := h.validator.Var(userID, "uuid"); err != nil {
|
||||||
|
// return utils.BadRequest(c, "Invalid user ID format")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Get admin ID from context
|
||||||
|
adminClaims, err := middleware.GetUserFromContext(c)
|
||||||
|
if err != nil {
|
||||||
|
return utils.Unauthorized(c, "Admin authentication required")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse optional notes from body
|
||||||
|
var body struct {
|
||||||
|
Notes string `json:"notes"`
|
||||||
|
}
|
||||||
|
c.BodyParser(&body) // Ignore error as notes are optional
|
||||||
|
|
||||||
|
// Call service
|
||||||
|
result, err := h.service.RejectUser(c.Context(), userID, adminClaims.UserID, body.Notes)
|
||||||
|
if err != nil {
|
||||||
|
if err.Error() == "user not found" {
|
||||||
|
return utils.NotFound(c, "User not found")
|
||||||
|
}
|
||||||
|
return utils.InternalServerError(c, "Failed to reject user: "+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return utils.SuccessWithData(c, "User rejected successfully", result)
|
||||||
|
}
|
|
@ -0,0 +1,183 @@
|
||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"rijig/model"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ApprovalRepository interface {
|
||||||
|
GetPendingUsers(ctx context.Context, req *GetPendingUsersRequest) ([]model.User, int64, error)
|
||||||
|
GetUserByID(ctx context.Context, userID string) (*model.User, error)
|
||||||
|
UpdateUserRegistrationStatus(ctx context.Context, userID, status string, progress int8) error
|
||||||
|
GetApprovalSummary(ctx context.Context) (*ApprovalSummary, error)
|
||||||
|
GetUsersByIDs(ctx context.Context, userIDs []string) ([]model.User, error)
|
||||||
|
BulkUpdateRegistrationStatus(ctx context.Context, userIDs []string, status string, progress int8) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type approvalRepository struct {
|
||||||
|
db *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewApprovalRepository(db *gorm.DB) ApprovalRepository {
|
||||||
|
return &approvalRepository{
|
||||||
|
db: db,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *approvalRepository) GetPendingUsers(ctx context.Context, req *GetPendingUsersRequest) ([]model.User, int64, error) {
|
||||||
|
var users []model.User
|
||||||
|
var totalRecords int64
|
||||||
|
|
||||||
|
query := r.db.WithContext(ctx).Model(&model.User{}).
|
||||||
|
Preload("Role").
|
||||||
|
Preload("IdentityCard").
|
||||||
|
Preload("CompanyProfile")
|
||||||
|
|
||||||
|
query = r.applyFilters(query, req)
|
||||||
|
|
||||||
|
if err := query.Count(&totalRecords).Error; err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("failed to count pending users: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
offset := (req.Page - 1) * req.Limit
|
||||||
|
if err := query.
|
||||||
|
Order("created_at DESC").
|
||||||
|
Limit(req.Limit).
|
||||||
|
Offset(offset).
|
||||||
|
Find(&users).Error; err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("failed to fetch pending users: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return users, totalRecords, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *approvalRepository) applyFilters(query *gorm.DB, req *GetPendingUsersRequest) *gorm.DB {
|
||||||
|
|
||||||
|
if req.Status != "" {
|
||||||
|
|
||||||
|
if req.Status == "pending" {
|
||||||
|
req.Status = "awaiting_approval"
|
||||||
|
}
|
||||||
|
query = query.Where("registration_status = ?", req.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Role != "" {
|
||||||
|
|
||||||
|
query = query.Joins("JOIN roles ON roles.id = users.role_id").
|
||||||
|
Where("LOWER(roles.role_name) = ?", strings.ToLower(req.Role))
|
||||||
|
}
|
||||||
|
|
||||||
|
query = query.Where("registration_progress >= ?", 2)
|
||||||
|
|
||||||
|
return query
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *approvalRepository) GetUserByID(ctx context.Context, userID string) (*model.User, error) {
|
||||||
|
var user model.User
|
||||||
|
|
||||||
|
if err := r.db.WithContext(ctx).
|
||||||
|
Preload("Role").
|
||||||
|
Preload("IdentityCard").
|
||||||
|
Preload("CompanyProfile").
|
||||||
|
Where("id = ?", userID).
|
||||||
|
First(&user).Error; err != nil {
|
||||||
|
if err == gorm.ErrRecordNotFound {
|
||||||
|
return nil, fmt.Errorf("user not found")
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("failed to get user: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *approvalRepository) UpdateUserRegistrationStatus(ctx context.Context, userID, status string, progress int8) error {
|
||||||
|
result := r.db.WithContext(ctx).
|
||||||
|
Model(&model.User{}).
|
||||||
|
Where("id = ?", userID).
|
||||||
|
Updates(map[string]interface{}{
|
||||||
|
"registration_status": status,
|
||||||
|
"registration_progress": progress,
|
||||||
|
"updated_at": "NOW()",
|
||||||
|
})
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
return fmt.Errorf("failed to update user registration status: %w", result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.RowsAffected == 0 {
|
||||||
|
return fmt.Errorf("user not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *approvalRepository) GetApprovalSummary(ctx context.Context) (*ApprovalSummary, error) {
|
||||||
|
var summary ApprovalSummary
|
||||||
|
|
||||||
|
if err := r.db.WithContext(ctx).
|
||||||
|
Model(&model.User{}).
|
||||||
|
Where("registration_status = ? AND registration_progress >= ?", "awaiting_approval", 2).
|
||||||
|
Count(&summary.TotalPending).Error; err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to count total pending users: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.db.WithContext(ctx).
|
||||||
|
Model(&model.User{}).
|
||||||
|
Joins("JOIN roles ON roles.id = users.role_id").
|
||||||
|
Where("users.registration_status = ? AND users.registration_progress >= ? AND LOWER(roles.role_name) = ?",
|
||||||
|
"awaiting_approval", 2, "pengelola").
|
||||||
|
Count(&summary.PengelolaPending).Error; err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to count pengelola pending: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.db.WithContext(ctx).
|
||||||
|
Model(&model.User{}).
|
||||||
|
Joins("JOIN roles ON roles.id = users.role_id").
|
||||||
|
Where("users.registration_status = ? AND users.registration_progress >= ? AND LOWER(roles.role_name) = ?",
|
||||||
|
"awaiting_approval", 2, "pengepul").
|
||||||
|
Count(&summary.PengepulPending).Error; err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to count pengepul pending: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &summary, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *approvalRepository) GetUsersByIDs(ctx context.Context, userIDs []string) ([]model.User, error) {
|
||||||
|
var users []model.User
|
||||||
|
|
||||||
|
if err := r.db.WithContext(ctx).
|
||||||
|
Preload("Role").
|
||||||
|
Preload("IdentityCard").
|
||||||
|
Preload("CompanyProfile").
|
||||||
|
Where("id IN ?", userIDs).
|
||||||
|
Find(&users).Error; err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get users by IDs: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return users, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *approvalRepository) BulkUpdateRegistrationStatus(ctx context.Context, userIDs []string, status string, progress int8) error {
|
||||||
|
result := r.db.WithContext(ctx).
|
||||||
|
Model(&model.User{}).
|
||||||
|
Where("id IN ?", userIDs).
|
||||||
|
Updates(map[string]interface{}{
|
||||||
|
"registration_status": status,
|
||||||
|
"registration_progress": progress,
|
||||||
|
"updated_at": "NOW()",
|
||||||
|
})
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
return fmt.Errorf("failed to bulk update registration status: %w", result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.RowsAffected == 0 {
|
||||||
|
return fmt.Errorf("no users found to update")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"rijig/config"
|
||||||
|
"rijig/middleware"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ApprovalRoutes(api fiber.Router) {
|
||||||
|
baseRepo := NewApprovalRepository(config.DB)
|
||||||
|
baseService := NewApprovalService(baseRepo)
|
||||||
|
baseHandler := NewApprovalHandler(baseService)
|
||||||
|
|
||||||
|
adminGroup := api.Group("/needapprove")
|
||||||
|
adminGroup.Use(middleware.RequireAdminRole(), middleware.AuthMiddleware())
|
||||||
|
|
||||||
|
adminGroup.Get("/pending", baseHandler.GetPendingUsers)
|
||||||
|
|
||||||
|
adminGroup.Get("/:user_id/approval-details", baseHandler.GetUserApprovalDetails)
|
||||||
|
adminGroup.Post("/approval-action", baseHandler.ProcessApprovalAction)
|
||||||
|
adminGroup.Post("/bulk-approval", baseHandler.BulkProcessApproval)
|
||||||
|
adminGroup.Post("/:user_id/approve", baseHandler.ApproveUser)
|
||||||
|
adminGroup.Post("/:user_id/reject", baseHandler.RejectUser)
|
||||||
|
}
|
|
@ -0,0 +1,320 @@
|
||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"rijig/model"
|
||||||
|
"rijig/utils"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ApprovalService interface {
|
||||||
|
GetPendingUsers(ctx context.Context, req *GetPendingUsersRequest) (*PendingUsersListResponse, error)
|
||||||
|
ApproveUser(ctx context.Context, userID, adminID string, notes string) (*ApprovalActionResponse, error)
|
||||||
|
RejectUser(ctx context.Context, userID, adminID string, notes string) (*ApprovalActionResponse, error)
|
||||||
|
ProcessApprovalAction(ctx context.Context, req *ApprovalActionRequest, adminID string) (*ApprovalActionResponse, error)
|
||||||
|
BulkProcessApproval(ctx context.Context, req *BulkApprovalRequest, adminID string) (*BulkApprovalResponse, error)
|
||||||
|
GetUserApprovalDetails(ctx context.Context, userID string) (*PendingUserResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type approvalService struct {
|
||||||
|
repo ApprovalRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewApprovalService(repo ApprovalRepository) ApprovalService {
|
||||||
|
return &approvalService{
|
||||||
|
repo: repo,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *approvalService) GetPendingUsers(ctx context.Context, req *GetPendingUsersRequest) (*PendingUsersListResponse, error) {
|
||||||
|
|
||||||
|
req.SetDefaults()
|
||||||
|
|
||||||
|
users, totalRecords, err := s.repo.GetPendingUsers(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get pending users: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
summary, err := s.repo.GetApprovalSummary(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get approval summary: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
totalPages := int(math.Ceil(float64(totalRecords) / float64(req.Limit)))
|
||||||
|
pagination := PaginationInfo{
|
||||||
|
Page: req.Page,
|
||||||
|
Limit: req.Limit,
|
||||||
|
TotalPages: totalPages,
|
||||||
|
TotalRecords: totalRecords,
|
||||||
|
HasNext: req.Page < totalPages,
|
||||||
|
HasPrev: req.Page > 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
userResponses := make([]PendingUserResponse, len(users))
|
||||||
|
for i, user := range users {
|
||||||
|
userResponses[i] = s.convertToUserResponse(user)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &PendingUsersListResponse{
|
||||||
|
Users: userResponses,
|
||||||
|
Pagination: pagination,
|
||||||
|
Summary: *summary,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *approvalService) ApproveUser(ctx context.Context, userID, adminID string, notes string) (*ApprovalActionResponse, error) {
|
||||||
|
|
||||||
|
user, err := s.repo.GetUserByID(ctx, userID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get user: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.validateUserForApproval(user, "approved"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
previousStatus := user.RegistrationStatus
|
||||||
|
|
||||||
|
newStatus := utils.RegStatusConfirmed
|
||||||
|
newProgress := utils.ProgressDataSubmitted
|
||||||
|
|
||||||
|
if err := s.repo.UpdateUserRegistrationStatus(ctx, userID, newStatus, int8(newProgress)); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to approved user: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.revokeUserTokens(userID); err != nil {
|
||||||
|
|
||||||
|
fmt.Printf("Warning: failed to revoke tokens for user %s: %v\n", userID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ApprovalActionResponse{
|
||||||
|
UserID: userID,
|
||||||
|
Action: "approved",
|
||||||
|
PreviousStatus: previousStatus,
|
||||||
|
NewStatus: newStatus,
|
||||||
|
ProcessedAt: time.Now(),
|
||||||
|
ProcessedBy: adminID,
|
||||||
|
Notes: notes,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *approvalService) RejectUser(ctx context.Context, userID, adminID string, notes string) (*ApprovalActionResponse, error) {
|
||||||
|
|
||||||
|
user, err := s.repo.GetUserByID(ctx, userID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get user: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.validateUserForApproval(user, "rejected"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
previousStatus := user.RegistrationStatus
|
||||||
|
|
||||||
|
newStatus := utils.RegStatusRejected
|
||||||
|
newProgress := utils.ProgressOTPVerified
|
||||||
|
|
||||||
|
if err := s.repo.UpdateUserRegistrationStatus(ctx, userID, newStatus, int8(newProgress)); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to rejected user: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.revokeUserTokens(userID); err != nil {
|
||||||
|
|
||||||
|
fmt.Printf("Warning: failed to revoke tokens for user %s: %v\n", userID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ApprovalActionResponse{
|
||||||
|
UserID: userID,
|
||||||
|
Action: "rejected",
|
||||||
|
PreviousStatus: previousStatus,
|
||||||
|
NewStatus: newStatus,
|
||||||
|
ProcessedAt: time.Now(),
|
||||||
|
ProcessedBy: adminID,
|
||||||
|
Notes: notes,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *approvalService) ProcessApprovalAction(ctx context.Context, req *ApprovalActionRequest, adminID string) (*ApprovalActionResponse, error) {
|
||||||
|
switch req.Action {
|
||||||
|
case "approved":
|
||||||
|
return s.ApproveUser(ctx, req.UserID, adminID, req.Notes)
|
||||||
|
case "rejected":
|
||||||
|
return s.RejectUser(ctx, req.UserID, adminID, req.Notes)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("invalid action: %s", req.Action)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *approvalService) BulkProcessApproval(ctx context.Context, req *BulkApprovalRequest, adminID string) (*BulkApprovalResponse, error) {
|
||||||
|
|
||||||
|
users, err := s.repo.GetUsersByIDs(ctx, req.UserIDs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get users: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var results []ApprovalActionResponse
|
||||||
|
var failures []ApprovalFailure
|
||||||
|
successCount := 0
|
||||||
|
|
||||||
|
for _, user := range users {
|
||||||
|
|
||||||
|
if err := s.validateUserForApproval(&user, req.Action); err != nil {
|
||||||
|
failures = append(failures, ApprovalFailure{
|
||||||
|
UserID: user.ID,
|
||||||
|
Error: "validation_failed",
|
||||||
|
Reason: err.Error(),
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
actionReq := &ApprovalActionRequest{
|
||||||
|
UserID: user.ID,
|
||||||
|
Action: req.Action,
|
||||||
|
Notes: req.Notes,
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := s.ProcessApprovalAction(ctx, actionReq, adminID)
|
||||||
|
if err != nil {
|
||||||
|
failures = append(failures, ApprovalFailure{
|
||||||
|
UserID: user.ID,
|
||||||
|
Error: "processing_failed",
|
||||||
|
Reason: err.Error(),
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
results = append(results, *result)
|
||||||
|
successCount++
|
||||||
|
}
|
||||||
|
|
||||||
|
return &BulkApprovalResponse{
|
||||||
|
SuccessCount: successCount,
|
||||||
|
FailureCount: len(failures),
|
||||||
|
Results: results,
|
||||||
|
Failures: failures,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *approvalService) GetUserApprovalDetails(ctx context.Context, userID string) (*PendingUserResponse, error) {
|
||||||
|
user, err := s.repo.GetUserByID(ctx, userID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get user details: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
userResponse := s.convertToUserResponse(*user)
|
||||||
|
return &userResponse, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *approvalService) validateUserForApproval(user *model.User, action string) error {
|
||||||
|
|
||||||
|
if user.Role == nil {
|
||||||
|
return fmt.Errorf("user role not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
roleName := strings.ToLower(user.Role.RoleName)
|
||||||
|
if roleName != "pengelola" && roleName != "pengepul" {
|
||||||
|
return fmt.Errorf("only pengelola and pengepul can be approved/rejected")
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.RegistrationStatus != utils.RegStatusPending {
|
||||||
|
return fmt.Errorf("user is not in awaiting_approval status")
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.RegistrationProgress < utils.ProgressDataSubmitted {
|
||||||
|
return fmt.Errorf("user has not submitted required data yet")
|
||||||
|
}
|
||||||
|
|
||||||
|
if roleName == "pengepul" && user.IdentityCard == nil {
|
||||||
|
return fmt.Errorf("pengepul must have identity card data")
|
||||||
|
}
|
||||||
|
|
||||||
|
if roleName == "pengelola" && user.CompanyProfile == nil {
|
||||||
|
return fmt.Errorf("pengelola must have company profile data")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *approvalService) revokeUserTokens(userID string) error {
|
||||||
|
|
||||||
|
return utils.RevokeAllRefreshTokens(userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *approvalService) convertToUserResponse(user model.User) PendingUserResponse {
|
||||||
|
response := PendingUserResponse{
|
||||||
|
ID: user.ID,
|
||||||
|
Name: user.Name,
|
||||||
|
Phone: user.Phone,
|
||||||
|
Email: user.Email,
|
||||||
|
RegistrationStatus: user.RegistrationStatus,
|
||||||
|
RegistrationProgress: user.RegistrationProgress,
|
||||||
|
SubmittedAt: user.UpdatedAt,
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.Role != nil {
|
||||||
|
response.Role = RoleInfo{
|
||||||
|
ID: user.Role.ID,
|
||||||
|
RoleName: user.Role.RoleName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stepInfo := utils.GetRegistrationStepInfo(
|
||||||
|
user.Role.RoleName,
|
||||||
|
int(user.RegistrationProgress),
|
||||||
|
user.RegistrationStatus,
|
||||||
|
)
|
||||||
|
if stepInfo != nil {
|
||||||
|
response.RegistrationStepInfo = &RegistrationStepResponse{
|
||||||
|
Step: stepInfo.Step,
|
||||||
|
Status: stepInfo.Status,
|
||||||
|
Description: stepInfo.Description,
|
||||||
|
RequiresAdminApproval: stepInfo.RequiresAdminApproval,
|
||||||
|
IsAccessible: stepInfo.IsAccessible,
|
||||||
|
IsCompleted: stepInfo.IsCompleted,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.IdentityCard != nil {
|
||||||
|
response.IdentityCard = &IdentityCardInfo{
|
||||||
|
ID: user.IdentityCard.ID,
|
||||||
|
IdentificationNumber: user.IdentityCard.Identificationumber,
|
||||||
|
Fullname: user.IdentityCard.Fullname,
|
||||||
|
Placeofbirth: user.IdentityCard.Placeofbirth,
|
||||||
|
Dateofbirth: user.IdentityCard.Dateofbirth,
|
||||||
|
Gender: user.IdentityCard.Gender,
|
||||||
|
BloodType: user.IdentityCard.BloodType,
|
||||||
|
Province: user.IdentityCard.Province,
|
||||||
|
District: user.IdentityCard.District,
|
||||||
|
SubDistrict: user.IdentityCard.SubDistrict,
|
||||||
|
Village: user.IdentityCard.Village,
|
||||||
|
PostalCode: user.IdentityCard.PostalCode,
|
||||||
|
Religion: user.IdentityCard.Religion,
|
||||||
|
Maritalstatus: user.IdentityCard.Maritalstatus,
|
||||||
|
Job: user.IdentityCard.Job,
|
||||||
|
Citizenship: user.IdentityCard.Citizenship,
|
||||||
|
Validuntil: user.IdentityCard.Validuntil,
|
||||||
|
Cardphoto: user.IdentityCard.Cardphoto,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.CompanyProfile != nil {
|
||||||
|
response.CompanyProfile = &CompanyProfileInfo{
|
||||||
|
ID: user.CompanyProfile.ID,
|
||||||
|
CompanyName: user.CompanyProfile.CompanyName,
|
||||||
|
CompanyAddress: user.CompanyProfile.CompanyAddress,
|
||||||
|
CompanyPhone: user.CompanyProfile.CompanyPhone,
|
||||||
|
CompanyEmail: user.CompanyProfile.CompanyEmail,
|
||||||
|
CompanyLogo: user.CompanyProfile.CompanyLogo,
|
||||||
|
CompanyWebsite: user.CompanyProfile.CompanyWebsite,
|
||||||
|
TaxID: user.CompanyProfile.TaxID,
|
||||||
|
FoundedDate: user.CompanyProfile.FoundedDate,
|
||||||
|
CompanyType: user.CompanyProfile.CompanyType,
|
||||||
|
CompanyDescription: user.CompanyProfile.CompanyDescription,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response
|
||||||
|
}
|
|
@ -147,7 +147,7 @@ func (s *authenticationService) LoginAdmin(ctx context.Context, req *LoginAdminR
|
||||||
return nil, fmt.Errorf("invalid credentials")
|
return nil, fmt.Errorf("invalid credentials")
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.RegistrationStatus != "completed" {
|
if user.RegistrationStatus != "complete" {
|
||||||
return nil, fmt.Errorf("account not activated")
|
return nil, fmt.Errorf("account not activated")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,7 +470,7 @@ func (s *authenticationService) RegisterAdmin(ctx context.Context, req *Register
|
||||||
Password: hashedPassword,
|
Password: hashedPassword,
|
||||||
RoleID: role.ID,
|
RoleID: role.ID,
|
||||||
RegistrationStatus: "pending_email_verification",
|
RegistrationStatus: "pending_email_verification",
|
||||||
RegistrationProgress: 1,
|
// RegistrationProgress: 1,
|
||||||
EmailVerified: false,
|
EmailVerified: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
package model
|
|
|
@ -105,8 +105,6 @@ func (s *userProfileService) UpdateRegistUserProfile(ctx context.Context, userID
|
||||||
NextStep: nextStep,
|
NextStep: nextStep,
|
||||||
SessionID: tokenResponse.SessionID,
|
SessionID: tokenResponse.SessionID,
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
// return s.mapToResponseDTO(updatedUser), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *userProfileService) mapToResponseDTO(user *model.User) *UserProfileResponseDTO {
|
func (s *userProfileService) mapToResponseDTO(user *model.User) *UserProfileResponseDTO {
|
||||||
|
|
|
@ -3,21 +3,23 @@ package model
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4();unique;not null" json:"id"`
|
ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4();unique;not null" json:"id"`
|
||||||
Avatar *string `json:"avatar,omitempty"`
|
Avatar *string `json:"avatar,omitempty"`
|
||||||
Name string `gorm:"not null" json:"name"`
|
Name string `gorm:"not null" json:"name"`
|
||||||
Gender string `gorm:"not null" json:"gender"`
|
Gender string `gorm:"not null" json:"gender"`
|
||||||
Dateofbirth string `gorm:"not null" json:"dateofbirth"`
|
Dateofbirth string `gorm:"not null" json:"dateofbirth"`
|
||||||
Placeofbirth string `gorm:"not null" json:"placeofbirth"`
|
Placeofbirth string `gorm:"not null" json:"placeofbirth"`
|
||||||
Phone string `gorm:"not null;index" json:"phone"`
|
Phone string `gorm:"not null;index" json:"phone"`
|
||||||
Email string `json:"email,omitempty"`
|
Email string `json:"email,omitempty"`
|
||||||
EmailVerified bool `gorm:"default:false" json:"emailVerified"`
|
EmailVerified bool `gorm:"default:false" json:"emailVerified"`
|
||||||
PhoneVerified bool `gorm:"default:false" json:"phoneVerified"`
|
PhoneVerified bool `gorm:"default:false" json:"phoneVerified"`
|
||||||
Password string `json:"password,omitempty"`
|
Password string `json:"password,omitempty"`
|
||||||
RoleID string `gorm:"not null" json:"roleId"`
|
RoleID string `gorm:"not null" json:"roleId"`
|
||||||
Role *Role `gorm:"foreignKey:RoleID;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;" json:"role"`
|
Role *Role `gorm:"foreignKey:RoleID;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;" json:"role"`
|
||||||
RegistrationStatus string `json:"registrationstatus"`
|
RegistrationStatus string `json:"registrationstatus"`
|
||||||
RegistrationProgress int8 `json:"registration_progress"`
|
RegistrationProgress int8 `json:"registration_progress"`
|
||||||
CreatedAt time.Time `gorm:"default:current_timestamp" json:"createdAt"`
|
IdentityCard *IdentityCard `gorm:"foreignKey:UserID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"identity_card,omitempty"`
|
||||||
UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updatedAt"`
|
CompanyProfile *CompanyProfile `gorm:"foreignKey:UserID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"company_profile,omitempty"`
|
||||||
|
CreatedAt time.Time `gorm:"default:current_timestamp" json:"createdAt"`
|
||||||
|
UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updatedAt"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"rijig/internal/about"
|
"rijig/internal/about"
|
||||||
|
"rijig/internal/admin"
|
||||||
"rijig/internal/article"
|
"rijig/internal/article"
|
||||||
"rijig/internal/authentication"
|
"rijig/internal/authentication"
|
||||||
"rijig/internal/company"
|
"rijig/internal/company"
|
||||||
|
@ -42,6 +43,7 @@ func SetupRoutes(app *fiber.App) {
|
||||||
trash.TrashRouter(api)
|
trash.TrashRouter(api)
|
||||||
about.AboutRouter(api)
|
about.AboutRouter(api)
|
||||||
whatsapp.WhatsAppRouter(api)
|
whatsapp.WhatsAppRouter(api)
|
||||||
|
admin.ApprovalRoutes(api)
|
||||||
|
|
||||||
// || auth router || //
|
// || auth router || //
|
||||||
// presentation.AuthRouter(api)
|
// presentation.AuthRouter(api)
|
||||||
|
|
Loading…
Reference in New Issue