fix namings
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
-- Deletion paths.
|
||||
--
|
||||
-- Discord's developer policy requires deleting user data on request, and API
|
||||
-- registrants are an international user base whose data protection expectations
|
||||
-- apply regardless. Build this before you need it: retrofitting a deletion path
|
||||
-- across three stores is miserable, and being asked for one you do not have is
|
||||
-- worse.
|
||||
--
|
||||
-- These functions cover Postgres. The caller must ALSO clear Redis - cached
|
||||
-- callsign lookups, rate-limit counters keyed by hashed Discord ID, and any
|
||||
-- verification challenge in flight. Postgres is not the whole story.
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
-- Removes a Discord user and everything referencing them. The ON DELETE CASCADE
|
||||
-- chain reaches verifications, subscriptions, imports and qsos, so this is one
|
||||
-- statement rather than a list that can fall out of date as tables are added.
|
||||
--
|
||||
-- Returns the number of QSOs removed, purely so the caller can tell the user
|
||||
-- what was deleted.
|
||||
CREATE FUNCTION core.forget_user(p_discord_id bigint)
|
||||
RETURNS TABLE (deleted_user boolean, deleted_qsos bigint)
|
||||
LANGUAGE plpgsql
|
||||
-- Pinned: the body qualifies its tables, but now(), count() and friends resolve
|
||||
-- through search_path. Matters more if this ever becomes SECURITY DEFINER.
|
||||
SET search_path = pg_catalog, core, logbook
|
||||
AS $$
|
||||
DECLARE
|
||||
v_user_id bigint;
|
||||
v_qsos bigint := 0;
|
||||
BEGIN
|
||||
SELECT id INTO v_user_id FROM core.users WHERE discord_id = p_discord_id;
|
||||
|
||||
IF v_user_id IS NULL THEN
|
||||
RETURN QUERY SELECT false, 0::bigint;
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
SELECT count(*) INTO v_qsos FROM logbook.qsos WHERE user_id = v_user_id;
|
||||
|
||||
-- Cascades do the rest.
|
||||
DELETE FROM core.users WHERE id = v_user_id;
|
||||
|
||||
RETURN QUERY SELECT true, v_qsos;
|
||||
END;
|
||||
$$;
|
||||
|
||||
COMMENT ON FUNCTION core.forget_user(bigint) IS 'Hard-deletes a Discord user and all dependent rows. Caller must also purge Redis keys for this user.';
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
-- The API-side equivalent. Keys and usage rows cascade from the owner.
|
||||
CREATE FUNCTION api.forget_owner(p_email core.email)
|
||||
RETURNS TABLE (deleted_owner boolean, deleted_keys bigint)
|
||||
LANGUAGE plpgsql
|
||||
SET search_path = pg_catalog, core, api
|
||||
AS $$
|
||||
DECLARE
|
||||
v_owner_id bigint;
|
||||
v_keys bigint := 0;
|
||||
BEGIN
|
||||
SELECT id INTO v_owner_id FROM api.owners WHERE email = p_email;
|
||||
|
||||
IF v_owner_id IS NULL THEN
|
||||
RETURN QUERY SELECT false, 0::bigint;
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
SELECT count(*) INTO v_keys FROM api.keys WHERE owner_id = v_owner_id;
|
||||
|
||||
DELETE FROM api.owners WHERE id = v_owner_id;
|
||||
|
||||
RETURN QUERY SELECT true, v_keys;
|
||||
END;
|
||||
$$;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
-- Retention. Verification records carry a hashed challenge and a timestamp, and
|
||||
-- are useful for a short while when investigating a failed verification. They
|
||||
-- are not useful a year later. Run this from cron.
|
||||
CREATE FUNCTION core.prune_verifications(p_keep_days integer DEFAULT 90)
|
||||
RETURNS bigint
|
||||
LANGUAGE plpgsql
|
||||
SET search_path = pg_catalog, core
|
||||
AS $$
|
||||
DECLARE
|
||||
v_removed bigint;
|
||||
BEGIN
|
||||
DELETE FROM core.verifications
|
||||
WHERE created_at < now() - make_interval(days => p_keep_days)
|
||||
AND status <> 'succeeded';
|
||||
|
||||
GET DIAGNOSTICS v_removed = ROW_COUNT;
|
||||
|
||||
RETURN v_removed;
|
||||
END;
|
||||
$$;
|
||||
|
||||
GRANT EXECUTE ON FUNCTION core.forget_user(bigint) TO hammy_app;
|
||||
GRANT EXECUTE ON FUNCTION api.forget_owner(core.email) TO hammy_app;
|
||||
GRANT EXECUTE ON FUNCTION core.prune_verifications(integer) TO hammy_app;
|
||||
Reference in New Issue
Block a user