forked from wangziqi/gongxue-base
96 lines
4.3 KiB
SQL
96 lines
4.3 KiB
SQL
alter table public.content_nodes
|
|
add column if not exists access_rules jsonb not null default '{}'::jsonb;
|
|
|
|
alter table public.question_collections
|
|
add column if not exists access_rules jsonb not null default '{}'::jsonb;
|
|
|
|
alter table public.practice_blueprints
|
|
add column if not exists access_rules jsonb not null default '{}'::jsonb;
|
|
|
|
alter table public.practice_sessions
|
|
add column if not exists access_mode text not null default 'free',
|
|
add column if not exists access_entitlement_id uuid references public.entitlements(id) on delete set null,
|
|
add column if not exists consumed_free_quota integer not null default 0,
|
|
add column if not exists access_snapshot jsonb not null default '{}'::jsonb;
|
|
|
|
do $$
|
|
begin
|
|
if not exists (select 1 from pg_constraint where conname = 'practice_sessions_access_mode_check') then
|
|
alter table public.practice_sessions
|
|
add constraint practice_sessions_access_mode_check
|
|
check (access_mode in ('free', 'svip', 'staff'));
|
|
end if;
|
|
|
|
if not exists (select 1 from pg_constraint where conname = 'practice_sessions_consumed_free_quota_check') then
|
|
alter table public.practice_sessions
|
|
add constraint practice_sessions_consumed_free_quota_check
|
|
check (consumed_free_quota >= 0);
|
|
end if;
|
|
end $$;
|
|
|
|
create table if not exists public.practice_daily_usage (
|
|
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,
|
|
usage_date date not null default current_date,
|
|
scope_type text not null default 'tenant'
|
|
check (scope_type in ('tenant', 'region', 'subject', 'question_bank', 'content_entry', 'content_node', 'collection', 'blueprint')),
|
|
scope_id uuid,
|
|
free_limit integer not null default 25 check (free_limit >= 0),
|
|
used_count integer not null default 0 check (used_count >= 0),
|
|
metadata jsonb not null default '{}'::jsonb,
|
|
created_at timestamptz not null default now(),
|
|
updated_at timestamptz not null default now()
|
|
);
|
|
|
|
create table if not exists public.practice_access_events (
|
|
id uuid primary key default gen_random_uuid(),
|
|
tenant_id uuid not null references public.tenants(id) on delete cascade,
|
|
user_id uuid references public.platform_users(id) on delete set null,
|
|
practice_session_id uuid references public.practice_sessions(id) on delete set null,
|
|
event_type text not null
|
|
check (event_type in ('session_created', 'session_denied', 'quota_consumed')),
|
|
access_mode text not null default 'free'
|
|
check (access_mode in ('free', 'svip', 'staff', 'denied')),
|
|
requested_count integer not null default 0 check (requested_count >= 0),
|
|
granted_count integer not null default 0 check (granted_count >= 0),
|
|
consumed_free_quota integer not null default 0 check (consumed_free_quota >= 0),
|
|
reason text,
|
|
scope_type text,
|
|
scope_id uuid,
|
|
entitlement_id uuid references public.entitlements(id) on delete set null,
|
|
metadata jsonb not null default '{}'::jsonb,
|
|
created_at timestamptz not null default now()
|
|
);
|
|
|
|
create index if not exists idx_practice_daily_usage_user
|
|
on public.practice_daily_usage(tenant_id, user_id, usage_date desc);
|
|
|
|
create unique index if not exists idx_practice_daily_usage_unique_scope
|
|
on public.practice_daily_usage(tenant_id, user_id, usage_date, scope_type, scope_id)
|
|
nulls not distinct;
|
|
|
|
create index if not exists idx_practice_access_events_user
|
|
on public.practice_access_events(tenant_id, user_id, created_at desc);
|
|
|
|
create index if not exists idx_practice_access_events_session
|
|
on public.practice_access_events(tenant_id, practice_session_id);
|
|
|
|
do $$
|
|
declare
|
|
table_name text;
|
|
begin
|
|
foreach table_name in array array['practice_daily_usage', 'practice_access_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);
|
|
end loop;
|
|
|
|
execute 'create trigger set_updated_at before update on public.practice_daily_usage for each row execute function app.touch_updated_at()';
|
|
end $$;
|