drop discord requirement
This commit is contained in:
@@ -0,0 +1,75 @@
|
|||||||
|
-- Make core.users.discord_id optional.
|
||||||
|
--
|
||||||
|
-- Discord is the first client, not the only possible one. A web frontend, a
|
||||||
|
-- Matrix bridge or a CLI would each create users who have no Discord account,
|
||||||
|
-- and NOT NULL would have forced a fake value or a schema change under
|
||||||
|
-- pressure.
|
||||||
|
--
|
||||||
|
-- The surrogate id was already the primary key for this reason; this finishes
|
||||||
|
-- the job by making discord_id what it always was conceptually - one LINK to an
|
||||||
|
-- identity rather than the identity itself.
|
||||||
|
|
||||||
|
ALTER TABLE core.users ALTER COLUMN discord_id DROP NOT NULL;
|
||||||
|
|
||||||
|
COMMENT ON COLUMN core.users.discord_id IS 'Discord snowflake, or NULL for a user who reached the backend some other way. The UNIQUE constraint still holds for non-NULL values: Postgres treats NULLs as distinct in a unique index, so any number of rows may have none.';
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
-- Deletion by surrogate id.
|
||||||
|
--
|
||||||
|
-- core.forget_user(discord_id) can only reach users who have one. This is the
|
||||||
|
-- same cascade addressed by primary key, so /forget-me works regardless of how
|
||||||
|
-- the user arrived.
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
CREATE FUNCTION core.forget_user_by_id(p_user_id bigint)
|
||||||
|
RETURNS TABLE (deleted_user boolean, deleted_qsos bigint)
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
SET search_path = pg_catalog, core, logbook
|
||||||
|
AS $$
|
||||||
|
DECLARE
|
||||||
|
v_qsos bigint := 0;
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM core.users WHERE id = p_user_id) THEN
|
||||||
|
RETURN QUERY SELECT false, 0::bigint;
|
||||||
|
RETURN;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
SELECT count(*) INTO v_qsos FROM logbook.qsos WHERE user_id = p_user_id;
|
||||||
|
|
||||||
|
DELETE FROM core.users WHERE id = p_user_id;
|
||||||
|
|
||||||
|
RETURN QUERY SELECT true, v_qsos;
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
COMMENT ON FUNCTION core.forget_user_by_id(bigint) IS 'Hard-deletes a user and all dependent rows by surrogate id. Caller must also purge Redis keys for this user.';
|
||||||
|
|
||||||
|
GRANT EXECUTE ON FUNCTION core.forget_user_by_id(bigint) TO hammy_app;
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
-- Guard against rows nobody can reach.
|
||||||
|
--
|
||||||
|
-- With discord_id nullable and no other identifier column, a row with a NULL
|
||||||
|
-- discord_id and no callsign cannot be found by any lookup the application
|
||||||
|
-- performs: it is a leak, not a user. Require at least one way in.
|
||||||
|
--
|
||||||
|
-- Widen this CHECK as identifiers are added - or replace it with a core.identities
|
||||||
|
-- table, which is the right shape once there is genuinely a second client:
|
||||||
|
--
|
||||||
|
-- CREATE TABLE core.identities (
|
||||||
|
-- user_id bigint NOT NULL REFERENCES core.users(id) ON DELETE CASCADE,
|
||||||
|
-- provider text NOT NULL,
|
||||||
|
-- external_id text NOT NULL,
|
||||||
|
-- linked_at timestamptz NOT NULL DEFAULT now(),
|
||||||
|
-- PRIMARY KEY (provider, external_id)
|
||||||
|
-- );
|
||||||
|
--
|
||||||
|
-- Not worth doing yet: every lookup becomes a join, and Discord is the only
|
||||||
|
-- client. The migration when the time comes is mechanical - create the table,
|
||||||
|
-- INSERT INTO identities SELECT id, 'discord', discord_id FROM users WHERE
|
||||||
|
-- discord_id IS NOT NULL, drop the column.
|
||||||
|
-- ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
ALTER TABLE core.users
|
||||||
|
ADD CONSTRAINT users_reachable
|
||||||
|
CHECK (discord_id IS NOT NULL OR callsign IS NOT NULL);
|
||||||
@@ -11,6 +11,8 @@ sql:
|
|||||||
- "migrations/002_core.sql"
|
- "migrations/002_core.sql"
|
||||||
- "migrations/003_api.sql"
|
- "migrations/003_api.sql"
|
||||||
- "migrations/004_logbook.sql"
|
- "migrations/004_logbook.sql"
|
||||||
|
- "migrations/005_privacy.sql"
|
||||||
|
- "migrations/006_users_optional_discord.sql"
|
||||||
|
|
||||||
gen:
|
gen:
|
||||||
go:
|
go:
|
||||||
|
|||||||
Reference in New Issue
Block a user