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 CreateAdminReq 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"` } // CreateAdmin godoc // @Summary Create Admin // @Description Create Admin // @Tags admin // @Accept json // @Produce json // @Param manger body CreateAdminReq true "Create admin" // @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) CreateAdmin(c *fiber.Ctx) error { // var OrganizationID domain.ValidInt64 var req CreateAdminReq 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) } // if req.OrganizationID == nil { // OrganizationID = domain.ValidInt64{ // Value: 0, // Valid: false, // } // } else { // // _, err := h.companySvc.GetCompanyByID(c.Context(), *req.OrganizationID) // // if err != nil { // // h.mongoLoggerSvc.Error("invalid company ID for CreateAdmin", // // zap.Int64("status_code", fiber.StatusInternalServerError), // // zap.Int64("company_id", *req.OrganizationID), // // zap.Error(err), // // zap.Time("timestamp", time.Now()), // // ) // // return fiber.NewError(fiber.StatusInternalServerError, "Company ID is invalid:"+err.Error()) // // } // OrganizationID = domain.ValidInt64{ // Value: *req.OrganizationID, // Valid: true, // } // } user := domain.CreateUserReq{ FirstName: req.FirstName, LastName: req.LastName, Email: req.Email, PhoneNumber: req.PhoneNumber, Password: req.Password, Role: string(domain.RoleAdmin), } 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()) } // if req.OrganizationID != nil { // _, err := h.companySvc.UpdateCompany(c.Context(), domain.UpdateCompany{ // ID: *req.OrganizationID, // AdminID: domain.ValidInt64{ // Value: newUser.ID, // Valid: true, // }, // }) // if err != nil { // h.mongoLoggerSvc.Error("failed to update company with new admin", // zap.Int64("status_code", fiber.StatusInternalServerError), // zap.Int64("company_id", *req.OrganizationID), // zap.Int64("admin_id", newUser.ID), // zap.Error(err), // zap.Time("timestamp", time.Now()), // ) // return fiber.NewError(fiber.StatusInternalServerError, "Failed to update company"+err.Error()) // } // } h.mongoLoggerSvc.Info("admin created successfully", zap.Int64("admin_id", newUser.ID), zap.String("email", newUser.Email), zap.Time("timestamp", time.Now()), ) return response.WriteJSON(c, fiber.StatusOK, "Admin created successfully", nil, nil) } type AdminRes 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/admin [get] func (h *Handler) GetAllAdmins(c *fiber.Ctx) error { searchQuery := c.Query("query") searchString := domain.ValidString{ Value: searchQuery, // Valid: searchQuery != "", } createdBeforeQuery := c.Query("created_before") var createdBefore domain.ValidTime if createdBeforeQuery != "" { parsed, err := time.Parse(time.RFC3339, createdBeforeQuery) if err != nil { h.logger.Info("invalid created_before format", "error", err) return fiber.NewError(fiber.StatusBadRequest, "Invalid created_before format") } createdBefore = domain.ValidTime{Value: parsed, Valid: true} } createdAfterQuery := c.Query("created_after") var createdAfter domain.ValidTime if createdAfterQuery != "" { parsed, err := time.Parse(time.RFC3339, createdAfterQuery) if err != nil { h.logger.Info("invalid created_after format", "error", err) return fiber.NewError(fiber.StatusBadRequest, "Invalid created_after format") } createdAfter = domain.ValidTime{Value: parsed, Valid: true} } // companyID := int64(c.QueryInt("company_id")) filter := domain.UserFilter{ Role: string(domain.RoleAdmin), // OrganizationID: domain.ValidInt64{ // Value: companyID, // Valid: companyID != 0, // }, Page: int64(c.QueryInt("page", 1) - 1), PageSize: int64(c.QueryInt("page_size", 10)), Query: searchString.Value, CreatedBefore: createdBefore, CreatedAfter: createdAfter, } if valErrs, ok := h.validator.Validate(c, filter); !ok { var errMsg string for f, msg := range valErrs { errMsg += fmt.Sprintf("%s: %s; ", f, 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) } admins, total, err := h.userSvc.GetAllUsers(c.Context(), filter) if err != nil { h.mongoLoggerSvc.Error("failed to get admins", 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 admins: "+err.Error()) } result := make([]AdminRes, len(admins)) for i, admin := range admins { lastLogin, err := h.authSvc.GetLastLogin(c.Context(), admin.ID) if err != nil && err != authentication.ErrRefreshTokenNotFound { h.mongoLoggerSvc.Error("failed to get last login", 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 get last login: "+err.Error()) } if err == authentication.ErrRefreshTokenNotFound { lastLogin = &admin.CreatedAt } result[i] = AdminRes{ 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, LastLogin: *lastLogin, } } h.mongoLoggerSvc.Info("admins retrieved successfully", zap.Int("status_code", fiber.StatusOK), zap.Int("count", len(result)), zap.Int("page", int(filter.Page+1)), zap.Time("timestamp", time.Now()), ) return response.WritePaginatedJSON(c, fiber.StatusOK, "Admins retrieved successfully", result, nil, int(filter.Page+1), 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/admin/{id} [get] func (h *Handler) GetAdminByID(c *fiber.Ctx) error { idStr := c.Params("id") id, err := strconv.ParseInt(idStr, 10, 64) if err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid admin ID") } user, err := h.userSvc.GetUserByID(c.Context(), id) if err != nil { 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 { return fiber.NewError(fiber.StatusInternalServerError, "Failed to get last login: "+err.Error()) } if err == authentication.ErrRefreshTokenNotFound { lastLogin = &user.CreatedAt } res := AdminRes{ 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, LastLogin: *lastLogin, } return response.WriteJSON(c, fiber.StatusOK, "Admin retrieved successfully", res, nil) } type updateAdminReq 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/admin/{id} [put] func (h *Handler) UpdateAdmin(c *fiber.Ctx) error { var req updateAdminReq if err := c.BodyParser(&req); err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid request body: "+err.Error()) } adminIDStr := c.Params("id") adminID, err := strconv.ParseInt(adminIDStr, 10, 64) if err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid admin ID") } // var orgID domain.ValidInt64 // if req.OrganizationID != nil { // orgID = domain.ValidInt64{ // Value: *req.OrganizationID, // Valid: true, // } // } err = h.userSvc.UpdateUser(c.Context(), domain.UpdateUserReq{ UserID: adminID, FirstName: req.FirstName, LastName: req.LastName, // OrganizationID: orgID, }) if err != nil { return fiber.NewError(fiber.StatusInternalServerError, "Failed to update admin: "+err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Admin updated successfully", nil, nil) }