Files
quyun-v2/backend/app/http/tenant_public/content.go

224 lines
6.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package tenant_public
import (
"encoding/json"
"net/url"
"time"
"quyun/v2/app/errorx"
tenant_dto "quyun/v2/app/http/tenant/dto"
"quyun/v2/app/requests"
"quyun/v2/app/services"
"quyun/v2/database/models"
"quyun/v2/pkg/consts"
"quyun/v2/providers/jwt"
"github.com/gofiber/fiber/v3"
log "github.com/sirupsen/logrus"
)
// content 提供“租户维度的公开只读接口”(不要求租户成员)。
//
// @provider
type content struct{}
func viewerUserID(ctx fiber.Ctx) int64 {
claims, ok := ctx.Locals(consts.CtxKeyClaims).(*jwt.Claims)
if !ok || claims == nil {
return 0
}
return claims.UserID
}
// list
//
// @Summary 公开内容列表(已发布 + public
// @Tags TenantPublic
// @Accept json
// @Produce json
// @Param tenantCode path string true "Tenant Code"
// @Param filter query tenant_dto.ContentListFilter true "Filter"
// @Success 200 {object} requests.Pager{items=tenant_dto.ContentItem}
//
// @Router /t/:tenantCode/v1/public/contents [get]
// @Bind tenant local key(tenant)
// @Bind filter query
func (*content) list(
ctx fiber.Ctx,
tenant *models.Tenant,
filter *tenant_dto.ContentListFilter,
) (*requests.Pager, error) {
uid := viewerUserID(ctx)
log.WithFields(log.Fields{
"tenant_id": tenant.ID,
"user_id": uid,
}).Info("tenant_public.contents.list")
if filter == nil {
filter = &tenant_dto.ContentListFilter{}
}
filter.Pagination.Format()
return services.Content.ListPublicPublished(ctx, tenant.ID, uid, filter)
}
// show
//
// @Summary 公开内容详情(已发布 + public
// @Tags TenantPublic
// @Accept json
// @Produce json
// @Param tenantCode path string true "Tenant Code"
// @Param contentID path int64 true "ContentID"
// @Success 200 {object} tenant_dto.ContentDetail
//
// @Router /t/:tenantCode/v1/public/contents/:contentID [get]
// @Bind tenant local key(tenant)
// @Bind contentID path
func (*content) show(ctx fiber.Ctx, tenant *models.Tenant, contentID int64) (*tenant_dto.ContentDetail, error) {
uid := viewerUserID(ctx)
log.WithFields(log.Fields{
"tenant_id": tenant.ID,
"user_id": uid,
"content_id": contentID,
}).Info("tenant_public.contents.show")
item, err := services.Content.PublicDetail(ctx, tenant.ID, uid, contentID)
if err != nil {
return nil, err
}
return &tenant_dto.ContentDetail{
Content: item.Content,
Price: item.Price,
HasAccess: item.HasAccess,
}, nil
}
// previewAssets
//
// @Summary 获取公开试看资源preview role
// @Tags TenantPublic
// @Accept json
// @Produce json
// @Param tenantCode path string true "Tenant Code"
// @Param contentID path int64 true "ContentID"
// @Success 200 {object} tenant_dto.ContentAssetsResponse
//
// @Router /t/:tenantCode/v1/public/contents/:contentID/preview [get]
// @Bind tenant local key(tenant)
// @Bind contentID path
func (*content) previewAssets(
ctx fiber.Ctx,
tenant *models.Tenant,
contentID int64,
) (*tenant_dto.ContentAssetsResponse, error) {
uid := viewerUserID(ctx)
log.WithFields(log.Fields{
"tenant_id": tenant.ID,
"user_id": uid,
"content_id": contentID,
}).Info("tenant_public.contents.preview_assets")
detail, err := services.Content.PublicDetail(ctx, tenant.ID, uid, contentID)
if err != nil {
return nil, err
}
assets, err := services.Content.AssetsByRole(ctx, tenant.ID, contentID, consts.ContentAssetRolePreview)
if err != nil {
return nil, err
}
playables := make([]*tenant_dto.ContentPlayableAsset, 0, len(assets))
for _, asset := range assets {
token, expiresAt, err := services.MediaDelivery.CreatePlayToken(tenant.ID, contentID, asset.ID, consts.ContentAssetRolePreview, uid, 0, time.Now())
if err != nil {
return nil, err
}
var meta json.RawMessage
if len(asset.Meta) > 0 {
meta = json.RawMessage(asset.Meta)
}
playables = append(playables, &tenant_dto.ContentPlayableAsset{
AssetID: asset.ID,
Type: asset.Type,
PlayURL: "/t/" + tenant.Code + "/v1/media/play?token=" + url.QueryEscape(token),
ExpiresAt: expiresAt,
Meta: meta,
})
}
previewSeconds := int32(detail.Content.PreviewSeconds)
if previewSeconds <= 0 {
previewSeconds = consts.DefaultContentPreviewSeconds
}
return &tenant_dto.ContentAssetsResponse{
Content: detail.Content,
Assets: playables,
PreviewSeconds: previewSeconds,
}, nil
}
// mainAssets
//
// @Summary 获取公开正片资源main role免费/作者/已购)
// @Tags TenantPublic
// @Accept json
// @Produce json
// @Param tenantCode path string true "Tenant Code"
// @Param contentID path int64 true "ContentID"
// @Success 200 {object} tenant_dto.ContentAssetsResponse
//
// @Router /t/:tenantCode/v1/public/contents/:contentID/assets [get]
// @Bind tenant local key(tenant)
// @Bind contentID path
func (*content) mainAssets(
ctx fiber.Ctx,
tenant *models.Tenant,
contentID int64,
) (*tenant_dto.ContentAssetsResponse, error) {
uid := viewerUserID(ctx)
log.WithFields(log.Fields{
"tenant_id": tenant.ID,
"user_id": uid,
"content_id": contentID,
}).Info("tenantpublic.contents.main_assets")
detail, err := services.Content.PublicDetail(ctx, tenant.ID, uid, contentID)
if err != nil {
return nil, err
}
if !detail.HasAccess {
return nil, errorx.ErrPermissionDenied.WithMsg("未购买或无权限访问")
}
assets, err := services.Content.AssetsByRole(ctx, tenant.ID, contentID, consts.ContentAssetRoleMain)
if err != nil {
return nil, err
}
playables := make([]*tenant_dto.ContentPlayableAsset, 0, len(assets))
for _, asset := range assets {
token, expiresAt, err := services.MediaDelivery.CreatePlayToken(tenant.ID, contentID, asset.ID, consts.ContentAssetRoleMain, uid, 0, time.Now())
if err != nil {
return nil, err
}
var meta json.RawMessage
if len(asset.Meta) > 0 {
meta = json.RawMessage(asset.Meta)
}
playables = append(playables, &tenant_dto.ContentPlayableAsset{
AssetID: asset.ID,
Type: asset.Type,
PlayURL: "/t/" + tenant.Code + "/v1/media/play?token=" + url.QueryEscape(token),
ExpiresAt: expiresAt,
Meta: meta,
})
}
return &tenant_dto.ContentAssetsResponse{
Content: detail.Content,
Assets: playables,
}, nil
}