forked from wangziqi/gongxue-base
feat: protect video playback access
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
alter table public.video_explanations
|
||||
add column if not exists asset_id uuid references public.content_assets(id) on delete set null,
|
||||
add column if not exists access_mode text not null default 'svip',
|
||||
add column if not exists free_preview_seconds integer not null default 0,
|
||||
add column if not exists play_count integer not null default 0;
|
||||
|
||||
do $$
|
||||
begin
|
||||
if not exists (select 1 from pg_constraint where conname = 'video_explanations_access_mode_check') then
|
||||
alter table public.video_explanations
|
||||
add constraint video_explanations_access_mode_check
|
||||
check (access_mode in ('free', 'svip', 'video_quota'));
|
||||
end if;
|
||||
|
||||
if not exists (select 1 from pg_constraint where conname = 'video_explanations_free_preview_check') then
|
||||
alter table public.video_explanations
|
||||
add constraint video_explanations_free_preview_check
|
||||
check (free_preview_seconds >= 0);
|
||||
end if;
|
||||
|
||||
if not exists (select 1 from pg_constraint where conname = 'video_explanations_play_count_check') then
|
||||
alter table public.video_explanations
|
||||
add constraint video_explanations_play_count_check
|
||||
check (play_count >= 0);
|
||||
end if;
|
||||
end $$;
|
||||
|
||||
create table if not exists public.video_play_quota_accounts (
|
||||
id uuid primary key default gen_random_uuid(),
|
||||
tenant_id uuid not null references public.tenants(id) on delete cascade,
|
||||
user_id uuid not null references public.platform_users(id) on delete cascade,
|
||||
quota_type text not null default 'video_play',
|
||||
total_quota integer not null default 0,
|
||||
used_quota integer not null default 0,
|
||||
expires_at timestamptz,
|
||||
source_type text,
|
||||
source_id uuid,
|
||||
metadata jsonb not null default '{}'::jsonb,
|
||||
created_at timestamptz not null default now(),
|
||||
updated_at timestamptz not null default now(),
|
||||
unique (tenant_id, user_id, quota_type, source_type, source_id)
|
||||
);
|
||||
|
||||
create table if not exists public.video_play_events (
|
||||
id uuid primary key default gen_random_uuid(),
|
||||
tenant_id uuid not null references public.tenants(id) on delete cascade,
|
||||
user_id uuid not null references public.platform_users(id) on delete cascade,
|
||||
video_id uuid not null references public.video_explanations(id) on delete cascade,
|
||||
question_id uuid references public.questions(id) on delete set null,
|
||||
entitlement_id uuid references public.entitlements(id) on delete set null,
|
||||
quota_account_id uuid references public.video_play_quota_accounts(id) on delete set null,
|
||||
play_token_hash text not null unique,
|
||||
status text not null default 'issued' check (status in ('issued', 'started', 'completed', 'expired', 'revoked')),
|
||||
access_mode text not null default 'svip' check (access_mode in ('free', 'svip', 'video_quota')),
|
||||
consumed_quota integer not null default 0 check (consumed_quota >= 0),
|
||||
signed_url_expires_at timestamptz,
|
||||
ip_address text,
|
||||
user_agent text,
|
||||
metadata jsonb not null default '{}'::jsonb,
|
||||
created_at timestamptz not null default now(),
|
||||
updated_at timestamptz not null default now()
|
||||
);
|
||||
|
||||
create index if not exists idx_video_explanations_asset
|
||||
on public.video_explanations(tenant_id, asset_id)
|
||||
where asset_id is not null;
|
||||
|
||||
create index if not exists idx_video_quota_user
|
||||
on public.video_play_quota_accounts(tenant_id, user_id, quota_type, expires_at);
|
||||
|
||||
create index if not exists idx_video_play_events_user
|
||||
on public.video_play_events(tenant_id, user_id, created_at desc);
|
||||
|
||||
create index if not exists idx_video_play_events_video
|
||||
on public.video_play_events(tenant_id, video_id, created_at desc);
|
||||
|
||||
do $$
|
||||
declare
|
||||
table_name text;
|
||||
begin
|
||||
foreach table_name in array array['video_play_quota_accounts', 'video_play_events']
|
||||
loop
|
||||
execute format('alter table public.%I enable row level security', table_name);
|
||||
execute format('drop policy if exists tenant_isolation on public.%I', table_name);
|
||||
execute format(
|
||||
'create policy tenant_isolation on public.%I for all using (tenant_id = app.current_tenant_id() or app.is_platform_admin()) with check (tenant_id = app.current_tenant_id() or app.is_platform_admin())',
|
||||
table_name
|
||||
);
|
||||
execute format('drop trigger if exists set_updated_at on public.%I', table_name);
|
||||
execute format('create trigger set_updated_at before update on public.%I for each row execute function app.touch_updated_at()', table_name);
|
||||
end loop;
|
||||
end $$;
|
||||
Reference in New Issue
Block a user