package handlers import ( "strconv" "time" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication" "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response" "github.com/gofiber/fiber/v2" ) type CreateManagerReq struct { FirstName string `json:"first_name" example:"John"` LastName string `json:"last_name" example:"Doe"` Email string `json:"email" example:"john.doe@example.com"` PhoneNumber string `json:"phone_number" example:"1234567890"` Password string `json:"password" example:"password123"` CompanyID *int64 `json:"company_id,omitempty" example:"1"` } // CreateManager godoc // @Summary Create Manager // @Description Create Manager // @Tags manager // @Accept json // @Produce json // @Param manger body CreateManagerReq true "Create manager" // @Success 200 {object} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Router /managers [post] func (h *Handler) CreateManager(c *fiber.Ctx) error { // Get user_id from middleware var req CreateManagerReq if err := c.BodyParser(&req); err != nil { h.logger.Error("RegisterUser failed", "error", err) return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil) } valErrs, ok := h.validator.Validate(c, req) if !ok { return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) } var companyID domain.ValidInt64 role := c.Locals("role").(domain.Role) if role == domain.RoleSuperAdmin { if req.CompanyID == nil { h.logger.Error("RegisterUser failed error: company id is required") return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", "Company ID is required", nil) } companyID = domain.ValidInt64{ Value: *req.CompanyID, Valid: true, } } else { companyID = c.Locals("company_id").(domain.ValidInt64) } user := domain.CreateUserReq{ FirstName: req.FirstName, LastName: req.LastName, Email: req.Email, PhoneNumber: req.PhoneNumber, Password: req.Password, Role: string(domain.RoleBranchManager), CompanyID: companyID, } _, err := h.userSvc.CreateUser(c.Context(), user, true) if err != nil { h.logger.Error("CreateManager failed", "error", err) return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to create manager", nil, nil) } return response.WriteJSON(c, fiber.StatusOK, "Manager created successfully", nil, nil) } type ManagersRes struct { ID int64 `json:"id"` FirstName string `json:"first_name"` LastName string `json:"last_name"` Email string `json:"email"` PhoneNumber string `json:"phone_number"` Role domain.Role `json:"role"` EmailVerified bool `json:"email_verified"` PhoneVerified bool `json:"phone_verified"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` LastLogin time.Time `json:"last_login"` SuspendedAt time.Time `json:"suspended_at"` Suspended bool `json:"suspended"` } // GetAllManagers godoc // @Summary Get all Managers // @Description Get all Managers // @Tags manager // @Accept json // @Produce json // @Param page query int false "Page number" // @Param page_size query int false "Page size" // @Success 200 {object} ManagersRes // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Router /managers [get] func (h *Handler) GetAllManagers(c *fiber.Ctx) error { role := c.Locals("role").(domain.Role) companyId := c.Locals("company_id").(domain.ValidInt64) // Checking to make sure that admin user has a company id in the token if role != domain.RoleSuperAdmin && !companyId.Valid { return fiber.NewError(fiber.StatusInternalServerError, "Cannot get company ID") } searchQuery := c.Query("query") searchString := domain.ValidString{ Value: searchQuery, Valid: searchQuery != "", } createdBeforeQuery := c.Query("created_before") var createdBefore domain.ValidTime if createdBeforeQuery != "" { createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery) if err != nil { h.logger.Error("invalid start_time format", "error", err) return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil) } createdBefore = domain.ValidTime{ Value: createdBeforeParsed, Valid: true, } } createdAfterQuery := c.Query("created_after") var createdAfter domain.ValidTime if createdAfterQuery != "" { createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery) if err != nil { h.logger.Error("invalid start_time format", "error", err) return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil) } createdAfter = domain.ValidTime{ Value: createdAfterParsed, Valid: true, } } filter := domain.UserFilter{ Role: string(domain.RoleBranchManager), CompanyID: companyId, Page: domain.ValidInt{ Value: c.QueryInt("page", 1) - 1, Valid: true, }, PageSize: domain.ValidInt{ Value: c.QueryInt("page_size", 10), Valid: true, }, Query: searchString, CreatedBefore: createdBefore, CreatedAfter: createdAfter, } valErrs, ok := h.validator.Validate(c, filter) if !ok { return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) } managers, total, err := h.userSvc.GetAllUsers(c.Context(), filter) if err != nil { h.logger.Error("GetAllManagers failed", "error", err) return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get Managers", err, nil) } var result []ManagersRes = make([]ManagersRes, len(managers)) for index, manager := range managers { lastLogin, err := h.authSvc.GetLastLogin(c.Context(), manager.ID) if err != nil { if err == authentication.ErrRefreshTokenNotFound { lastLogin = &manager.CreatedAt } else { h.logger.Error("Failed to get user last login", "userID", manager.ID, "error", err) return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login") } } result[index] = ManagersRes{ ID: manager.ID, FirstName: manager.FirstName, LastName: manager.LastName, Email: manager.Email, PhoneNumber: manager.PhoneNumber, Role: manager.Role, EmailVerified: manager.EmailVerified, PhoneVerified: manager.PhoneVerified, CreatedAt: manager.CreatedAt, UpdatedAt: manager.UpdatedAt, SuspendedAt: manager.SuspendedAt, Suspended: manager.Suspended, LastLogin: *lastLogin, } } return response.WritePaginatedJSON(c, fiber.StatusOK, "Managers retrieved successfully", result, nil, filter.Page.Value, int(total)) } // GetManagerByID godoc // @Summary Get manager by id // @Description Get a single manager by id // @Tags manager // @Accept json // @Produce json // @Param id path int true "User ID" // @Success 200 {object} ManagersRes // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Router /managers/{id} [get] func (h *Handler) GetManagerByID(c *fiber.Ctx) error { role := c.Locals("role").(domain.Role) companyId := c.Locals("company_id").(domain.ValidInt64) requestUserID := c.Locals("user_id").(int64) // Only Super Admin / Admin / Branch Manager can view this route if role != domain.RoleSuperAdmin && role != domain.RoleAdmin && role != domain.RoleBranchManager { return fiber.NewError(fiber.StatusUnauthorized, "Role Unauthorized") } if role != domain.RoleSuperAdmin && !companyId.Valid { return fiber.NewError(fiber.StatusInternalServerError, "Cannot get company ID") } userIDstr := c.Params("id") userID, err := strconv.ParseInt(userIDstr, 10, 64) if err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid managers ID") } user, err := h.userSvc.GetUserByID(c.Context(), userID) if err != nil { return fiber.NewError(fiber.StatusInternalServerError, "Failed to get managers") } // A Branch Manager can only fetch his own branch info if role == domain.RoleBranchManager && user.ID != requestUserID { return fiber.NewError(fiber.StatusBadRequest, "User Access Not Allowed") } // Check that only admin from company can view this route if role != domain.RoleSuperAdmin && user.CompanyID.Value != companyId.Value { return fiber.NewError(fiber.StatusBadRequest, "Only company user can view manager info") } lastLogin, err := h.authSvc.GetLastLogin(c.Context(), user.ID) if err != nil { if err != authentication.ErrRefreshTokenNotFound { h.logger.Error("Failed to get user last login", "userID", user.ID, "error", err) return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login") } lastLogin = &user.CreatedAt } res := ManagersRes{ ID: user.ID, FirstName: user.FirstName, LastName: user.LastName, Email: user.Email, PhoneNumber: user.PhoneNumber, Role: user.Role, EmailVerified: user.EmailVerified, PhoneVerified: user.PhoneVerified, CreatedAt: user.CreatedAt, UpdatedAt: user.UpdatedAt, SuspendedAt: user.SuspendedAt, Suspended: user.Suspended, LastLogin: *lastLogin, } return response.WriteJSON(c, fiber.StatusOK, "User retrieved successfully", res, nil) } type updateManagerReq struct { FirstName string `json:"first_name" example:"John"` LastName string `json:"last_name" example:"Doe"` Suspended bool `json:"suspended" example:"false"` CompanyID *int64 `json:"company_id,omitempty" example:"1"` } // UpdateManagers godoc // @Summary Update Managers // @Description Update Managers // @Tags manager // @Accept json // @Produce json // @Param Managers body updateManagerReq true "Update Managers" // @Success 200 {object} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Router /managers/{id} [put] func (h *Handler) UpdateManagers(c *fiber.Ctx) error { var req updateManagerReq if err := c.BodyParser(&req); err != nil { h.logger.Error("UpdateManagers failed", "error", err) return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", nil, nil) } valErrs, ok := h.validator.Validate(c, req) if !ok { return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) } ManagersIdStr := c.Params("id") ManagersId, err := strconv.ParseInt(ManagersIdStr, 10, 64) if err != nil { h.logger.Error("UpdateManagers failed", "error", err) return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid Managers ID", nil, nil) } var companyID domain.ValidInt64 role := c.Locals("role").(domain.Role) if req.CompanyID != nil { if role != domain.RoleSuperAdmin { h.logger.Error("UpdateManagers failed", "error", err) return response.WriteJSON(c, fiber.StatusUnauthorized, "This user role cannot modify company ID", nil, nil) } companyID = domain.ValidInt64{ Value: *req.CompanyID, Valid: true, } } err = h.userSvc.UpdateUser(c.Context(), domain.UpdateUserReq{ UserId: ManagersId, FirstName: domain.ValidString{ Value: req.FirstName, Valid: req.FirstName != "", }, LastName: domain.ValidString{ Value: req.LastName, Valid: req.LastName != "", }, Suspended: domain.ValidBool{ Value: req.Suspended, Valid: true, }, CompanyID: companyID, }, ) if err != nil { h.logger.Error("UpdateManagers failed", "error", err) return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to update Managers", nil, nil) } return response.WriteJSON(c, fiber.StatusOK, "Managers updated successfully", nil, nil) }