Files
puter/src/backend/clients/database/migrations/postgres/postgres_mig_23.sql
T
Juan Castro 64db3fa050 feat: add audit_team_membership and share.holder_group_id
Insert-only record of what a workspace administrator did to an account,
shaped like \`audit_user_to_group_permissions\` after 0019: nullable FK
beside a NOT NULL \`_keep\` column. The FKs are ON DELETE SET NULL, never
CASCADE, so hard-deleting an account cannot erase the record of the
resets performed on it.

Two indexes rather than one. The member's own view is the only place a
reset becomes visible to the account it was performed on, so
(user_id_keep, id) is a read path, not an optimisation.

\`share.holder_group_id\` mirrors \`holder_user_id\` from 0067. The existing
unique index does not constrain team shares at all -- it leads with
\`holder_user_id\`, which is NULL on every team share, and NULLs are
distinct -- so the group-scoped unique index is what prevents duplicates.

Drops the \`role\` column from the specified DDL: it contradicted the
settled single-administrator model.
2026-09-03 15:07:53 -04:00

58 lines
2.5 KiB
SQL

-- Copyright (C) 2024-present Puter Technologies Inc.
--
-- This file is part of Puter.
--
-- Puter is free software: you can redistribute it and/or modify
-- it under the terms of the GNU Affero General Public License as published
-- by the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU Affero General Public License for more details.
--
-- You should have received a copy of the GNU Affero General Public License
-- along with this program. If not, see <https://www.gnu.org/licenses/>.
-- See sqlite/0076. Types follow `audit_user_to_group_permissions` in postgres_mig_1.
CREATE TABLE IF NOT EXISTS audit_team_membership (
id integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
-- SET NULL, never CASCADE: deleting an account must not erase what was done to it.
group_id integer REFERENCES "group" (id) ON DELETE SET NULL ON UPDATE CASCADE,
group_id_keep integer NOT NULL,
user_id integer REFERENCES "user" (id) ON DELETE SET NULL ON UPDATE CASCADE,
user_id_keep integer NOT NULL,
actor_user_id integer REFERENCES "user" (id) ON DELETE SET NULL ON UPDATE CASCADE,
action varchar(255) NOT NULL,
reason varchar(255),
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_audit_team_membership_group
ON audit_team_membership (group_id_keep, id);
CREATE INDEX IF NOT EXISTS idx_audit_team_membership_user
ON audit_team_membership (user_id_keep, id);
-- SET NULL has to find the child rows; postgres does not index FK columns for you.
CREATE INDEX IF NOT EXISTS idx_audit_team_membership_group_fk
ON audit_team_membership (group_id);
CREATE INDEX IF NOT EXISTS idx_audit_team_membership_user_fk
ON audit_team_membership (user_id);
CREATE INDEX IF NOT EXISTS idx_audit_team_membership_actor_fk
ON audit_team_membership (actor_user_id);
ALTER TABLE share ADD COLUMN IF NOT EXISTS holder_group_id integer
REFERENCES "group" (id) ON DELETE CASCADE ON UPDATE CASCADE;
CREATE INDEX IF NOT EXISTS idx_share_holder_group
ON share (holder_group_id, id);
-- Default NULLS DISTINCT, matching the other engines, so this binds only team shares.
CREATE UNIQUE INDEX IF NOT EXISTS idx_share_holder_group_entry_issuer
ON share (holder_group_id, fsentry_id, issuer_user_id);