package services import ( "context" "strings" "time" "quyun/v2/app/errorx" superdto "quyun/v2/app/http/super/dto" "quyun/v2/app/requests" "quyun/v2/database" "quyun/v2/database/models" "quyun/v2/pkg/consts" "github.com/pkg/errors" "github.com/samber/lo" log "github.com/sirupsen/logrus" "go.ipao.vip/gen" "go.ipao.vip/gen/field" ) // SuperTenantContentsPage returns tenant contents list for superadmin. func (s *content) SuperTenantContentsPage(ctx context.Context, tenantID int64, filter *superdto.TenantContentFilter) (*requests.Pager, error) { if tenantID <= 0 { return nil, errors.New("tenant_id must be > 0") } if filter == nil { filter = &superdto.TenantContentFilter{} } log.WithFields(log.Fields{ "tenant_id": tenantID, "page": filter.Page, "limit": filter.Limit, }).Info("services.content.super_tenant_contents_page") tbl, query := models.ContentQuery.QueryContext(ctx) conds := []gen.Condition{ tbl.TenantID.Eq(tenantID), tbl.DeletedAt.IsNull(), } if kw := strings.TrimSpace(filter.KeywordTrimmed()); kw != "" { conds = append(conds, tbl.Title.Like(database.WrapLike(kw))) } if filter.Status != nil { conds = append(conds, tbl.Status.Eq(*filter.Status)) } if filter.Visibility != nil { conds = append(conds, tbl.Visibility.Eq(*filter.Visibility)) } if filter.UserID != nil && *filter.UserID > 0 { conds = append(conds, tbl.UserID.Eq(*filter.UserID)) } if filter.PublishedAtFrom != nil { conds = append(conds, tbl.PublishedAt.Gte(*filter.PublishedAtFrom)) } if filter.PublishedAtTo != nil { conds = append(conds, tbl.PublishedAt.Lte(*filter.PublishedAtTo)) } if filter.CreatedAtFrom != nil { conds = append(conds, tbl.CreatedAt.Gte(*filter.CreatedAtFrom)) } if filter.CreatedAtTo != nil { conds = append(conds, tbl.CreatedAt.Lte(*filter.CreatedAtTo)) } filter.Pagination.Format() orderBys := make([]field.Expr, 0, 6) allowedAsc := map[string]field.Expr{ "id": tbl.ID.Asc(), "title": tbl.Title.Asc(), "user_id": tbl.UserID.Asc(), "status": tbl.Status.Asc(), "visibility": tbl.Visibility.Asc(), "published_at": tbl.PublishedAt.Asc(), "created_at": tbl.CreatedAt.Asc(), "updated_at": tbl.UpdatedAt.Asc(), } allowedDesc := map[string]field.Expr{ "id": tbl.ID.Desc(), "title": tbl.Title.Desc(), "user_id": tbl.UserID.Desc(), "status": tbl.Status.Desc(), "visibility": tbl.Visibility.Desc(), "published_at": tbl.PublishedAt.Desc(), "created_at": tbl.CreatedAt.Desc(), "updated_at": tbl.UpdatedAt.Desc(), } for _, f := range filter.AscFields() { f = strings.TrimSpace(f) if f == "" { continue } if ob, ok := allowedAsc[f]; ok { orderBys = append(orderBys, ob) } } for _, f := range filter.DescFields() { f = strings.TrimSpace(f) if f == "" { continue } if ob, ok := allowedDesc[f]; ok { orderBys = append(orderBys, ob) } } if len(orderBys) == 0 { orderBys = append(orderBys, tbl.ID.Desc()) } else { orderBys = append(orderBys, tbl.ID.Desc()) } items, total, err := query.Where(conds...).Order(orderBys...).FindByPage(int(filter.Offset()), int(filter.Limit)) if err != nil { return nil, err } contentIDs := lo.Map(items, func(item *models.Content, _ int) int64 { if item == nil { return 0 } return item.ID }) contentIDs = lo.Filter(contentIDs, func(id int64, _ int) bool { return id > 0 }) priceByContent, err := s.contentPriceMapping(ctx, tenantID, contentIDs) if err != nil { return nil, err } ownerIDs := lo.Uniq(lo.FilterMap(items, func(item *models.Content, _ int) (int64, bool) { if item == nil || item.UserID <= 0 { return 0, false } return item.UserID, true })) ownerMap := map[int64]*superdto.SuperUserLite{} if len(ownerIDs) > 0 { uTbl, uQuery := models.UserQuery.QueryContext(ctx) users, err := uQuery.Where(uTbl.ID.In(ownerIDs...)).Find() if err != nil { return nil, err } for _, u := range users { if u == nil { continue } ownerMap[u.ID] = &superdto.SuperUserLite{ ID: u.ID, Username: u.Username, Status: u.Status, Roles: u.Roles, VerifiedAt: u.VerifiedAt, CreatedAt: u.CreatedAt, UpdatedAt: u.UpdatedAt, StatusDescription: u.Status.Description(), } } } respItems := lo.Map(items, func(model *models.Content, _ int) *superdto.SuperTenantContentItem { if model == nil { return nil } return &superdto.SuperTenantContentItem{ Content: model, Price: priceByContent[model.ID], Owner: ownerMap[model.UserID], StatusDescription: model.Status.Description(), VisibilityDescription: model.Visibility.Description(), } }) return &requests.Pager{ Pagination: filter.Pagination, Total: total, Items: respItems, }, nil } func (s *content) SuperUpdateTenantContentStatus( ctx context.Context, operatorUserID, tenantID, contentID int64, status consts.ContentStatus, now time.Time, ) (*models.Content, error) { if operatorUserID <= 0 { return nil, errorx.ErrTokenInvalid } if tenantID <= 0 { return nil, errors.New("tenant_id must be > 0") } if contentID <= 0 { return nil, errors.New("content_id must be > 0") } if status != consts.ContentStatusUnpublished && status != consts.ContentStatusBlocked { return nil, errorx.ErrInvalidParameter.WithMsg("invalid status") } log.WithFields(log.Fields{ "operator_user_id": operatorUserID, "tenant_id": tenantID, "content_id": contentID, "status": status, }).Info("services.content.super_update_tenant_content_status") tbl, query := models.ContentQuery.QueryContext(ctx) model, err := query.Where( tbl.TenantID.Eq(tenantID), tbl.ID.Eq(contentID), tbl.DeletedAt.IsNull(), ).First() if err != nil { return nil, err } if status == consts.ContentStatusUnpublished && model.Status != consts.ContentStatusPublished { return nil, errorx.ErrPreconditionFailed.WithMsg("content is not published") } if _, err := query.Where( tbl.TenantID.Eq(tenantID), tbl.ID.Eq(contentID), tbl.DeletedAt.IsNull(), ).UpdateSimple( tbl.Status.Value(status), ); err != nil { return nil, err } model.Status = status model.UpdatedAt = now return model, nil }