mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
feat: enable soft delete for organizations (#16584)
- Add deleted column to organizations table - Add trigger to check for existing workspaces, templates, groups and members in a org before allowing the soft delete --------- Co-authored-by: Steven Masley <stevenmasley@gmail.com> Co-authored-by: Steven Masley <Emyrk@users.noreply.github.com>
This commit is contained in:
Generated
+73
-7
@@ -438,6 +438,74 @@ BEGIN
|
||||
END;
|
||||
$$;
|
||||
|
||||
CREATE FUNCTION protect_deleting_organizations() RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
workspace_count int;
|
||||
template_count int;
|
||||
group_count int;
|
||||
member_count int;
|
||||
provisioner_keys_count int;
|
||||
BEGIN
|
||||
workspace_count := (
|
||||
SELECT count(*) as count FROM workspaces
|
||||
WHERE
|
||||
workspaces.organization_id = OLD.id
|
||||
AND workspaces.deleted = false
|
||||
);
|
||||
|
||||
template_count := (
|
||||
SELECT count(*) as count FROM templates
|
||||
WHERE
|
||||
templates.organization_id = OLD.id
|
||||
AND templates.deleted = false
|
||||
);
|
||||
|
||||
group_count := (
|
||||
SELECT count(*) as count FROM groups
|
||||
WHERE
|
||||
groups.organization_id = OLD.id
|
||||
);
|
||||
|
||||
member_count := (
|
||||
SELECT count(*) as count FROM organization_members
|
||||
WHERE
|
||||
organization_members.organization_id = OLD.id
|
||||
);
|
||||
|
||||
provisioner_keys_count := (
|
||||
Select count(*) as count FROM provisioner_keys
|
||||
WHERE
|
||||
provisioner_keys.organization_id = OLD.id
|
||||
);
|
||||
|
||||
-- Fail the deletion if one of the following:
|
||||
-- * the organization has 1 or more workspaces
|
||||
-- * the organization has 1 or more templates
|
||||
-- * the organization has 1 or more groups other than "Everyone" group
|
||||
-- * the organization has 1 or more members other than the organization owner
|
||||
-- * the organization has 1 or more provisioner keys
|
||||
|
||||
IF (workspace_count + template_count + provisioner_keys_count) > 0 THEN
|
||||
RAISE EXCEPTION 'cannot delete organization: organization has % workspaces, % templates, and % provisioner keys that must be deleted first', workspace_count, template_count, provisioner_keys_count;
|
||||
END IF;
|
||||
|
||||
IF (group_count) > 1 THEN
|
||||
RAISE EXCEPTION 'cannot delete organization: organization has % groups that must be deleted first', group_count - 1;
|
||||
END IF;
|
||||
|
||||
-- Allow 1 member to exist, because you cannot remove yourself. You can
|
||||
-- remove everyone else. Ideally, we only omit the member that matches
|
||||
-- the user_id of the caller, however in a trigger, the caller is unknown.
|
||||
IF (member_count) > 1 THEN
|
||||
RAISE EXCEPTION 'cannot delete organization: organization has % members that must be deleted first', member_count - 1;
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
CREATE FUNCTION provisioner_tagset_contains(provisioner_tags tagset, job_tags tagset) RETURNS boolean
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
@@ -967,7 +1035,8 @@ CREATE TABLE organizations (
|
||||
updated_at timestamp with time zone NOT NULL,
|
||||
is_default boolean DEFAULT false NOT NULL,
|
||||
display_name text NOT NULL,
|
||||
icon text DEFAULT ''::text NOT NULL
|
||||
icon text DEFAULT ''::text NOT NULL,
|
||||
deleted boolean DEFAULT false NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE parameter_schemas (
|
||||
@@ -2030,9 +2099,6 @@ ALTER TABLE ONLY oauth2_provider_apps
|
||||
ALTER TABLE ONLY organization_members
|
||||
ADD CONSTRAINT organization_members_pkey PRIMARY KEY (organization_id, user_id);
|
||||
|
||||
ALTER TABLE ONLY organizations
|
||||
ADD CONSTRAINT organizations_name UNIQUE (name);
|
||||
|
||||
ALTER TABLE ONLY organizations
|
||||
ADD CONSTRAINT organizations_pkey PRIMARY KEY (id);
|
||||
|
||||
@@ -2218,9 +2284,7 @@ CREATE INDEX idx_organization_member_organization_id_uuid ON organization_member
|
||||
|
||||
CREATE INDEX idx_organization_member_user_id_uuid ON organization_members USING btree (user_id);
|
||||
|
||||
CREATE UNIQUE INDEX idx_organization_name ON organizations USING btree (name);
|
||||
|
||||
CREATE UNIQUE INDEX idx_organization_name_lower ON organizations USING btree (lower(name));
|
||||
CREATE UNIQUE INDEX idx_organization_name_lower ON organizations USING btree (lower(name)) WHERE (deleted = false);
|
||||
|
||||
CREATE UNIQUE INDEX idx_provisioner_daemons_org_name_owner_key ON provisioner_daemons USING btree (organization_id, name, lower(COALESCE((tags ->> 'owner'::text), ''::text)));
|
||||
|
||||
@@ -2352,6 +2416,8 @@ CREATE OR REPLACE VIEW provisioner_job_stats AS
|
||||
|
||||
CREATE TRIGGER inhibit_enqueue_if_disabled BEFORE INSERT ON notification_messages FOR EACH ROW EXECUTE FUNCTION inhibit_enqueue_if_disabled();
|
||||
|
||||
CREATE TRIGGER protect_deleting_organizations BEFORE UPDATE ON organizations FOR EACH ROW WHEN (((new.deleted = true) AND (old.deleted = false))) EXECUTE FUNCTION protect_deleting_organizations();
|
||||
|
||||
CREATE TRIGGER remove_organization_member_custom_role BEFORE DELETE ON custom_roles FOR EACH ROW EXECUTE FUNCTION remove_organization_member_role();
|
||||
|
||||
COMMENT ON TRIGGER remove_organization_member_custom_role ON custom_roles IS 'When a custom_role is deleted, this trigger removes the role from all organization members.';
|
||||
|
||||
Reference in New Issue
Block a user