feat: 添加媒体资产上传初始化和完成相关API接口及数据结构
This commit is contained in:
57
backend/app/http/tenant/dto/media_asset_admin.go
Normal file
57
backend/app/http/tenant/dto/media_asset_admin.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package dto
|
||||
|
||||
import "time"
|
||||
|
||||
// AdminMediaAssetUploadInitForm defines payload for tenant-admin to initialize a media asset upload.
|
||||
type AdminMediaAssetUploadInitForm struct {
|
||||
// Type is the media asset type (video/audio/image).
|
||||
// Used to decide processing pipeline and validation rules; required.
|
||||
Type string `json:"type,omitempty"`
|
||||
// ContentType is the MIME type reported by the client (e.g. video/mp4); optional.
|
||||
// Server should not fully trust it, but can use it as a hint for validation/logging.
|
||||
ContentType string `json:"content_type,omitempty"`
|
||||
// FileSize is the expected file size in bytes; optional.
|
||||
// Used for quota/limit checks and audit; client may omit when unknown.
|
||||
FileSize int64 `json:"file_size,omitempty"`
|
||||
// SHA256 is the hex-encoded sha256 of the file; optional.
|
||||
// Used for deduplication/audit; server may validate it later during upload-complete.
|
||||
SHA256 string `json:"sha256,omitempty"`
|
||||
}
|
||||
|
||||
// AdminMediaAssetUploadInitResponse returns server-generated upload parameters and the created asset id.
|
||||
type AdminMediaAssetUploadInitResponse struct {
|
||||
// AssetID is the created media asset id.
|
||||
AssetID int64 `json:"asset_id"`
|
||||
// Provider is the storage provider identifier (e.g. s3/minio/oss/local); for debugging/audit.
|
||||
Provider string `json:"provider,omitempty"`
|
||||
// Bucket is the target bucket/container; for debugging/audit (may be empty in stub mode).
|
||||
Bucket string `json:"bucket,omitempty"`
|
||||
// ObjectKey is the server-generated object key/path; client must NOT choose it.
|
||||
ObjectKey string `json:"object_key,omitempty"`
|
||||
|
||||
// UploadURL is the URL the client should upload to (signed URL or service endpoint).
|
||||
UploadURL string `json:"upload_url,omitempty"`
|
||||
// Headers are additional headers required for upload (e.g. signed headers); optional.
|
||||
Headers map[string]string `json:"headers,omitempty"`
|
||||
// FormFields are form fields required for multipart form upload (S3 POST policy); optional.
|
||||
FormFields map[string]string `json:"form_fields,omitempty"`
|
||||
// ExpiresAt indicates when UploadURL/FormFields expire; optional.
|
||||
ExpiresAt *time.Time `json:"expires_at,omitempty"`
|
||||
}
|
||||
|
||||
// AdminMediaAssetUploadCompleteForm defines payload for tenant-admin to mark a media upload as completed.
|
||||
// This endpoint is expected to be called after the client finishes uploading the object to storage.
|
||||
type AdminMediaAssetUploadCompleteForm struct {
|
||||
// ETag is the storage returned ETag (or similar checksum); optional.
|
||||
// Used for audit/debugging and later integrity verification.
|
||||
ETag string `json:"etag,omitempty"`
|
||||
// ContentType is the MIME type observed during upload; optional.
|
||||
// Server may record it for audit and later processing decisions.
|
||||
ContentType string `json:"content_type,omitempty"`
|
||||
// FileSize is the uploaded object size in bytes; optional.
|
||||
// Server records it for quota/audit and later validation.
|
||||
FileSize int64 `json:"file_size,omitempty"`
|
||||
// SHA256 is the hex-encoded sha256 of the uploaded object; optional.
|
||||
// Server records it for integrity checks/deduplication.
|
||||
SHA256 string `json:"sha256,omitempty"`
|
||||
}
|
||||
90
backend/app/http/tenant/media_asset_admin.go
Normal file
90
backend/app/http/tenant/media_asset_admin.go
Normal file
@@ -0,0 +1,90 @@
|
||||
package tenant
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"quyun/v2/app/errorx"
|
||||
"quyun/v2/app/http/tenant/dto"
|
||||
"quyun/v2/app/services"
|
||||
"quyun/v2/database/models"
|
||||
|
||||
"github.com/gofiber/fiber/v3"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// mediaAssetAdmin provides tenant-admin media asset endpoints.
|
||||
//
|
||||
// @provider
|
||||
type mediaAssetAdmin struct{}
|
||||
|
||||
// uploadInit
|
||||
//
|
||||
// @Summary 初始化媒体资源上传(租户管理)
|
||||
// @Tags Tenant
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param tenantCode path string true "Tenant Code"
|
||||
// @Param form body dto.AdminMediaAssetUploadInitForm true "Form"
|
||||
// @Success 200 {object} dto.AdminMediaAssetUploadInitResponse
|
||||
//
|
||||
// @Router /t/:tenantCode/v1/admin/media_assets/upload_init [post]
|
||||
// @Bind tenant local key(tenant)
|
||||
// @Bind tenantUser local key(tenant_user)
|
||||
// @Bind form body
|
||||
func (*mediaAssetAdmin) uploadInit(
|
||||
ctx fiber.Ctx,
|
||||
tenant *models.Tenant,
|
||||
tenantUser *models.TenantUser,
|
||||
form *dto.AdminMediaAssetUploadInitForm,
|
||||
) (*dto.AdminMediaAssetUploadInitResponse, error) {
|
||||
if err := requireTenantAdmin(tenantUser); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if form == nil {
|
||||
return nil, errorx.ErrInvalidParameter
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"tenant_id": tenant.ID,
|
||||
"user_id": tenantUser.UserID,
|
||||
"type": form.Type,
|
||||
}).Info("tenant.admin.media_assets.upload_init")
|
||||
|
||||
return services.MediaAsset.AdminUploadInit(ctx.Context(), tenant.ID, tenantUser.UserID, form, time.Now())
|
||||
}
|
||||
|
||||
// uploadComplete
|
||||
//
|
||||
// @Summary 确认上传完成并进入处理(租户管理)
|
||||
// @Tags Tenant
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param tenantCode path string true "Tenant Code"
|
||||
// @Param assetID path int64 true "AssetID"
|
||||
// @Param form body dto.AdminMediaAssetUploadCompleteForm false "Form"
|
||||
// @Success 200 {object} models.MediaAsset
|
||||
//
|
||||
// @Router /t/:tenantCode/v1/admin/media_assets/:assetID/upload_complete [post]
|
||||
// @Bind tenant local key(tenant)
|
||||
// @Bind tenantUser local key(tenant_user)
|
||||
// @Bind assetID path
|
||||
// @Bind form body
|
||||
func (*mediaAssetAdmin) uploadComplete(
|
||||
ctx fiber.Ctx,
|
||||
tenant *models.Tenant,
|
||||
tenantUser *models.TenantUser,
|
||||
assetID int64,
|
||||
form *dto.AdminMediaAssetUploadCompleteForm,
|
||||
) (*models.MediaAsset, error) {
|
||||
if err := requireTenantAdmin(tenantUser); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"tenant_id": tenant.ID,
|
||||
"user_id": tenantUser.UserID,
|
||||
"asset_id": assetID,
|
||||
}).Info("tenant.admin.media_assets.upload_complete")
|
||||
|
||||
return services.MediaAsset.AdminUploadComplete(ctx.Context(), tenant.ID, tenantUser.UserID, assetID, form, time.Now())
|
||||
}
|
||||
@@ -31,6 +31,13 @@ func Provide(opts ...opt.Option) error {
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := container.Container.Provide(func() (*mediaAssetAdmin, error) {
|
||||
obj := &mediaAssetAdmin{}
|
||||
|
||||
return obj, nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := container.Container.Provide(func() (*order, error) {
|
||||
obj := &order{}
|
||||
|
||||
@@ -56,6 +63,7 @@ func Provide(opts ...opt.Option) error {
|
||||
content *content,
|
||||
contentAdmin *contentAdmin,
|
||||
me *me,
|
||||
mediaAssetAdmin *mediaAssetAdmin,
|
||||
middlewares *middlewares.Middlewares,
|
||||
order *order,
|
||||
orderAdmin *orderAdmin,
|
||||
@@ -68,6 +76,7 @@ func Provide(opts ...opt.Option) error {
|
||||
content: content,
|
||||
contentAdmin: contentAdmin,
|
||||
me: me,
|
||||
mediaAssetAdmin: mediaAssetAdmin,
|
||||
middlewares: middlewares,
|
||||
order: order,
|
||||
orderAdmin: orderAdmin,
|
||||
|
||||
@@ -27,6 +27,7 @@ type Routes struct {
|
||||
content *content
|
||||
contentAdmin *contentAdmin
|
||||
me *me
|
||||
mediaAssetAdmin *mediaAssetAdmin
|
||||
order *order
|
||||
orderAdmin *orderAdmin
|
||||
orderMe *orderMe
|
||||
@@ -132,6 +133,22 @@ func (r *Routes) Register(router fiber.Router) {
|
||||
Local[*models.User]("user"),
|
||||
Query[dto.MyLedgerListFilter]("filter"),
|
||||
))
|
||||
// Register routes for controller: mediaAssetAdmin
|
||||
r.log.Debugf("Registering route: Post /t/:tenantCode/v1/admin/media_assets/:assetID/upload_complete -> mediaAssetAdmin.uploadComplete")
|
||||
router.Post("/t/:tenantCode/v1/admin/media_assets/:assetID/upload_complete"[len(r.Path()):], DataFunc4(
|
||||
r.mediaAssetAdmin.uploadComplete,
|
||||
Local[*models.Tenant]("tenant"),
|
||||
Local[*models.TenantUser]("tenant_user"),
|
||||
PathParam[int64]("assetID"),
|
||||
Body[dto.AdminMediaAssetUploadCompleteForm]("form"),
|
||||
))
|
||||
r.log.Debugf("Registering route: Post /t/:tenantCode/v1/admin/media_assets/upload_init -> mediaAssetAdmin.uploadInit")
|
||||
router.Post("/t/:tenantCode/v1/admin/media_assets/upload_init"[len(r.Path()):], DataFunc3(
|
||||
r.mediaAssetAdmin.uploadInit,
|
||||
Local[*models.Tenant]("tenant"),
|
||||
Local[*models.TenantUser]("tenant_user"),
|
||||
Body[dto.AdminMediaAssetUploadInitForm]("form"),
|
||||
))
|
||||
// Register routes for controller: order
|
||||
r.log.Debugf("Registering route: Post /t/:tenantCode/v1/contents/:contentID/purchase -> order.purchaseContent")
|
||||
router.Post("/t/:tenantCode/v1/contents/:contentID/purchase"[len(r.Path()):], DataFunc4(
|
||||
|
||||
Reference in New Issue
Block a user