diff --git a/backend/app/http/v1/creator.go b/backend/app/http/v1/creator.go index bfab366..27c941a 100644 --- a/backend/app/http/v1/creator.go +++ b/backend/app/http/v1/creator.go @@ -50,11 +50,9 @@ func (c *Creator) Dashboard(ctx fiber.Ctx) (*dto.DashboardStats, error) { // @Param genre query string false "Genre" // @Param keyword query string false "Keyword" // @Success 200 {array} dto.ContentItem -// @Bind status query -// @Bind genre query -// @Bind keyword query -func (c *Creator) ListContents(ctx fiber.Ctx, status, genre, keyword string) ([]dto.ContentItem, error) { - return services.Creator.ListContents(ctx.Context(), status, genre, keyword) +// @Bind filter query +func (c *Creator) ListContents(ctx fiber.Ctx, filter *dto.CreatorContentListFilter) ([]dto.ContentItem, error) { + return services.Creator.ListContents(ctx.Context(), filter) } // Create/Publish content @@ -115,10 +113,9 @@ func (c *Creator) DeleteContent(ctx fiber.Ctx, id string) error { // @Param status query string false "Status" // @Param keyword query string false "Keyword" // @Success 200 {array} dto.Order -// @Bind status query -// @Bind keyword query -func (c *Creator) ListOrders(ctx fiber.Ctx, status, keyword string) ([]dto.Order, error) { - return services.Creator.ListOrders(ctx.Context(), status, keyword) +// @Bind filter query +func (c *Creator) ListOrders(ctx fiber.Ctx, filter *dto.CreatorOrderListFilter) ([]dto.Order, error) { + return services.Creator.ListOrders(ctx.Context(), filter) } // Process refund diff --git a/backend/app/http/v1/dto/content.go b/backend/app/http/v1/dto/content.go index 2b89263..c1df632 100644 --- a/backend/app/http/v1/dto/content.go +++ b/backend/app/http/v1/dto/content.go @@ -4,10 +4,10 @@ import "quyun/v2/app/requests" type ContentListFilter struct { requests.Pagination - Keyword string `query:"keyword"` - Genre string `query:"genre"` - TenantID string `query:"tenantId"` - Sort string `query:"sort"` + Keyword *string `query:"keyword"` + Genre *string `query:"genre"` + TenantID *string `query:"tenantId"` + Sort *string `query:"sort"` } type ContentItem struct { diff --git a/backend/app/http/v1/dto/creator.go b/backend/app/http/v1/dto/creator.go index 6be26f8..8582b24 100644 --- a/backend/app/http/v1/dto/creator.go +++ b/backend/app/http/v1/dto/creator.go @@ -1,5 +1,7 @@ package dto +import "quyun/v2/app/requests" + type ApplyForm struct { Name string `json:"name"` Bio string `json:"bio"` @@ -37,6 +39,19 @@ type ContentUpdateForm struct { MediaIDs []string `json:"media_ids"` } +type CreatorContentListFilter struct { + requests.Pagination + Status *string `query:"status"` + Genre *string `query:"genre"` + Keyword *string `query:"keyword"` +} + +type CreatorOrderListFilter struct { + requests.Pagination + Status *string `query:"status"` + Keyword *string `query:"keyword"` +} + type RefundForm struct { Action string `json:"action"` // accept, reject Reason string `json:"reason"` @@ -63,15 +78,3 @@ type WithdrawForm struct { Method string `json:"method"` // wallet, external AccountID string `json:"account_id"` } - -// Re-export or Wrap -// Since ContentItem and Order are in the same package 'dto', -// we don't need type aliases unless we want to rename them. -// If creator.go uses them, it can use dto.ContentItem directly. -// But creator.go is in `v1` (package v1) and imports `dto`. -// So it uses `dto.ContentItem`. -// So we don't need aliases here if the original types are in this package. - -// However, if the originals were in `content/dto` and `user/dto` and we moved them to `v1/dto` (this package), -// then we just have them defined in `content.go` (dto) and `user.go` (dto). -// So aliases are not needed if they are in the same package. diff --git a/backend/app/http/v1/dto/super.go b/backend/app/http/v1/dto/super.go index daeddb4..781a155 100644 --- a/backend/app/http/v1/dto/super.go +++ b/backend/app/http/v1/dto/super.go @@ -1,9 +1,31 @@ package dto import ( + "quyun/v2/app/requests" "quyun/v2/pkg/consts" ) +// Filters +type UserListFilter struct { + requests.Pagination + Username *string `query:"username"` +} + +type TenantListFilter struct { + requests.Pagination + Name *string `query:"name"` +} + +type SuperContentListFilter struct { + requests.Pagination + // Add filters if needed, currently list signature is just pagination in super.go service +} + +type SuperOrderListFilter struct { + requests.Pagination + // Add filters if needed +} + // SuperUserLite 用于平台用户列表的轻量级用户信息 type SuperUserLite struct { ID int64 `json:"id"` diff --git a/backend/app/http/v1/routes.gen.go b/backend/app/http/v1/routes.gen.go index 4dcea09..82285d0 100644 --- a/backend/app/http/v1/routes.gen.go +++ b/backend/app/http/v1/routes.gen.go @@ -111,21 +111,18 @@ func (r *Routes) Register(router fiber.Router) { QueryParam[string]("id"), )) r.log.Debugf("Registering route: Get /v1/creator/contents -> creator.ListContents") - router.Get("/v1/creator/contents"[len(r.Path()):], DataFunc3( + router.Get("/v1/creator/contents"[len(r.Path()):], DataFunc1( r.creator.ListContents, - QueryParam[string]("status"), - QueryParam[string]("genre"), - QueryParam[string]("keyword"), + Query[dto.CreatorContentListFilter]("filter"), )) r.log.Debugf("Registering route: Get /v1/creator/dashboard -> creator.Dashboard") router.Get("/v1/creator/dashboard"[len(r.Path()):], DataFunc0( r.creator.Dashboard, )) r.log.Debugf("Registering route: Get /v1/creator/orders -> creator.ListOrders") - router.Get("/v1/creator/orders"[len(r.Path()):], DataFunc2( + router.Get("/v1/creator/orders"[len(r.Path()):], DataFunc1( r.creator.ListOrders, - QueryParam[string]("status"), - QueryParam[string]("keyword"), + Query[dto.CreatorOrderListFilter]("filter"), )) r.log.Debugf("Registering route: Get /v1/creator/payout-accounts -> creator.ListPayoutAccounts") router.Get("/v1/creator/payout-accounts"[len(r.Path()):], DataFunc0( @@ -178,16 +175,14 @@ func (r *Routes) Register(router fiber.Router) { r.super.CheckToken, )) r.log.Debugf("Registering route: Get /v1/contents -> super.ListContents") - router.Get("/v1/contents"[len(r.Path()):], DataFunc2( + router.Get("/v1/contents"[len(r.Path()):], DataFunc1( r.super.ListContents, - QueryParam[int]("page"), - QueryParam[int]("limit"), + Query[dto.SuperContentListFilter]("filter"), )) r.log.Debugf("Registering route: Get /v1/orders -> super.ListOrders") - router.Get("/v1/orders"[len(r.Path()):], DataFunc2( + router.Get("/v1/orders"[len(r.Path()):], DataFunc1( r.super.ListOrders, - QueryParam[int]("page"), - QueryParam[int]("limit"), + Query[dto.SuperOrderListFilter]("filter"), )) r.log.Debugf("Registering route: Get /v1/orders/:id -> super.GetOrder") router.Get("/v1/orders/:id"[len(r.Path()):], DataFunc1( @@ -199,11 +194,9 @@ func (r *Routes) Register(router fiber.Router) { r.super.OrderStatistics, )) r.log.Debugf("Registering route: Get /v1/tenants -> super.ListTenants") - router.Get("/v1/tenants"[len(r.Path()):], DataFunc3( + router.Get("/v1/tenants"[len(r.Path()):], DataFunc1( r.super.ListTenants, - QueryParam[int]("page"), - QueryParam[int]("limit"), - QueryParam[string]("name"), + Query[dto.TenantListFilter]("filter"), )) r.log.Debugf("Registering route: Get /v1/tenants/:id -> super.GetTenant") router.Get("/v1/tenants/:id"[len(r.Path()):], DataFunc1( @@ -215,11 +208,9 @@ func (r *Routes) Register(router fiber.Router) { r.super.TenantStatuses, )) r.log.Debugf("Registering route: Get /v1/users -> super.ListUsers") - router.Get("/v1/users"[len(r.Path()):], DataFunc3( + router.Get("/v1/users"[len(r.Path()):], DataFunc1( r.super.ListUsers, - QueryParam[int]("page"), - QueryParam[int]("limit"), - QueryParam[string]("username"), + Query[dto.UserListFilter]("filter"), )) r.log.Debugf("Registering route: Get /v1/users/:id -> super.GetUser") router.Get("/v1/users/:id"[len(r.Path()):], DataFunc1( diff --git a/backend/app/http/v1/super.go b/backend/app/http/v1/super.go index c41f574..ec695aa 100644 --- a/backend/app/http/v1/super.go +++ b/backend/app/http/v1/super.go @@ -15,294 +15,308 @@ type Super struct{} // // @Router /v1/auth/login [post] // @Summary Login -// @Tags Super +// @Description Login +// @Tags Auth // @Accept json // @Produce json // @Param form body dto.LoginForm true "Login form" // @Success 200 {object} dto.LoginResponse // @Bind form body -func (s *Super) Login(ctx fiber.Ctx, form *dto.LoginForm) (*dto.LoginResponse, error) { +func (c *Super) Login(ctx fiber.Ctx, form *dto.LoginForm) (*dto.LoginResponse, error) { return services.Super.Login(ctx.Context(), form) } // Check Token // // @Router /v1/auth/token [get] -// @Summary Check Token -// @Tags Super +// @Summary Check token +// @Description Check token +// @Tags Auth // @Accept json // @Produce json // @Success 200 {object} dto.LoginResponse -func (s *Super) CheckToken(ctx fiber.Ctx) (*dto.LoginResponse, error) { +func (c *Super) CheckToken(ctx fiber.Ctx) (*dto.LoginResponse, error) { return services.Super.CheckToken(ctx.Context()) } -// List Users +// List users // // @Router /v1/users [get] -// @Summary User list -// @Tags Super +// @Summary List users +// @Description List users +// @Tags User // @Accept json // @Produce json -// @Param page query int false "Page" -// @Param limit query int false "Limit" +// @Param page query int false "Page number" +// @Param limit query int false "Page size" // @Param username query string false "Username" // @Success 200 {object} requests.Pager{items=[]dto.UserItem} -// @Bind page query -// @Bind limit query -// @Bind username query -func (s *Super) ListUsers(ctx fiber.Ctx, page, limit int, username string) (*requests.Pager, error) { - return services.Super.ListUsers(ctx.Context(), page, limit, username) +// @Bind filter query +func (c *Super) ListUsers(ctx fiber.Ctx, filter *dto.UserListFilter) (*requests.Pager, error) { + return services.Super.ListUsers(ctx.Context(), filter) } -// Get User +// Get user // // @Router /v1/users/:id [get] -// @Summary Get User -// @Tags Super +// @Summary Get user +// @Description Get user +// @Tags User // @Accept json // @Produce json -// @Param id path int64 true "ID" +// @Param id path int64 true "User ID" // @Success 200 {object} dto.UserItem // @Bind id path -func (s *Super) GetUser(ctx fiber.Ctx, id int64) (*dto.UserItem, error) { +func (c *Super) GetUser(ctx fiber.Ctx, id int64) (*dto.UserItem, error) { return services.Super.GetUser(ctx.Context(), id) } -// Update User Status +// Update user status // // @Router /v1/users/:id/status [patch] // @Summary Update user status -// @Tags Super +// @Description Update user status +// @Tags User // @Accept json // @Produce json -// @Param id path int64 true "ID" -// @Param form body dto.UserStatusUpdateForm true "Form" -// @Success 200 +// @Param id path int64 true "User ID" +// @Param form body dto.UserStatusUpdateForm true "Update form" +// @Success 200 {string} string "Updated" // @Bind id path // @Bind form body -func (s *Super) UpdateUserStatus(ctx fiber.Ctx, id int64, form *dto.UserStatusUpdateForm) error { +func (c *Super) UpdateUserStatus(ctx fiber.Ctx, id int64, form *dto.UserStatusUpdateForm) error { return services.Super.UpdateUserStatus(ctx.Context(), id, form) } -// Update User Roles +// Update user roles // // @Router /v1/users/:id/roles [patch] // @Summary Update user roles -// @Tags Super +// @Description Update user roles +// @Tags User // @Accept json // @Produce json -// @Param id path int64 true "ID" -// @Param form body dto.UserRolesUpdateForm true "Form" -// @Success 200 +// @Param id path int64 true "User ID" +// @Param form body dto.UserRolesUpdateForm true "Update form" +// @Success 200 {string} string "Updated" // @Bind id path // @Bind form body -func (s *Super) UpdateUserRoles(ctx fiber.Ctx, id int64, form *dto.UserRolesUpdateForm) error { +func (c *Super) UpdateUserRoles(ctx fiber.Ctx, id int64, form *dto.UserRolesUpdateForm) error { return services.Super.UpdateUserRoles(ctx.Context(), id, form) } -// List Tenants +// List tenants // // @Router /v1/tenants [get] -// @Summary Tenant list -// @Tags Super +// @Summary List tenants +// @Description List tenants +// @Tags Tenant // @Accept json // @Produce json -// @Param page query int false "Page" -// @Param limit query int false "Limit" +// @Param page query int false "Page number" +// @Param limit query int false "Page size" // @Param name query string false "Name" // @Success 200 {object} requests.Pager{items=[]dto.TenantItem} -// @Bind page query -// @Bind limit query -// @Bind name query -func (s *Super) ListTenants(ctx fiber.Ctx, page, limit int, name string) (*requests.Pager, error) { - return services.Super.ListTenants(ctx.Context(), page, limit, name) +// @Bind filter query +func (c *Super) ListTenants(ctx fiber.Ctx, filter *dto.TenantListFilter) (*requests.Pager, error) { + return services.Super.ListTenants(ctx.Context(), filter) } -// Create Tenant +// Create tenant // // @Router /v1/tenants [post] -// @Summary Create Tenant -// @Tags Super +// @Summary Create tenant +// @Description Create tenant +// @Tags Tenant // @Accept json // @Produce json -// @Param form body dto.TenantCreateForm true "Form" -// @Success 200 +// @Param form body dto.TenantCreateForm true "Create form" +// @Success 200 {string} string "Created" // @Bind form body -func (s *Super) CreateTenant(ctx fiber.Ctx, form *dto.TenantCreateForm) error { +func (c *Super) CreateTenant(ctx fiber.Ctx, form *dto.TenantCreateForm) error { return services.Super.CreateTenant(ctx.Context(), form) } -// Get Tenant +// Get tenant // // @Router /v1/tenants/:id [get] -// @Summary Get Tenant -// @Tags Super +// @Summary Get tenant +// @Description Get tenant +// @Tags Tenant // @Accept json // @Produce json -// @Param id path int64 true "ID" +// @Param id path int64 true "Tenant ID" // @Success 200 {object} dto.TenantItem // @Bind id path -func (s *Super) GetTenant(ctx fiber.Ctx, id int64) (*dto.TenantItem, error) { +func (c *Super) GetTenant(ctx fiber.Ctx, id int64) (*dto.TenantItem, error) { return services.Super.GetTenant(ctx.Context(), id) } -// Update Tenant Status +// Update tenant status // // @Router /v1/tenants/:id/status [patch] -// @Summary Update Tenant Status -// @Tags Super +// @Summary Update tenant status +// @Description Update tenant status +// @Tags Tenant // @Accept json // @Produce json -// @Param id path int64 true "ID" -// @Param form body dto.TenantStatusUpdateForm true "Form" -// @Success 200 +// @Param id path int64 true "Tenant ID" +// @Param form body dto.TenantStatusUpdateForm true "Update form" +// @Success 200 {string} string "Updated" // @Bind id path // @Bind form body -func (s *Super) UpdateTenantStatus(ctx fiber.Ctx, id int64, form *dto.TenantStatusUpdateForm) error { +func (c *Super) UpdateTenantStatus(ctx fiber.Ctx, id int64, form *dto.TenantStatusUpdateForm) error { return services.Super.UpdateTenantStatus(ctx.Context(), id, form) } -// Update Tenant Expire +// Update tenant expire // // @Router /v1/tenants/:id [patch] -// @Summary Update Tenant Expire -// @Tags Super +// @Summary Update tenant expire +// @Description Update tenant expire +// @Tags Tenant // @Accept json // @Produce json -// @Param id path int64 true "ID" -// @Param form body dto.TenantExpireUpdateForm true "Form" -// @Success 200 +// @Param id path int64 true "Tenant ID" +// @Param form body dto.TenantExpireUpdateForm true "Update form" +// @Success 200 {string} string "Updated" // @Bind id path // @Bind form body -func (s *Super) UpdateTenantExpire(ctx fiber.Ctx, id int64, form *dto.TenantExpireUpdateForm) error { +func (c *Super) UpdateTenantExpire(ctx fiber.Ctx, id int64, form *dto.TenantExpireUpdateForm) error { return services.Super.UpdateTenantExpire(ctx.Context(), id, form) } -// List Contents +// List contents // // @Router /v1/contents [get] -// @Summary Content list -// @Tags Super +// @Summary List contents +// @Description List contents +// @Tags Content // @Accept json // @Produce json -// @Param page query int false "Page" -// @Param limit query int false "Limit" -// @Success 200 {object} requests.Pager{items=[]dto.SuperTenantContentItem} -// @Bind page query -// @Bind limit query -func (s *Super) ListContents(ctx fiber.Ctx, page, limit int) (*requests.Pager, error) { - return services.Super.ListContents(ctx.Context(), page, limit) +// @Param page query int false "Page number" +// @Param limit query int false "Page size" +// @Success 200 {object} requests.Pager{items=[]dto.AdminContentItem} +// @Bind filter query +func (c *Super) ListContents(ctx fiber.Ctx, filter *dto.SuperContentListFilter) (*requests.Pager, error) { + return services.Super.ListContents(ctx.Context(), filter) } -// Update Content Status +// Update content status // // @Router /v1/tenants/:tenantID/contents/:contentID/status [patch] -// @Summary Update Content Status -// @Tags Super +// @Summary Update content status +// @Description Update content status +// @Tags Content // @Accept json // @Produce json -// @Param tenantID path int64 true "TenantID" -// @Param contentID path int64 true "ContentID" -// @Param form body dto.SuperTenantContentStatusUpdateForm true "Form" -// @Success 200 +// @Param tenantID path int64 true "Tenant ID" +// @Param contentID path int64 true "Content ID" +// @Param form body dto.SuperTenantContentStatusUpdateForm true "Update form" +// @Success 200 {string} string "Updated" // @Bind tenantID path // @Bind contentID path // @Bind form body -func (s *Super) UpdateContentStatus(ctx fiber.Ctx, tenantID, contentID int64, form *dto.SuperTenantContentStatusUpdateForm) error { +func (c *Super) UpdateContentStatus(ctx fiber.Ctx, tenantID, contentID int64, form *dto.SuperTenantContentStatusUpdateForm) error { return services.Super.UpdateContentStatus(ctx.Context(), tenantID, contentID, form) } -// List Orders +// List orders // // @Router /v1/orders [get] -// @Summary Order list -// @Tags Super +// @Summary List orders +// @Description List orders +// @Tags Order // @Accept json // @Produce json -// @Param page query int false "Page" -// @Param limit query int false "Limit" +// @Param page query int false "Page number" +// @Param limit query int false "Page size" // @Success 200 {object} requests.Pager{items=[]dto.SuperOrderItem} -// @Bind page query -// @Bind limit query -func (s *Super) ListOrders(ctx fiber.Ctx, page, limit int) (*requests.Pager, error) { - return services.Super.ListOrders(ctx.Context(), page, limit) +// @Bind filter query +func (c *Super) ListOrders(ctx fiber.Ctx, filter *dto.SuperOrderListFilter) (*requests.Pager, error) { + return services.Super.ListOrders(ctx.Context(), filter) } -// Get Order +// Get order // // @Router /v1/orders/:id [get] -// @Summary Get Order -// @Tags Super +// @Summary Get order +// @Description Get order +// @Tags Order // @Accept json // @Produce json -// @Param id path int64 true "ID" +// @Param id path int64 true "Order ID" // @Success 200 {object} dto.SuperOrderDetail // @Bind id path -func (s *Super) GetOrder(ctx fiber.Ctx, id int64) (*dto.SuperOrderDetail, error) { +func (c *Super) GetOrder(ctx fiber.Ctx, id int64) (*dto.SuperOrderDetail, error) { return services.Super.GetOrder(ctx.Context(), id) } -// Refund Order +// Refund order // // @Router /v1/orders/:id/refund [post] -// @Summary Refund Order -// @Tags Super +// @Summary Refund order +// @Description Refund order +// @Tags Order // @Accept json // @Produce json -// @Param id path int64 true "ID" -// @Param form body dto.SuperOrderRefundForm true "Form" -// @Success 200 +// @Param id path int64 true "Order ID" +// @Param form body dto.SuperOrderRefundForm true "Refund form" +// @Success 200 {string} string "Refunded" // @Bind id path // @Bind form body -func (s *Super) RefundOrder(ctx fiber.Ctx, id int64, form *dto.SuperOrderRefundForm) error { +func (c *Super) RefundOrder(ctx fiber.Ctx, id int64, form *dto.SuperOrderRefundForm) error { return services.Super.RefundOrder(ctx.Context(), id, form) } -// Order Statistics +// Order statistics // // @Router /v1/orders/statistics [get] -// @Summary Order Statistics -// @Tags Super +// @Summary Order statistics +// @Description Order statistics +// @Tags Order // @Accept json // @Produce json // @Success 200 {object} dto.OrderStatisticsResponse -func (s *Super) OrderStatistics(ctx fiber.Ctx) (*dto.OrderStatisticsResponse, error) { +func (c *Super) OrderStatistics(ctx fiber.Ctx) (*dto.OrderStatisticsResponse, error) { return services.Super.OrderStatistics(ctx.Context()) } -// User Statistics +// User statistics // // @Router /v1/users/statistics [get] -// @Summary User Statistics -// @Tags Super +// @Summary User statistics +// @Description User statistics +// @Tags User // @Accept json // @Produce json // @Success 200 {array} dto.UserStatistics -func (s *Super) UserStatistics(ctx fiber.Ctx) ([]dto.UserStatistics, error) { +func (c *Super) UserStatistics(ctx fiber.Ctx) ([]dto.UserStatistics, error) { return services.Super.UserStatistics(ctx.Context()) } -// User Statuses +// User statuses // // @Router /v1/users/statuses [get] -// @Summary User Statuses Enum -// @Tags Super +// @Summary User statuses +// @Description User statuses +// @Tags User // @Accept json // @Produce json // @Success 200 {array} requests.KV -func (s *Super) UserStatuses(ctx fiber.Ctx) ([]requests.KV, error) { +func (c *Super) UserStatuses(ctx fiber.Ctx) ([]requests.KV, error) { return services.Super.UserStatuses(ctx.Context()) } -// Tenant Statuses +// Tenant statuses // // @Router /v1/tenants/statuses [get] -// @Summary Tenant Statuses Enum -// @Tags Super +// @Summary Tenant statuses +// @Description Tenant statuses +// @Tags Tenant // @Accept json // @Produce json // @Success 200 {array} requests.KV -func (s *Super) TenantStatuses(ctx fiber.Ctx) ([]requests.KV, error) { +func (c *Super) TenantStatuses(ctx fiber.Ctx) ([]requests.KV, error) { return services.Super.TenantStatuses(ctx.Context()) } diff --git a/backend/app/services/content.go b/backend/app/services/content.go index 2f402ff..afa51b5 100644 --- a/backend/app/services/content.go +++ b/backend/app/services/content.go @@ -23,14 +23,14 @@ func (s *content) List(ctx context.Context, filter *content_dto.ContentListFilte // Filters q = q.Where(tbl.Status.Eq(consts.ContentStatusPublished)) - if filter.Keyword != "" { - q = q.Where(tbl.Title.Like("%" + filter.Keyword + "%")) + if filter.Keyword != nil && *filter.Keyword != "" { + q = q.Where(tbl.Title.Like("%" + *filter.Keyword + "%")) } - if filter.Genre != "" { - q = q.Where(tbl.Genre.Eq(filter.Genre)) + if filter.Genre != nil && *filter.Genre != "" { + q = q.Where(tbl.Genre.Eq(*filter.Genre)) } - if filter.TenantID != "" { - tid := cast.ToInt64(filter.TenantID) + if filter.TenantID != nil && *filter.TenantID != "" { + tid := cast.ToInt64(*filter.TenantID) q = q.Where(tbl.TenantID.Eq(tid)) } @@ -38,7 +38,12 @@ func (s *content) List(ctx context.Context, filter *content_dto.ContentListFilte q = q.Preload(tbl.Author) // Sort - switch filter.Sort { + sort := "latest" + if filter.Sort != nil && *filter.Sort != "" { + sort = *filter.Sort + } + + switch sort { case "hot": q = q.Order(tbl.Views.Desc()) case "price_asc": @@ -48,7 +53,6 @@ func (s *content) List(ctx context.Context, filter *content_dto.ContentListFilte } // Pagination - // Use embedded pagination directly filter.Pagination.Format() total, err := q.Count() if err != nil { diff --git a/backend/app/services/content_test.go b/backend/app/services/content_test.go index 36942ff..7d3c05f 100644 --- a/backend/app/services/content_test.go +++ b/backend/app/services/content_test.go @@ -66,8 +66,9 @@ func (s *ContentTestSuite) Test_List() { models.ContentQuery.WithContext(ctx).Create(c1, c2) Convey("should list only published contents", func() { + tid := "1" filter := &content_dto.ContentListFilter{ - TenantID: "1", + TenantID: &tid, Pagination: requests.Pagination{ Page: 1, Limit: 10, diff --git a/backend/app/services/creator.go b/backend/app/services/creator.go index 5b92fcf..7a7bd6a 100644 --- a/backend/app/services/creator.go +++ b/backend/app/services/creator.go @@ -80,7 +80,7 @@ func (s *creator) Dashboard(ctx context.Context) (*creator_dto.DashboardStats, e return stats, nil } -func (s *creator) ListContents(ctx context.Context, status, genre, keyword string) ([]creator_dto.ContentItem, error) { +func (s *creator) ListContents(ctx context.Context, filter *creator_dto.CreatorContentListFilter) ([]creator_dto.ContentItem, error) { tid, err := s.getTenantID(ctx) if err != nil { return nil, err @@ -89,14 +89,14 @@ func (s *creator) ListContents(ctx context.Context, status, genre, keyword strin tbl, q := models.ContentQuery.QueryContext(ctx) q = q.Where(tbl.TenantID.Eq(tid)) - if status != "" { - q = q.Where(tbl.Status.Eq(consts.ContentStatus(status))) + if filter.Status != nil && *filter.Status != "" { + q = q.Where(tbl.Status.Eq(consts.ContentStatus(*filter.Status))) } - if genre != "" { - q = q.Where(tbl.Genre.Eq(genre)) + if filter.Genre != nil && *filter.Genre != "" { + q = q.Where(tbl.Genre.Eq(*filter.Genre)) } - if keyword != "" { - q = q.Where(tbl.Title.Like("%" + keyword + "%")) + if filter.Keyword != nil && *filter.Keyword != "" { + q = q.Where(tbl.Title.Like("%" + *filter.Keyword + "%")) } list, err := q.Order(tbl.CreatedAt.Desc()).Find() @@ -190,7 +190,7 @@ func (s *creator) DeleteContent(ctx context.Context, id string) error { return nil } -func (s *creator) ListOrders(ctx context.Context, status, keyword string) ([]creator_dto.Order, error) { +func (s *creator) ListOrders(ctx context.Context, filter *creator_dto.CreatorOrderListFilter) ([]creator_dto.Order, error) { tid, err := s.getTenantID(ctx) if err != nil { return nil, err @@ -198,7 +198,12 @@ func (s *creator) ListOrders(ctx context.Context, status, keyword string) ([]cre tbl, q := models.OrderQuery.QueryContext(ctx) q = q.Where(tbl.TenantID.Eq(tid)) - // Filters... + + if filter.Status != nil && *filter.Status != "" { + q = q.Where(tbl.Status.Eq(consts.OrderStatus(*filter.Status))) + } + // Keyword could match ID or other fields if needed + list, err := q.Order(tbl.CreatedAt.Desc()).Find() if err != nil { return nil, errorx.ErrDatabaseError.WithCause(err) diff --git a/backend/app/services/super.go b/backend/app/services/super.go index d1bda2d..2841f91 100644 --- a/backend/app/services/super.go +++ b/backend/app/services/super.go @@ -2,6 +2,7 @@ package services import ( "context" + "errors" "time" "quyun/v2/app/errorx" @@ -13,6 +14,7 @@ import ( "github.com/google/uuid" "github.com/spf13/cast" "go.ipao.vip/gen/types" + "gorm.io/gorm" ) // @provider @@ -27,33 +29,31 @@ func (s *super) CheckToken(ctx context.Context) (*super_dto.LoginResponse, error return &super_dto.LoginResponse{}, nil } -func (s *super) ListUsers(ctx context.Context, page, limit int, username string) (*requests.Pager, error) { +func (s *super) ListUsers(ctx context.Context, filter *super_dto.UserListFilter) (*requests.Pager, error) { tbl, q := models.UserQuery.QueryContext(ctx) - if username != "" { - q = q.Where(tbl.Username.Like("%" + username + "%")).Or(tbl.Nickname.Like("%" + username + "%")) + if filter.Username != nil && *filter.Username != "" { + q = q.Where(tbl.Username.Like("%" + *filter.Username + "%")).Or(tbl.Nickname.Like("%" + *filter.Username + "%")) } - p := requests.Pagination{Page: int64(page), Limit: int64(limit)} + filter.Pagination.Format() total, err := q.Count() if err != nil { - return nil, errorx.ErrDatabaseError + return nil, errorx.ErrDatabaseError.WithCause(err) } - list, err := q.Offset(int(p.Offset())).Limit(int(p.Limit)).Order(tbl.ID.Desc()).Find() + list, err := q.Offset(int(filter.Pagination.Offset())).Limit(int(filter.Pagination.Limit)).Order(tbl.ID.Desc()).Find() if err != nil { - return nil, errorx.ErrDatabaseError + return nil, errorx.ErrDatabaseError.WithCause(err) } var data []super_dto.UserItem for _, u := range list { data = append(data, super_dto.UserItem{ SuperUserLite: super_dto.SuperUserLite{ - ID: u.ID, - Username: u.Username, - Roles: u.Roles, - Status: u.Status, - // StatusDescription: u.Status.Description(), // Status is consts.UserStatus, it has Description() - // But u.Status might be string if gen didn't map it properly? No, it's consts.UserStatus. + ID: u.ID, + Username: u.Username, + Roles: u.Roles, + Status: u.Status, StatusDescription: u.Status.Description(), CreatedAt: u.CreatedAt.Format(time.RFC3339), UpdatedAt: u.UpdatedAt.Format(time.RFC3339), @@ -64,7 +64,7 @@ func (s *super) ListUsers(ctx context.Context, page, limit int, username string) } return &requests.Pager{ - Pagination: p, + Pagination: filter.Pagination, Total: total, Items: data, }, nil @@ -74,7 +74,10 @@ func (s *super) GetUser(ctx context.Context, id int64) (*super_dto.UserItem, err tbl, q := models.UserQuery.QueryContext(ctx) u, err := q.Where(tbl.ID.Eq(id)).First() if err != nil { - return nil, errorx.ErrRecordNotFound + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, errorx.ErrRecordNotFound + } + return nil, errorx.ErrDatabaseError.WithCause(err) } return &super_dto.UserItem{ SuperUserLite: super_dto.SuperUserLite{ @@ -95,7 +98,7 @@ func (s *super) UpdateUserStatus(ctx context.Context, id int64, form *super_dto. tbl, q := models.UserQuery.QueryContext(ctx) _, err := q.Where(tbl.ID.Eq(id)).Update(tbl.Status, consts.UserStatus(form.Status)) if err != nil { - return errorx.ErrDatabaseError + return errorx.ErrDatabaseError.WithCause(err) } return nil } @@ -108,26 +111,26 @@ func (s *super) UpdateUserRoles(ctx context.Context, id int64, form *super_dto.U tbl, q := models.UserQuery.QueryContext(ctx) _, err := q.Where(tbl.ID.Eq(id)).Update(tbl.Roles, roles) if err != nil { - return errorx.ErrDatabaseError + return errorx.ErrDatabaseError.WithCause(err) } return nil } -func (s *super) ListTenants(ctx context.Context, page, limit int, name string) (*requests.Pager, error) { +func (s *super) ListTenants(ctx context.Context, filter *super_dto.TenantListFilter) (*requests.Pager, error) { tbl, q := models.TenantQuery.QueryContext(ctx) - if name != "" { - q = q.Where(tbl.Name.Like("%" + name + "%")) + if filter.Name != nil && *filter.Name != "" { + q = q.Where(tbl.Name.Like("%" + *filter.Name + "%")) } - p := requests.Pagination{Page: int64(page), Limit: int64(limit)} + filter.Pagination.Format() total, err := q.Count() if err != nil { - return nil, errorx.ErrDatabaseError + return nil, errorx.ErrDatabaseError.WithCause(err) } - list, err := q.Offset(int(p.Offset())).Limit(int(p.Limit)).Order(tbl.ID.Desc()).Find() + list, err := q.Offset(int(filter.Pagination.Offset())).Limit(int(filter.Pagination.Limit)).Order(tbl.ID.Desc()).Find() if err != nil { - return nil, errorx.ErrDatabaseError + return nil, errorx.ErrDatabaseError.WithCause(err) } var data []super_dto.TenantItem @@ -146,7 +149,7 @@ func (s *super) ListTenants(ctx context.Context, page, limit int, name string) ( } return &requests.Pager{ - Pagination: p, + Pagination: filter.Pagination, Total: total, Items: data, }, nil @@ -166,7 +169,7 @@ func (s *super) CreateTenant(ctx context.Context, form *super_dto.TenantCreateFo Status: consts.TenantStatusVerified, } if err := models.TenantQuery.WithContext(ctx).Create(t); err != nil { - return errorx.ErrDatabaseError + return errorx.ErrDatabaseError.WithCause(err) } return nil } @@ -175,7 +178,10 @@ func (s *super) GetTenant(ctx context.Context, id int64) (*super_dto.TenantItem, tbl, q := models.TenantQuery.QueryContext(ctx) t, err := q.Where(tbl.ID.Eq(id)).First() if err != nil { - return nil, errorx.ErrRecordNotFound + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, errorx.ErrRecordNotFound + } + return nil, errorx.ErrDatabaseError.WithCause(err) } return &super_dto.TenantItem{ ID: t.ID, @@ -194,7 +200,7 @@ func (s *super) UpdateTenantStatus(ctx context.Context, id int64, form *super_dt tbl, q := models.TenantQuery.QueryContext(ctx) _, err := q.Where(tbl.ID.Eq(id)).Update(tbl.Status, consts.TenantStatus(form.Status)) if err != nil { - return errorx.ErrDatabaseError + return errorx.ErrDatabaseError.WithCause(err) } return nil } @@ -204,21 +210,22 @@ func (s *super) UpdateTenantExpire(ctx context.Context, id int64, form *super_dt tbl, q := models.TenantQuery.QueryContext(ctx) _, err := q.Where(tbl.ID.Eq(id)).Update(tbl.ExpiredAt, expire) if err != nil { - return errorx.ErrDatabaseError + return errorx.ErrDatabaseError.WithCause(err) } return nil } -func (s *super) ListContents(ctx context.Context, page, limit int) (*requests.Pager, error) { +func (s *super) ListContents(ctx context.Context, filter *super_dto.SuperContentListFilter) (*requests.Pager, error) { tbl, q := models.ContentQuery.QueryContext(ctx) - p := requests.Pagination{Page: int64(page), Limit: int64(limit)} + + filter.Pagination.Format() total, err := q.Count() if err != nil { - return nil, errorx.ErrDatabaseError + return nil, errorx.ErrDatabaseError.WithCause(err) } - list, err := q.Offset(int(p.Offset())).Limit(int(p.Limit)).Order(tbl.ID.Desc()).Find() + list, err := q.Offset(int(filter.Pagination.Offset())).Limit(int(filter.Pagination.Limit)).Order(tbl.ID.Desc()).Find() if err != nil { - return nil, errorx.ErrDatabaseError + return nil, errorx.ErrDatabaseError.WithCause(err) } // Simplified DTO for list var data []any @@ -226,7 +233,7 @@ func (s *super) ListContents(ctx context.Context, page, limit int) (*requests.Pa data = append(data, c) // TODO: Map to DTO } return &requests.Pager{ - Pagination: p, + Pagination: filter.Pagination, Total: total, Items: data, }, nil @@ -236,25 +243,26 @@ func (s *super) UpdateContentStatus(ctx context.Context, tenantID, contentID int tbl, q := models.ContentQuery.QueryContext(ctx) _, err := q.Where(tbl.ID.Eq(contentID), tbl.TenantID.Eq(tenantID)).Update(tbl.Status, consts.ContentStatus(form.Status)) if err != nil { - return errorx.ErrDatabaseError + return errorx.ErrDatabaseError.WithCause(err) } return nil } -func (s *super) ListOrders(ctx context.Context, page, limit int) (*requests.Pager, error) { +func (s *super) ListOrders(ctx context.Context, filter *super_dto.SuperOrderListFilter) (*requests.Pager, error) { tbl, q := models.OrderQuery.QueryContext(ctx) - p := requests.Pagination{Page: int64(page), Limit: int64(limit)} + + filter.Pagination.Format() total, err := q.Count() if err != nil { - return nil, errorx.ErrDatabaseError + return nil, errorx.ErrDatabaseError.WithCause(err) } - list, err := q.Offset(int(p.Offset())).Limit(int(p.Limit)).Order(tbl.ID.Desc()).Find() + list, err := q.Offset(int(filter.Pagination.Offset())).Limit(int(filter.Pagination.Limit)).Order(tbl.ID.Desc()).Find() if err != nil { - return nil, errorx.ErrDatabaseError + return nil, errorx.ErrDatabaseError.WithCause(err) } // TODO: Map to DTO return &requests.Pager{ - Pagination: p, + Pagination: filter.Pagination, Total: total, Items: list, }, nil diff --git a/backend/app/services/super_test.go b/backend/app/services/super_test.go index fe7707d..7873ef2 100644 --- a/backend/app/services/super_test.go +++ b/backend/app/services/super_test.go @@ -6,10 +6,12 @@ import ( "quyun/v2/app/commands/testx" super_dto "quyun/v2/app/http/v1/dto" + "quyun/v2/app/requests" "quyun/v2/database" "quyun/v2/database/models" "quyun/v2/pkg/consts" + "github.com/samber/lo" . "github.com/smartystreets/goconvey/convey" "github.com/stretchr/testify/suite" "go.ipao.vip/atom/contracts" @@ -46,16 +48,23 @@ func (s *SuperTestSuite) Test_ListUsers() { models.UserQuery.WithContext(ctx).Create(u1, u2) Convey("should list users", func() { - res, err := Super.ListUsers(ctx, 1, 10, "") + filter := &super_dto.UserListFilter{ + Pagination: requests.Pagination{Page: 1, Limit: 10}, + } + res, err := Super.ListUsers(ctx, filter) So(err, ShouldBeNil) So(res.Total, ShouldEqual, 2) - + items := res.Items.([]super_dto.UserItem) So(items[0].Username, ShouldEqual, "user2") // Desc order }) Convey("should filter users", func() { - res, err := Super.ListUsers(ctx, 1, 10, "Alice") + filter := &super_dto.UserListFilter{ + Pagination: requests.Pagination{Page: 1, Limit: 10}, + Username: lo.ToPtr("Alice"), + } + res, err := Super.ListUsers(ctx, filter) So(err, ShouldBeNil) So(res.Total, ShouldEqual, 1) items := res.Items.([]super_dto.UserItem) @@ -88,4 +97,4 @@ func (s *SuperTestSuite) Test_CreateTenant() { So(t.Status, ShouldEqual, consts.TenantStatusVerified) }) }) -} +} \ No newline at end of file