package handlers import ( "Yimaru-Backend/internal/domain" "Yimaru-Backend/internal/web_server/response" "strconv" "time" "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 /api/v1/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) // h.mongoLoggerSvc.Info("CreateManager failed to create manager", // zap.Int("status_code", fiber.StatusBadRequest), // zap.Error(err), // zap.Time("timestamp", time.Now()), // ) // return fiber.NewError(fiber.StatusBadRequest, "Invalid request body:"+err.Error()) // } // valErrs, ok := h.validator.Validate(c, req) // if !ok { // var errMsg string // for field, msg := range valErrs { // errMsg += fmt.Sprintf("%s: %s; ", field, msg) // } // h.mongoLoggerSvc.Info("Failed to validate CreateManager", // zap.Any("request", req), // zap.Int("status_code", fiber.StatusBadRequest), // zap.String("errMsg", errMsg), // zap.Time("timestamp", time.Now()), // ) // return fiber.NewError(fiber.StatusBadRequest, errMsg) // } // 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") // h.mongoLoggerSvc.Info("RegisterUser failed error: company id is required", // zap.Int("status_code", fiber.StatusBadRequest), // zap.Time("timestamp", time.Now()), // ) // return fiber.NewError(fiber.StatusBadRequest, "Company ID is required for super-admin") // } // 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), // OrganizationID: companyID, // } // _, err := h.userSvc.CreateUser(c.Context(), user, true) // if err != nil { // h.mongoLoggerSvc.Error("CreateManager failed to create manager", // zap.Int("status_code", fiber.StatusInternalServerError), // zap.Error(err), // zap.Time("timestamp", time.Now()), // ) // return fiber.NewError(fiber.StatusInternalServerError, "Failed to create manager:"+err.Error()) // } // 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 /api/v1/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 { // h.mongoLoggerSvc.Error("Cannot get company ID from context", // zap.String("role", string(role)), // zap.Int("status_code", fiber.StatusInternalServerError), // zap.Time("timestamp", time.Now()), // ) // return fiber.NewError(fiber.StatusInternalServerError, "Cannot get company ID from context") // } // 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.mongoLoggerSvc.Info("invalid created_before format", // zap.String("created_before", createdBeforeQuery), // zap.Int("status_code", fiber.StatusBadRequest), // zap.Error(err), // zap.Time("timestamp", time.Now()), // ) // return fiber.NewError(fiber.StatusBadRequest, "Invalid created_before format") // } // 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.mongoLoggerSvc.Info("invalid created_after format", // zap.String("created_after", createdAfterQuery), // zap.Int("status_code", fiber.StatusBadRequest), // zap.Error(err), // zap.Time("timestamp", time.Now()), // ) // return fiber.NewError(fiber.StatusBadRequest, "Invalid created_after format") // } // createdAfter = domain.ValidTime{ // Value: createdAfterParsed, // Valid: true, // } // } // filter := domain.UserFilter{ // Role: string(domain.RoleBranchManager), // OrganizationID: 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 { // var errMsg string // for field, msg := range valErrs { // errMsg += fmt.Sprintf("%s: %s; ", field, msg) // } // h.mongoLoggerSvc.Info("Failed to validate get all filters", // zap.Any("filter", filter), // zap.Int("status_code", fiber.StatusBadRequest), // zap.String("errMsg", errMsg), // zap.Time("timestamp", time.Now()), // ) // return fiber.NewError(fiber.StatusBadRequest, errMsg) // } // managers, total, err := h.userSvc.GetAllUsers(c.Context(), filter) // if err != nil { // h.logger.Error("GetAllManagers failed", "error", err) // h.mongoLoggerSvc.Error("GetAllManagers failed to get all managers", // zap.Any("filter", filter), // zap.Int("status_code", fiber.StatusInternalServerError), // zap.Error(err), // zap.Time("timestamp", time.Now()), // ) // return fiber.NewError(fiber.StatusInternalServerError, "Failed to get Managers"+err.Error()) // } // 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.mongoLoggerSvc.Error("Failed to get user last login", // zap.Int64("userID", manager.ID), // zap.Int("status_code", fiber.StatusInternalServerError), // zap.Error(err), // zap.Time("timestamp", time.Now()), // ) // return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login:"+err.Error()) // } // } // 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 /api/v1/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 { // h.mongoLoggerSvc.Warn("Attempt to access from unauthorized role", // zap.Int64("userID", requestUserID), // zap.String("role", string(role)), // zap.Int("status_code", fiber.StatusForbidden), // zap.Time("timestamp", time.Now()), // ) // return fiber.NewError(fiber.StatusForbidden, "This role cannot view this route") // } // if role != domain.RoleSuperAdmin && !companyId.Valid { // h.mongoLoggerSvc.Error("Cannot get company ID in context", // zap.String("role", string(role)), // zap.Int("status_code", fiber.StatusInternalServerError), // zap.Time("timestamp", time.Now()), // ) // return fiber.NewError(fiber.StatusInternalServerError, "Cannot get company ID in context") // } // 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 { // h.mongoLoggerSvc.Error("Failed to get manager by id", // zap.Int64("userID", userID), // zap.Int("status_code", fiber.StatusInternalServerError), // zap.Error(err), // zap.Time("timestamp", time.Now()), // ) // return fiber.NewError(fiber.StatusInternalServerError, "Failed to get managers:"+err.Error()) // } // // A Branch Manager can only fetch his own branch info // if role == domain.RoleBranchManager && user.ID != requestUserID { // h.mongoLoggerSvc.Warn("Attempt to access another branch manager info", // zap.String("userID", userIDstr), // zap.Int("status_code", fiber.StatusForbidden), // zap.Error(err), // zap.Time("timestamp", time.Now()), // ) // return fiber.NewError(fiber.StatusForbidden, "User Access Not Allowed") // } // // Check that only admin from company can view this route // if role != domain.RoleSuperAdmin && user.OrganizationID.Value != companyId.Value { // h.mongoLoggerSvc.Warn("Attempt to access info from another company", // zap.String("userID", userIDstr), // zap.Int("status_code", fiber.StatusForbidden), // zap.Error(err), // zap.Time("timestamp", time.Now()), // ) // return fiber.NewError(fiber.StatusForbidden, "Cannot access another company information") // } // lastLogin, err := h.authSvc.GetLastLogin(c.Context(), user.ID) // if err != nil { // if err != authentication.ErrRefreshTokenNotFound { // h.mongoLoggerSvc.Error("Failed to get user last login", // zap.Int64("userID", userID), // zap.Int("status_code", fiber.StatusInternalServerError), // zap.Error(err), // zap.Time("timestamp", time.Now()), // ) // return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login"+err.Error()) // } // 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 /api/v1/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, }, OrganizationID: 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) }