feat: protect video playback access

This commit is contained in:
Codex
2026-06-28 23:00:05 +08:00
parent db65295ddc
commit 3647c2bc2d
12 changed files with 581 additions and 24 deletions

View File

@@ -33,6 +33,10 @@ const ids = {
vocabularyWord: '00000000-0000-0000-0000-000000000812',
video: '00000000-0000-0000-0000-000000000821',
questionVideo: '00000000-0000-0000-0000-000000000822',
videoAsset: '00000000-0000-0000-0000-000000000823',
quotaVideo: '00000000-0000-0000-0000-000000000824',
quotaQuestionVideo: '00000000-0000-0000-0000-000000000825',
videoQuotaAccount: '00000000-0000-0000-0000-000000000826',
scorelineSchool: '00000000-0000-0000-0000-000000000831',
scorelineMajor: '00000000-0000-0000-0000-000000000832',
scorelineField: '00000000-0000-0000-0000-000000000833',
@@ -508,26 +512,73 @@ async function main() {
[tenantId, ids.question, ids.questionVersion],
);
await client.query(
`
insert into public.content_assets (
id, tenant_id, asset_key, title, asset_type, storage_provider,
bucket, object_key, file_name, mime_type, visibility, status, source
)
values (
$1, $2, 'smoke-video-asset', '烟测视频对象', 'video', 'local_dev',
'tenant-assets', $3, 'smoke.mp4', 'video/mp4',
'svip', 'active', 'smoke-seed'
)
on conflict (id)
do update set storage_provider = excluded.storage_provider,
bucket = excluded.bucket,
object_key = excluded.object_key,
visibility = excluded.visibility,
status = 'active',
updated_at = now()
`,
[ids.videoAsset, tenantId, `${tenantId}/videos/smoke.mp4`],
);
await client.query(
`
insert into public.video_explanations (
id, tenant_id, legacy_id, title, description, video_url, thumbnail_url,
duration_seconds, knowledge_tags, is_general, subject_id, difficulty,
sort_order, is_active
sort_order, is_active, asset_id, access_mode, free_preview_seconds
)
values (
$1, $2, 'smoke-video', '烟测题目视频讲解', '用于验证题目视频 API',
'https://example.test/videos/smoke.mp4', 'https://example.test/videos/smoke.jpg',
180, '["基础加法","烟测"]'::jsonb, true, $3, 1, 1, true
180, '["基础加法","烟测"]'::jsonb, true, $3, 1, 1, true, $4, 'svip', 15
)
on conflict (id)
do update set title = excluded.title,
video_url = excluded.video_url,
subject_id = excluded.subject_id,
asset_id = excluded.asset_id,
access_mode = excluded.access_mode,
is_active = true,
updated_at = now()
`,
[ids.video, tenantId, ids.subject],
[ids.video, tenantId, ids.subject, ids.videoAsset],
);
await client.query(
`
insert into public.video_explanations (
id, tenant_id, legacy_id, title, description, video_url, thumbnail_url,
duration_seconds, knowledge_tags, is_general, subject_id, difficulty,
sort_order, is_active, asset_id, access_mode, free_preview_seconds
)
values (
$1, $2, 'smoke-quota-video', '烟测次数视频讲解', '用于验证视频播放次数扣减',
'https://example.test/videos/quota.mp4', 'https://example.test/videos/quota.jpg',
90, '["次数权益","烟测"]'::jsonb, false, $3, 1, 2, true, $4, 'video_quota', 0
)
on conflict (id)
do update set title = excluded.title,
subject_id = excluded.subject_id,
asset_id = excluded.asset_id,
access_mode = excluded.access_mode,
is_active = true,
updated_at = now()
`,
[ids.quotaVideo, tenantId, ids.subject, ids.videoAsset],
);
await client.query(
@@ -544,6 +595,36 @@ async function main() {
[ids.questionVideo, tenantId, ids.question, ids.video],
);
await client.query(
`
insert into public.question_videos (
id, tenant_id, question_id, video_id, legacy_id, video_type, sort_order
)
values ($1, $2, $3, $4, 'smoke-quota-question-video', 'quota', 2)
on conflict (id)
do update set question_id = excluded.question_id,
video_id = excluded.video_id,
video_type = excluded.video_type,
updated_at = now()
`,
[ids.quotaQuestionVideo, tenantId, ids.question, ids.quotaVideo],
);
await client.query(
`
insert into public.video_play_quota_accounts (
id, tenant_id, user_id, quota_type, total_quota, used_quota, expires_at, source_type, source_id, metadata
)
values ($1, $2, $3, 'video_play', 3, 0, now() + interval '30 days', 'smoke-seed', null, '{"source":"smoke-seed"}'::jsonb)
on conflict (id)
do update set total_quota = 3,
used_quota = 0,
expires_at = now() + interval '30 days',
updated_at = now()
`,
[ids.videoQuotaAccount, tenantId, ids.user],
);
await client.query(
`
insert into public.svip_plans (