Migrate people to identities / memberships / profiles
Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
498
pkg/coredata/migrations/20260203T132700Z.sql
Normal file
498
pkg/coredata/migrations/20260203T132700Z.sql
Normal file
@@ -0,0 +1,498 @@
|
||||
-- 1. Add peoples column onto profiles
|
||||
ALTER TABLE
|
||||
iam_membership_profiles
|
||||
ADD
|
||||
COLUMN additional_email_addresses CITEXT [] NOT NULL,
|
||||
ADD
|
||||
COLUMN kind PEOPLE_KIND NOT NULL,
|
||||
ADD
|
||||
COLUMN contract_start_date DATE,
|
||||
ADD
|
||||
COLUMN contract_end_date DATE,
|
||||
ADD
|
||||
COLUMN position TEXT;
|
||||
|
||||
-- 2. Add profile references to all table referencing peoples
|
||||
-- was owner_id, NOT NULL
|
||||
ALTER TABLE
|
||||
assets
|
||||
ADD
|
||||
COLUMN owner_profile_id REFERENCES iam_membership_profiles(id) ON UPDATE CASCADE ON DELETE RESTRICT;
|
||||
|
||||
-- was owner_id, NOT NULL
|
||||
ALTER TABLE
|
||||
continual_improvements
|
||||
ADD
|
||||
COLUMN owner_profile_id REFERENCES iam_membership_profiles(id) ON UPDATE CASCADE ON DELETE RESTRICT;
|
||||
|
||||
-- was owner_id, NOT NULL
|
||||
ALTER TABLE
|
||||
data
|
||||
ADD
|
||||
COLUMN owner_profile_id REFERENCES iam_membership_profiles(id) ON UPDATE CASCADE ON DELETE RESTRICT;
|
||||
|
||||
-- was owner_id, NOT NULL
|
||||
ALTER TABLE
|
||||
document_versions
|
||||
ADD
|
||||
COLUMN owner_profile_id REFERENCES iam_membership_profiles(id) ON UPDATE CASCADE ON DELETE RESTRICT;
|
||||
|
||||
-- was attendee_id, NOT NULL
|
||||
ALTER TABLE
|
||||
meeting_attendees
|
||||
ADD
|
||||
COLUMN attendee_profile_id REFERENCES iam_membership_profiles(id) ON UPDATE CASCADE ON DELETE CASCADE;
|
||||
|
||||
-- was owner_id, NOT NULL
|
||||
ALTER TABLE
|
||||
nonconformities
|
||||
ADD
|
||||
COLUMN owner_profile_id REFERENCES iam_membership_profiles(id) ON UPDATE CASCADE ON DELETE RESTRICT;
|
||||
|
||||
-- was owner_id, NOT NULL
|
||||
ALTER TABLE
|
||||
obligations
|
||||
ADD
|
||||
COLUMN owner_profile_id REFERENCES iam_membership_profiles(id) ON UPDATE CASCADE ON DELETE RESTRICT;
|
||||
|
||||
-- was owner_id, can be null
|
||||
ALTER TABLE
|
||||
documents
|
||||
ADD
|
||||
COLUMN owner_profile_id REFERENCES iam_membership_profiles(id);
|
||||
|
||||
-- was signed_by, NOT NULL
|
||||
ALTER TABLE
|
||||
document_version_signatures
|
||||
ADD
|
||||
COLUMN signed_by_profile_id REFERENCES iam_membership_profiles(id);
|
||||
|
||||
-- was data_protection_officer_id, can be null
|
||||
ALTER TABLE
|
||||
processing_activities
|
||||
ADD
|
||||
COLUMN dpo_profile_id REFERENCES iam_membership_profiles(id) ON UPDATE CASCADE ON DELETE RESTRICT;
|
||||
|
||||
-- was owner_id, can be null
|
||||
ALTER TABLE
|
||||
risks
|
||||
ADD
|
||||
COLUMN owner_profile_id REFERENCES iam_membership_profiles(id) ON UPDATE CASCADE ON DELETE
|
||||
SET
|
||||
NULL;
|
||||
|
||||
-- was owner_id, NOT NULL
|
||||
ALTER TABLE
|
||||
states_of_applicability
|
||||
ADD
|
||||
COLUMN owner_profile_id REFERENCES iam_membership_profiles(id) ON UPDATE CASCADE ON DELETE RESTRICT;
|
||||
|
||||
-- was assigned_to, can be null
|
||||
ALTER TABLE
|
||||
tasks
|
||||
ADD
|
||||
COLUMN assigned_to_profile_id REFERENCES iam_membership_profiles(id) ON UPDATE CASCADE ON DELETE
|
||||
SET
|
||||
NULL;
|
||||
|
||||
-- was business_owner_id, can be null
|
||||
ALTER TABLE
|
||||
vendors
|
||||
ADD
|
||||
COLUMN business_owner_profile_id REFERENCES iam_membership_profiles(id) ON UPDATE CASCADE ON DELETE
|
||||
SET
|
||||
NULL;
|
||||
|
||||
-- was security_owner_id, can be null
|
||||
ALTER TABLE
|
||||
vendors
|
||||
ADD
|
||||
COLUMN security_owner_profile_id REFERENCES iam_membership_profiles(id) ON UPDATE CASCADE ON DELETE
|
||||
SET
|
||||
NULL;
|
||||
|
||||
-- 3. Create missing identities
|
||||
INSERT INTO
|
||||
identities (
|
||||
id,
|
||||
created_at,
|
||||
updated_at,
|
||||
email_address,
|
||||
email_address_verified,
|
||||
full_name
|
||||
)
|
||||
SELECT
|
||||
generate_gid('\x0000000000000000' :: bytea, 11),
|
||||
NOW(),
|
||||
NOW(),
|
||||
p.primary_email_address,
|
||||
FALSE,
|
||||
p.full_name
|
||||
FROM
|
||||
peoples p ON CONFLICT DO NOTHING;
|
||||
|
||||
-- 4. Create missing memberships & profiles
|
||||
WITH people_identities AS (
|
||||
SELECT
|
||||
i.id AS identity_id,
|
||||
p.tenant_id AS tenant_id,
|
||||
p.organization_id AS organization_id,
|
||||
p.kind AS kind,
|
||||
p.full_name AS full_name,
|
||||
p.additional_email_addresses AS additional_email_addresses,
|
||||
p.position AS position,
|
||||
p.contract_start_date AS contract_start_date,
|
||||
p.contract_end_date AS contract_end_date,
|
||||
sc.id IS NOT NULL AS scim
|
||||
FROM
|
||||
peoples
|
||||
JOIN identities i ON i.primary_email_address = p.primary_email_address
|
||||
JOIN organizations o ON o.id = p.organization_id
|
||||
LEFT JOIN iam_scim_configurations sc ON sc.organization_id = o.id
|
||||
),
|
||||
people_memberships AS (
|
||||
INSERT INTO
|
||||
iam_memberships (
|
||||
id,
|
||||
tenant_id,
|
||||
identity_id,
|
||||
organization_id,
|
||||
role,
|
||||
source,
|
||||
state,
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
SELECT
|
||||
generate_gid(decode_base64_unpadded(pi.tenant_id), 39),
|
||||
pi.tenant_id,
|
||||
pi.identity_id,
|
||||
pi.organization_id,
|
||||
'EMPLOYEE' :: authz_role,
|
||||
'MANUAL',
|
||||
CASE
|
||||
WHEN pi.scim THEN 'INACTIVE' :: membership_state
|
||||
ELSE 'ACTIVE' :: membership_state
|
||||
END,
|
||||
NOW(),
|
||||
NOW()
|
||||
FROM
|
||||
people_identities pi ON CONFLICT DO NOTHING RETURNING id AS membership_id,
|
||||
pi.identity_id AS identity_id,
|
||||
pi.tenant_id AS tenant_id,
|
||||
pi.organization_id AS organization_id,
|
||||
pi.kind AS kind,
|
||||
pi.full_name AS full_name,
|
||||
pi.additional_email_addresses AS additional_email_addresses,
|
||||
pi.position AS position,
|
||||
pi.contract_start_date AS contract_start_date,
|
||||
pi.contract_end_date AS contract_start_date,
|
||||
) -- Create missing profiles
|
||||
-- Note: we always have a profile for an existing membership (they are created together in the same TX),
|
||||
-- So it is safe to create the missing profiles from the newly created memberships
|
||||
INSERT INTO
|
||||
iam_membership_profiles (
|
||||
id,
|
||||
tenant_id,
|
||||
membership_id,
|
||||
full_name,
|
||||
kind,
|
||||
additional_email_addresses,
|
||||
position,
|
||||
contract_start_date,
|
||||
contract_end_date,
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
SELECT
|
||||
generate_gid(decode_base64_unpadded(pm.tenant_id), 51),
|
||||
pm.tenant_id,
|
||||
pm.membership_id,
|
||||
pm.full_name,
|
||||
pm.kind,
|
||||
pm.additional_email_addresses,
|
||||
pm.position,
|
||||
pm.contract_start_date,
|
||||
pm.contract_end_date,
|
||||
NOW(),
|
||||
NOW()
|
||||
FROM
|
||||
people_memberships pm ON CONFLICT DO NOTHING;
|
||||
|
||||
-- 5. Update all profiles from peoples
|
||||
WITH people_memberships AS (
|
||||
SELECT
|
||||
m.id AS membership_id,
|
||||
COALESCE(p.additional_email_addresses, [] :: CITEXT),
|
||||
COALESCE(p.kind, 'EMPLOYEE' :: PEOPLE_KIND),
|
||||
p.contract_start_date,
|
||||
p.contract_end_date,
|
||||
p.position,
|
||||
FROM
|
||||
iam_memberships m
|
||||
JOIN identities i ON i.id = m.identity_id
|
||||
LEFT JOIN peoples p ON p.primary_email_address = i.email_address
|
||||
AND p.organization_id = m.organization_id
|
||||
)
|
||||
UPDATE
|
||||
iam_membership_profiles
|
||||
SET
|
||||
additional_email_addresses = pm.additional_email_addresses,
|
||||
kind = pm.kind,
|
||||
contract_start_date = pm.contract_start_date,
|
||||
contract_end_date = pm.contract_end_date,
|
||||
position = pm.position
|
||||
FROM
|
||||
people_memberships pm
|
||||
WHERE
|
||||
membership_id = pm.membership_id;
|
||||
|
||||
-- 6. Fill new references to profiles (e.g. previous references to peoples)
|
||||
WITH people_profiles AS (
|
||||
SELECT
|
||||
mp.id AS membership_profile_id,
|
||||
p.id AS people_id
|
||||
FROM
|
||||
iam_membership_profiles mp
|
||||
JOIN iam_memberships m ON m.id = mp.membership_id
|
||||
JOIN identities i ON i.id = m.identity_id
|
||||
LEFT JOIN peoples p ON p.primary_email_address = i.email_address
|
||||
),
|
||||
updated_assets AS (
|
||||
UPDATE
|
||||
assets a
|
||||
SET
|
||||
owner_profile_id = pp.membership_profile_id
|
||||
FROM
|
||||
people_profiles pp
|
||||
WHERE
|
||||
a.owner_id = pp.people_id
|
||||
),
|
||||
updated_ci AS (
|
||||
UPDATE
|
||||
continual_improvements ci
|
||||
SET
|
||||
owner_profile_id = pp.membership_profile_id
|
||||
FROM
|
||||
people_profiles pp
|
||||
WHERE
|
||||
ci.owner_id = pp.people_id
|
||||
),
|
||||
updated_data AS (
|
||||
UPDATE
|
||||
data d
|
||||
SET
|
||||
owner_profile_id = pp.membership_profile_id
|
||||
FROM
|
||||
people_profiles pp
|
||||
WHERE
|
||||
d.owner_id = pp.people_id
|
||||
),
|
||||
updated_dv AS (
|
||||
UPDATE
|
||||
document_versions dv
|
||||
SET
|
||||
owner_profile_id = pp.membership_profile_id
|
||||
FROM
|
||||
people_profiles pp
|
||||
WHERE
|
||||
dv.owner_id = pp.people_id
|
||||
),
|
||||
updated_ma AS (
|
||||
UPDATE
|
||||
meeting_attendees ma
|
||||
SET
|
||||
attendee_profile_id = pp.membership_profile_id
|
||||
FROM
|
||||
people_profiles pp
|
||||
WHERE
|
||||
ma.attendee_id = pp.people_id
|
||||
),
|
||||
updated_nc AS (
|
||||
UPDATE
|
||||
nonconformities nc
|
||||
SET
|
||||
owner_profile_id = pp.membership_profile_id
|
||||
FROM
|
||||
people_profiles pp
|
||||
WHERE
|
||||
nc.owner_id = pp.people_id
|
||||
),
|
||||
updated_obligations AS (
|
||||
UPDATE
|
||||
obligations o
|
||||
SET
|
||||
owner_profile_id = pp.membership_profile_id
|
||||
FROM
|
||||
people_profiles pp
|
||||
WHERE
|
||||
o.owner_id = pp.people_id
|
||||
),
|
||||
updated_documents AS (
|
||||
UPDATE
|
||||
documents d
|
||||
SET
|
||||
owner_profile_id = pp.membership_profile_id
|
||||
FROM
|
||||
people_profiles pp
|
||||
WHERE
|
||||
d.owner_id = pp.people_id
|
||||
),
|
||||
updated_dvs AS (
|
||||
UPDATE
|
||||
document_version_signatures dvs
|
||||
SET
|
||||
signed_by_profile_id = pp.membership_profile_id
|
||||
FROM
|
||||
people_profiles pp
|
||||
WHERE
|
||||
dvs.signed_by = pp.people_id
|
||||
),
|
||||
updated_pa AS (
|
||||
UPDATE
|
||||
processing_activities pa
|
||||
SET
|
||||
dpo_profile_id = pp.membership_profile_id
|
||||
FROM
|
||||
people_profiles pp
|
||||
WHERE
|
||||
pa.data_protection_officer_id = pp.people_id
|
||||
),
|
||||
updated_risks AS (
|
||||
UPDATE
|
||||
risks r
|
||||
SET
|
||||
owner_profile_id = pp.membership_profile_id
|
||||
FROM
|
||||
people_profiles pp
|
||||
WHERE
|
||||
r.owner_id = pp.people_id
|
||||
),
|
||||
updated_soa AS (
|
||||
UPDATE
|
||||
states_of_applicability soa
|
||||
SET
|
||||
owner_profile_id = pp.membership_profile_id
|
||||
FROM
|
||||
people_profiles pp
|
||||
WHERE
|
||||
soa.owner_id = pp.people_id
|
||||
),
|
||||
updated_tasks AS (
|
||||
UPDATE
|
||||
tasks t
|
||||
SET
|
||||
assigned_to_profile_id = pp.membership_profile_id
|
||||
FROM
|
||||
people_profiles pp
|
||||
WHERE
|
||||
t.assigned_to = pp.people_id
|
||||
),
|
||||
updated_vendors AS (
|
||||
UPDATE
|
||||
vendors v
|
||||
SET
|
||||
business_owner_profile_id = pp.membership_profile_id
|
||||
FROM
|
||||
people_profiles pp
|
||||
WHERE
|
||||
v.business_owner_id = pp.people_id
|
||||
)
|
||||
UPDATE
|
||||
vendors v
|
||||
SET
|
||||
security_owner_profile_id = pp.membership_profile_id
|
||||
FROM
|
||||
people_profiles pp
|
||||
WHERE
|
||||
v.security_owner_id = pp.people_id;
|
||||
|
||||
-- 7. Now that references are filled, add the NOT NULL constraints to those who need it
|
||||
ALTER TABLE
|
||||
assets
|
||||
ALTER COLUMN
|
||||
owner_profile_id
|
||||
SET
|
||||
NOT NULL;
|
||||
|
||||
ALTER TABLE
|
||||
continual_improvements
|
||||
ALTER COLUMN
|
||||
owner_profile_id
|
||||
SET
|
||||
NOT NULL;
|
||||
|
||||
ALTER TABLE
|
||||
data
|
||||
ALTER COLUMN
|
||||
owner_profile_id
|
||||
SET
|
||||
NOT NULL;
|
||||
|
||||
ALTER TABLE
|
||||
document_versions
|
||||
ALTER COLUMN
|
||||
owner_profile_id
|
||||
SET
|
||||
NOT NULL;
|
||||
|
||||
ALTER TABLE
|
||||
meeting_attendees
|
||||
ALTER COLUMN
|
||||
attendee_profile_id
|
||||
SET
|
||||
NOT NULL;
|
||||
|
||||
ALTER TABLE
|
||||
nonconformities
|
||||
ALTER COLUMN
|
||||
owner_profile_id
|
||||
SET
|
||||
NOT NULL;
|
||||
|
||||
ALTER TABLE
|
||||
obligations
|
||||
ALTER COLUMN
|
||||
owner_profile_id
|
||||
SET
|
||||
NOT NULL;
|
||||
|
||||
ALTER TABLE
|
||||
document_version_signatures
|
||||
ALTER COLUMN
|
||||
signed_by_profile_id
|
||||
SET
|
||||
NOT NULL;
|
||||
|
||||
ALTER TABLE
|
||||
states_of_applicability
|
||||
ALTER COLUMN
|
||||
owner_profile_id
|
||||
SET
|
||||
NOT NULL;
|
||||
|
||||
-- 8. Expire any potential invitation that is now obsolete since we created memberships
|
||||
ALTER TABLE
|
||||
iam_invitations
|
||||
ALTER COLUMN
|
||||
email TYPE CITEXT [];
|
||||
|
||||
WITH people_identities AS (
|
||||
SELECT
|
||||
m.organization_id AS organization_id,
|
||||
i.email_address AS email_address
|
||||
FROM
|
||||
iam_memberships m
|
||||
JOIN identities i ON i.id = m.identity_id
|
||||
JOIN peoples p ON p.primary_email_address = i.email_address
|
||||
AND p.organization_id = m.organization_id
|
||||
)
|
||||
UPDATE
|
||||
iam_invitations i
|
||||
SET
|
||||
expires_at = NOW()
|
||||
FROM
|
||||
people_identities pi
|
||||
WHERE
|
||||
pi.organization_id = i.organization_id
|
||||
AND i.email = pi.email_address;
|
||||
Reference in New Issue
Block a user