package handlers import ( "Yimaru-Backend/internal/domain" "Yimaru-Backend/internal/services/authentication" "Yimaru-Backend/internal/web_server/response" "fmt" "strconv" "time" "github.com/gofiber/fiber/v2" "go.uber.org/zap" ) type CreateTransactionApproverReq 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" example:"1"` } // CreateTransactionApprover godoc // @Summary Create transaction approver // @Description Create transaction approver // @Tags admin // @Accept json // @Produce json // @Param manger body CreateTransactionApproverReq true "Create transaction approver" // @Success 200 {object} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Router /api/v1/admin [post] // func (h *Handler) CreateTransactionApprover(c *fiber.Ctx) error { // var companyID domain.ValidInt64 // var req CreateTransactionApproverReq // if err := c.BodyParser(&req); err != nil { // h.mongoLoggerSvc.Info("failed to parse CreateAdmin request", // zap.Int64("status_code", fiber.StatusBadRequest), // zap.Error(err), // zap.Time("timestamp", time.Now()), // ) // return fiber.NewError(fiber.StatusBadRequest, "Invalid request:"+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.Error("validation failed for CreateAdmin request", // zap.Int64("status_code", fiber.StatusBadRequest), // zap.Any("validation_errors", valErrs), // zap.Time("timestamp", time.Now()), // ) // return fiber.NewError(fiber.StatusBadRequest, errMsg) // } // // _, err := h.companySvc.GetCompanyByID(c.Context(), req.CompanyID) // // if err != nil { // // h.mongoLoggerSvc.Error("invalid company ID for CreateAdmin", // // zap.Int64("status_code", fiber.StatusInternalServerError), // // zap.Int64("company_id", req.CompanyID), // // zap.Error(err), // // zap.Time("timestamp", time.Now()), // // ) // // return fiber.NewError(fiber.StatusInternalServerError, "Company ID is invalid:"+err.Error()) // // } // companyID = domain.ValidInt64{ // Value: req.CompanyID, // Valid: true, // } // user := domain.CreateUserReq{ // FirstName: req.FirstName, // LastName: req.LastName, // Email: req.Email, // PhoneNumber: req.PhoneNumber, // Password: req.Password, // Role: string(domain.RoleTransactionApprover), // OrganizationID: companyID, // } // newUser, err := h.userSvc.CreateUser(c.Context(), user, true) // if err != nil { // h.mongoLoggerSvc.Error("failed to create admin user", // zap.Int64("status_code", fiber.StatusInternalServerError), // zap.Any("request", req), // zap.Error(err), // zap.Time("timestamp", time.Now()), // ) // return fiber.NewError(fiber.StatusInternalServerError, "Failed to create admin:"+err.Error()) // } // h.mongoLoggerSvc.Info("transaction_approver created successfully", // zap.Int64("transaction_approver_id", newUser.ID), // zap.String("email", newUser.Email), // zap.Time("timestamp", time.Now()), // ) // return response.WriteJSON(c, fiber.StatusOK, "Transaction Approver created successfully", nil, nil) // } type TransactionApproverRes 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"` } // GetAllAdmins godoc // @Summary Get all Admins // @Description Get all Admins // @Tags admin // @Accept json // @Produce json // @Param page query int false "Page number" // @Param page_size query int false "Page size" // @Success 200 {object} AdminRes // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Router /api/v1/t-approver [get] // func (h *Handler) GetAllTransactionApprovers(c *fiber.Ctx) error { // role := c.Locals("role").(domain.Role) // companyID := c.Locals("company_id").(domain.ValidInt64) // 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.Info("invalid start_time format", "error", err) // return fiber.NewError(fiber.StatusBadRequest, "Invalid start_time 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.logger.Info("invalid start_time format", "error", err) // return fiber.NewError(fiber.StatusBadRequest, "Invalid start_time format") // } // createdAfter = domain.ValidTime{ // Value: createdAfterParsed, // Valid: true, // } // } // var companyIDFilter domain.ValidInt64 // if role == domain.RoleSuperAdmin { // companyIDQuery := int64(c.QueryInt("company_id")) // companyIDFilter = domain.ValidInt64{ // Value: companyIDQuery, // Valid: companyIDQuery != 0, // } // } else { // if !companyID.Valid { // h.logger.Info("invalid companyID") // return fiber.NewError(fiber.StatusBadRequest, "Unable to get company ID") // } // companyIDFilter = companyID // } // filter := domain.UserFilter{ // Role: string(domain.RoleTransactionApprover), // OrganizationID: companyIDFilter, // 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("invalid filter values in GetAllAdmins request", // zap.Int("status_code", fiber.StatusBadRequest), // zap.Any("validation_errors", valErrs), // zap.Time("timestamp", time.Now()), // ) // return fiber.NewError(fiber.StatusBadRequest, errMsg) // } // users, total, err := h.userSvc.GetAllUsers(c.Context(), filter) // if err != nil { // h.mongoLoggerSvc.Error("failed to get users from user service", // zap.Int("status_code", fiber.StatusInternalServerError), // zap.Any("filter", filter), // zap.Error(err), // zap.Time("timestamp", time.Now()), // ) // return fiber.NewError(fiber.StatusInternalServerError, "Failed to get users"+err.Error()) // } // result := make([]TransactionApproverRes, len(users)) // for index, admin := range users { // lastLogin, err := h.authSvc.GetLastLogin(c.Context(), admin.ID) // if err != nil { // if err == authentication.ErrRefreshTokenNotFound { // lastLogin = &admin.CreatedAt // } else { // h.mongoLoggerSvc.Error("failed to get last login for admin", // zap.Int("status_code", fiber.StatusInternalServerError), // zap.Int64("admin_id", admin.ID), // zap.Error(err), // zap.Time("timestamp", time.Now()), // ) // return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login"+err.Error()) // } // } // result[index] = TransactionApproverRes{ // ID: admin.ID, // FirstName: admin.FirstName, // LastName: admin.LastName, // Email: admin.Email, // PhoneNumber: admin.PhoneNumber, // Role: admin.Role, // EmailVerified: admin.EmailVerified, // PhoneVerified: admin.PhoneVerified, // CreatedAt: admin.CreatedAt, // UpdatedAt: admin.UpdatedAt, // SuspendedAt: admin.SuspendedAt, // Suspended: admin.Suspended, // LastLogin: *lastLogin, // } // } // h.mongoLoggerSvc.Info("approvers retrieved successfully", // zap.Int("status_code", fiber.StatusOK), // zap.Int("count", len(result)), // zap.Int("page", filter.Page.Value+1), // zap.Time("timestamp", time.Now()), // ) // return response.WritePaginatedJSON(c, fiber.StatusOK, "Admins retrieved successfully", result, nil, filter.Page.Value, int(total)) // } // GetAdminByID godoc // @Summary Get admin by id // @Description Get a single admin by id // @Tags admin // @Accept json // @Produce json // @Param id path int true "User ID" // @Success 200 {object} AdminRes // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Router /api/v1/t-approver/{id} [get] func (h *Handler) GetTransactionApproverByID(c *fiber.Ctx) error { userIDstr := c.Params("id") userID, err := strconv.ParseInt(userIDstr, 10, 64) if err != nil { h.mongoLoggerSvc.Error("invalid admin ID param", zap.Int("status_code", fiber.StatusBadRequest), zap.String("param", userIDstr), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusBadRequest, "Invalid admin ID") } user, err := h.userSvc.GetUserByID(c.Context(), userID) if err != nil { h.mongoLoggerSvc.Error("failed to fetch admin by ID", zap.Int("status_code", fiber.StatusInternalServerError), zap.Int64("admin_id", userID), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusInternalServerError, "Failed to get admin"+err.Error()) } lastLogin, err := h.authSvc.GetLastLogin(c.Context(), user.ID) if err != nil && err != authentication.ErrRefreshTokenNotFound { h.mongoLoggerSvc.Error("failed to get admin last login", zap.Int("status_code", fiber.StatusInternalServerError), zap.Int64("admin_id", user.ID), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login:"+err.Error()) } if err == authentication.ErrRefreshTokenNotFound { lastLogin = &user.CreatedAt } res := TransactionApproverRes{ 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, // SuspendedAt: user.SuspendedAt, // Suspended: user.Suspended, LastLogin: *lastLogin, } h.mongoLoggerSvc.Info("admin retrieved successfully", zap.Int("status_code", fiber.StatusOK), zap.Int64("admin_id", user.ID), zap.Time("timestamp", time.Now()), ) return response.WriteJSON(c, fiber.StatusOK, "Admin retrieved successfully", res, nil) } type updateTransactionApproverReq struct { FirstName string `json:"first_name" example:"John"` LastName string `json:"last_name" example:"Doe"` Suspended bool `json:"suspended" example:"false"` } // UpdateAdmin godoc // @Summary Update Admin // @Description Update Admin // @Tags admin // @Accept json // @Produce json // @Param admin body updateAdminReq true "Update Admin" // @Success 200 {object} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Router /api/v1/t-approver/{id} [put] func (h *Handler) UpdateTransactionApprover(c *fiber.Ctx) error { var req updateTransactionApproverReq if err := c.BodyParser(&req); err != nil { h.mongoLoggerSvc.Error("UpdateTransactionApprover failed - invalid request body", zap.Int("status_code", fiber.StatusBadRequest), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusBadRequest, "Invalid request body: "+err.Error()) } if valErrs, ok := h.validator.Validate(c, req); !ok { var errMsg string for field, msg := range valErrs { errMsg += fmt.Sprintf("%s: %s; ", field, msg) } h.mongoLoggerSvc.Error("UpdateTransactionApprover failed - validation errors", zap.Int("status_code", fiber.StatusBadRequest), zap.Any("validation_errors", valErrs), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusBadRequest, errMsg) } approverIDStr := c.Params("id") approverID, err := strconv.ParseInt(approverIDStr, 10, 64) if err != nil { h.mongoLoggerSvc.Info("UpdateTransactionApprover failed - invalid approver ID", zap.Int("status_code", fiber.StatusBadRequest), zap.String("approver_id_param", approverIDStr), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusBadRequest, "Invalid approver ID") } updateReq := domain.UpdateUserReq{ UserID: approverID, FirstName: domain.ValidString{ Value: req.FirstName, Valid: req.FirstName != "", }, LastName: domain.ValidString{ Value: req.LastName, Valid: req.LastName != "", }, } err = h.userSvc.UpdateUser(c.Context(), updateReq) if err != nil { h.mongoLoggerSvc.Error("UpdateTransactionApprover failed - user service error", zap.Int("status_code", fiber.StatusInternalServerError), zap.Int64("approver_id", approverID), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusInternalServerError, "Failed to update approver: "+err.Error()) } h.mongoLoggerSvc.Info("UpdateTransactionApprover succeeded", zap.Int("status_code", fiber.StatusOK), zap.Int64("approver_id", approverID), zap.Time("timestamp", time.Now()), ) return response.WriteJSON(c, fiber.StatusOK, "Transaction approver updated successfully", nil, nil) }