Move custom domains onto trust centers
Custom domains previously hung off the organization. Attach them to the trust center instead, adding default and custom domain references plus a managed flag, and backfill existing rows. Domains now belong to a compliance page rather than the whole organization. Signed-off-by: Bryan Frimin <bryan@probo.com>
This commit is contained in:
33
pkg/coredata/migrations/20260706T132923Z.sql
Normal file
33
pkg/coredata/migrations/20260706T132923Z.sql
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
-- Copyright (c) 2026 Probo Inc <hello@probo.com>.
|
||||||
|
--
|
||||||
|
-- Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
-- purpose with or without fee is hereby granted, provided that the above
|
||||||
|
-- copyright notice and this permission notice appear in all copies.
|
||||||
|
--
|
||||||
|
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
-- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
-- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
-- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
|
-- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
|
-- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
-- PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
ALTER TABLE custom_domains ADD COLUMN managed BOOLEAN NOT NULL DEFAULT FALSE;
|
||||||
|
ALTER TABLE custom_domains ALTER COLUMN managed DROP DEFAULT;
|
||||||
|
|
||||||
|
ALTER TABLE trust_centers ADD COLUMN default_domain_id TEXT REFERENCES custom_domains(id) ON DELETE SET NULL;
|
||||||
|
ALTER TABLE trust_centers ADD COLUMN custom_domain_id TEXT REFERENCES custom_domains(id) ON DELETE SET NULL;
|
||||||
|
|
||||||
|
UPDATE trust_centers tc
|
||||||
|
SET custom_domain_id = o.custom_domain_id
|
||||||
|
FROM organizations o
|
||||||
|
WHERE o.id = tc.organization_id AND o.custom_domain_id IS NOT NULL;
|
||||||
|
|
||||||
|
DELETE FROM custom_domains cd
|
||||||
|
WHERE NOT EXISTS (
|
||||||
|
SELECT 1 FROM trust_centers tc
|
||||||
|
WHERE tc.custom_domain_id = cd.id OR tc.default_domain_id = cd.id
|
||||||
|
);
|
||||||
|
|
||||||
|
DROP INDEX IF EXISTS idx_organizations_custom_domain;
|
||||||
|
ALTER TABLE organizations DROP COLUMN custom_domain_id;
|
||||||
@@ -47,6 +47,12 @@ type (
|
|||||||
LogoFileID *gid.GID `db:"logo_file_id"`
|
LogoFileID *gid.GID `db:"logo_file_id"`
|
||||||
DarkLogoFileID *gid.GID `db:"dark_logo_file_id"`
|
DarkLogoFileID *gid.GID `db:"dark_logo_file_id"`
|
||||||
NonDisclosureAgreementFileID *gid.GID `db:"non_disclosure_agreement_file_id"`
|
NonDisclosureAgreementFileID *gid.GID `db:"non_disclosure_agreement_file_id"`
|
||||||
|
DefaultDomainID *gid.GID `db:"default_domain_id"`
|
||||||
|
CustomDomainID *gid.GID `db:"custom_domain_id"`
|
||||||
|
Description *string `db:"description"`
|
||||||
|
WebsiteURL *string `db:"website_url"`
|
||||||
|
Email *string `db:"email"`
|
||||||
|
HeadquarterAddress *string `db:"headquarter_address"`
|
||||||
CreatedAt time.Time `db:"created_at"`
|
CreatedAt time.Time `db:"created_at"`
|
||||||
UpdatedAt time.Time `db:"updated_at"`
|
UpdatedAt time.Time `db:"updated_at"`
|
||||||
}
|
}
|
||||||
@@ -120,6 +126,12 @@ SELECT
|
|||||||
slug,
|
slug,
|
||||||
search_engine_indexing,
|
search_engine_indexing,
|
||||||
non_disclosure_agreement_file_id,
|
non_disclosure_agreement_file_id,
|
||||||
|
default_domain_id,
|
||||||
|
custom_domain_id,
|
||||||
|
description,
|
||||||
|
website_url,
|
||||||
|
email,
|
||||||
|
headquarter_address,
|
||||||
created_at,
|
created_at,
|
||||||
updated_at
|
updated_at
|
||||||
FROM
|
FROM
|
||||||
@@ -172,6 +184,12 @@ SELECT
|
|||||||
slug,
|
slug,
|
||||||
search_engine_indexing,
|
search_engine_indexing,
|
||||||
non_disclosure_agreement_file_id,
|
non_disclosure_agreement_file_id,
|
||||||
|
default_domain_id,
|
||||||
|
custom_domain_id,
|
||||||
|
description,
|
||||||
|
website_url,
|
||||||
|
email,
|
||||||
|
headquarter_address,
|
||||||
created_at,
|
created_at,
|
||||||
updated_at
|
updated_at
|
||||||
FROM
|
FROM
|
||||||
@@ -224,6 +242,12 @@ SELECT
|
|||||||
slug,
|
slug,
|
||||||
search_engine_indexing,
|
search_engine_indexing,
|
||||||
non_disclosure_agreement_file_id,
|
non_disclosure_agreement_file_id,
|
||||||
|
default_domain_id,
|
||||||
|
custom_domain_id,
|
||||||
|
description,
|
||||||
|
website_url,
|
||||||
|
email,
|
||||||
|
headquarter_address,
|
||||||
created_at,
|
created_at,
|
||||||
updated_at
|
updated_at
|
||||||
FROM
|
FROM
|
||||||
@@ -276,6 +300,12 @@ SELECT
|
|||||||
slug,
|
slug,
|
||||||
search_engine_indexing,
|
search_engine_indexing,
|
||||||
non_disclosure_agreement_file_id,
|
non_disclosure_agreement_file_id,
|
||||||
|
default_domain_id,
|
||||||
|
custom_domain_id,
|
||||||
|
description,
|
||||||
|
website_url,
|
||||||
|
email,
|
||||||
|
headquarter_address,
|
||||||
created_at,
|
created_at,
|
||||||
updated_at
|
updated_at
|
||||||
FROM
|
FROM
|
||||||
@@ -306,6 +336,65 @@ LIMIT 1;
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadByDomainID loads the compliance page that references the given custom
|
||||||
|
// domain in either of its two slots (default or custom). It powers the
|
||||||
|
// reverse SNI lookup: a served host resolves to a custom domain, which resolves
|
||||||
|
// back to its page. Tenant scope is not applied because SNI resolution happens
|
||||||
|
// across all tenants for public access.
|
||||||
|
func (tc *TrustCenter) LoadByDomainID(
|
||||||
|
ctx context.Context,
|
||||||
|
conn pg.Querier,
|
||||||
|
domainID gid.GID,
|
||||||
|
) error {
|
||||||
|
q := `
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
organization_id,
|
||||||
|
tenant_id,
|
||||||
|
mailing_list_id,
|
||||||
|
logo_file_id,
|
||||||
|
dark_logo_file_id,
|
||||||
|
active,
|
||||||
|
slug,
|
||||||
|
search_engine_indexing,
|
||||||
|
non_disclosure_agreement_file_id,
|
||||||
|
default_domain_id,
|
||||||
|
custom_domain_id,
|
||||||
|
description,
|
||||||
|
website_url,
|
||||||
|
email,
|
||||||
|
headquarter_address,
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
|
FROM
|
||||||
|
trust_centers
|
||||||
|
WHERE
|
||||||
|
default_domain_id = @domain_id
|
||||||
|
OR custom_domain_id = @domain_id
|
||||||
|
LIMIT 1;
|
||||||
|
`
|
||||||
|
|
||||||
|
args := pgx.StrictNamedArgs{"domain_id": domainID}
|
||||||
|
|
||||||
|
rows, err := conn.Query(ctx, q, args)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cannot query trust center by domain id: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
trustCenter, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[TrustCenter])
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return ErrResourceNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("cannot collect trust center: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
*tc = trustCenter
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (tc *TrustCenter) Insert(
|
func (tc *TrustCenter) Insert(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Tx,
|
conn pg.Tx,
|
||||||
@@ -323,6 +412,12 @@ INSERT INTO trust_centers (
|
|||||||
slug,
|
slug,
|
||||||
search_engine_indexing,
|
search_engine_indexing,
|
||||||
non_disclosure_agreement_file_id,
|
non_disclosure_agreement_file_id,
|
||||||
|
default_domain_id,
|
||||||
|
custom_domain_id,
|
||||||
|
description,
|
||||||
|
website_url,
|
||||||
|
email,
|
||||||
|
headquarter_address,
|
||||||
created_at,
|
created_at,
|
||||||
updated_at
|
updated_at
|
||||||
) VALUES (
|
) VALUES (
|
||||||
@@ -336,6 +431,12 @@ INSERT INTO trust_centers (
|
|||||||
@slug,
|
@slug,
|
||||||
@search_engine_indexing,
|
@search_engine_indexing,
|
||||||
@non_disclosure_agreement_file_id,
|
@non_disclosure_agreement_file_id,
|
||||||
|
@default_domain_id,
|
||||||
|
@custom_domain_id,
|
||||||
|
@description,
|
||||||
|
@website_url,
|
||||||
|
@email,
|
||||||
|
@headquarter_address,
|
||||||
@created_at,
|
@created_at,
|
||||||
@updated_at
|
@updated_at
|
||||||
)
|
)
|
||||||
@@ -352,6 +453,12 @@ INSERT INTO trust_centers (
|
|||||||
"slug": tc.Slug,
|
"slug": tc.Slug,
|
||||||
"search_engine_indexing": tc.SearchEngineIndexing,
|
"search_engine_indexing": tc.SearchEngineIndexing,
|
||||||
"non_disclosure_agreement_file_id": tc.NonDisclosureAgreementFileID,
|
"non_disclosure_agreement_file_id": tc.NonDisclosureAgreementFileID,
|
||||||
|
"default_domain_id": tc.DefaultDomainID,
|
||||||
|
"custom_domain_id": tc.CustomDomainID,
|
||||||
|
"description": tc.Description,
|
||||||
|
"website_url": tc.WebsiteURL,
|
||||||
|
"email": tc.Email,
|
||||||
|
"headquarter_address": tc.HeadquarterAddress,
|
||||||
"created_at": tc.CreatedAt,
|
"created_at": tc.CreatedAt,
|
||||||
"updated_at": tc.UpdatedAt,
|
"updated_at": tc.UpdatedAt,
|
||||||
}
|
}
|
||||||
@@ -384,6 +491,12 @@ SET
|
|||||||
logo_file_id = @logo_file_id,
|
logo_file_id = @logo_file_id,
|
||||||
dark_logo_file_id = @dark_logo_file_id,
|
dark_logo_file_id = @dark_logo_file_id,
|
||||||
non_disclosure_agreement_file_id = @non_disclosure_agreement_file_id,
|
non_disclosure_agreement_file_id = @non_disclosure_agreement_file_id,
|
||||||
|
default_domain_id = @default_domain_id,
|
||||||
|
custom_domain_id = @custom_domain_id,
|
||||||
|
description = @description,
|
||||||
|
website_url = @website_url,
|
||||||
|
email = @email,
|
||||||
|
headquarter_address = @headquarter_address,
|
||||||
updated_at = @updated_at
|
updated_at = @updated_at
|
||||||
WHERE
|
WHERE
|
||||||
%s
|
%s
|
||||||
@@ -400,6 +513,12 @@ WHERE
|
|||||||
"slug": tc.Slug,
|
"slug": tc.Slug,
|
||||||
"search_engine_indexing": tc.SearchEngineIndexing,
|
"search_engine_indexing": tc.SearchEngineIndexing,
|
||||||
"non_disclosure_agreement_file_id": tc.NonDisclosureAgreementFileID,
|
"non_disclosure_agreement_file_id": tc.NonDisclosureAgreementFileID,
|
||||||
|
"default_domain_id": tc.DefaultDomainID,
|
||||||
|
"custom_domain_id": tc.CustomDomainID,
|
||||||
|
"description": tc.Description,
|
||||||
|
"website_url": tc.WebsiteURL,
|
||||||
|
"email": tc.Email,
|
||||||
|
"headquarter_address": tc.HeadquarterAddress,
|
||||||
"updated_at": tc.UpdatedAt,
|
"updated_at": tc.UpdatedAt,
|
||||||
}
|
}
|
||||||
maps.Copy(args, scope.SQLArguments())
|
maps.Copy(args, scope.SQLArguments())
|
||||||
|
|||||||
Reference in New Issue
Block a user