From 55a8e72c17fa91c051514b3e4e00b83fa3473a06 Mon Sep 17 00:00:00 2001 From: Bryan Frimin Date: Fri, 10 Jul 2026 15:11:40 +0200 Subject: [PATCH] Rename external URLs and move profile fields Rename the compliance external URL concept to compliance custom links, and move the public-facing profile fields (description, website, email, headquarter address) off the organization onto the trust center. Backfill managed default domains for pages that lack them. Signed-off-by: Bryan Frimin --- pkg/coredata/audit_log_resource_type.go | 4 +- ...ernal_url.go => compliance_custom_link.go} | 64 +++++------ ... => compliance_custom_link_order_field.go} | 44 +++---- pkg/coredata/migrations/20260710T081759Z.sql | 19 ++++ pkg/coredata/migrations/20260710T085314Z.sql | 34 ++++++ pkg/coredata/migrations/20260710T121004Z.sql | 107 ++++++++++++++++++ pkg/coredata/organization.go | 99 +--------------- pkg/iam/organization_service.go | 52 ++++----- pkg/probo/organization_service.go | 31 ----- 9 files changed, 239 insertions(+), 215 deletions(-) rename pkg/coredata/{compliance_external_url.go => compliance_custom_link.go} (79%) rename pkg/coredata/{compliance_external_url_order_field.go => compliance_custom_link_order_field.go} (53%) create mode 100644 pkg/coredata/migrations/20260710T081759Z.sql create mode 100644 pkg/coredata/migrations/20260710T085314Z.sql create mode 100644 pkg/coredata/migrations/20260710T121004Z.sql diff --git a/pkg/coredata/audit_log_resource_type.go b/pkg/coredata/audit_log_resource_type.go index c81fbbd36..8a272e43e 100644 --- a/pkg/coredata/audit_log_resource_type.go +++ b/pkg/coredata/audit_log_resource_type.go @@ -105,8 +105,8 @@ func ResourceTypeName(entityType uint16) string { return "WebhookSubscription" case ComplianceFrameworkEntityType: return "ComplianceFramework" - case ComplianceExternalURLEntityType: - return "ComplianceExternalURL" + case ComplianceCustomLinkEntityType: + return "ComplianceCustomLink" case MailingListEntityType: return "MailingList" case MailingListSubscriberEntityType: diff --git a/pkg/coredata/compliance_external_url.go b/pkg/coredata/compliance_custom_link.go similarity index 79% rename from pkg/coredata/compliance_external_url.go rename to pkg/coredata/compliance_custom_link.go index 0ce8cc630..6bc53c9d4 100644 --- a/pkg/coredata/compliance_external_url.go +++ b/pkg/coredata/compliance_custom_link.go @@ -35,7 +35,7 @@ import ( ) type ( - ComplianceExternalURL struct { + ComplianceCustomLink struct { ID gid.GID `db:"id"` OrganizationID gid.GID `db:"organization_id"` TrustCenterID gid.GID `db:"trust_center_id"` @@ -46,26 +46,26 @@ type ( UpdatedAt time.Time `db:"updated_at"` } - ComplianceExternalURLs []*ComplianceExternalURL + ComplianceCustomLinks []*ComplianceCustomLink ) -func (c ComplianceExternalURL) CursorKey(orderBy ComplianceExternalURLOrderField) page.CursorKey { +func (c ComplianceCustomLink) CursorKey(orderBy ComplianceCustomLinkOrderField) page.CursorKey { switch orderBy { - case ComplianceExternalURLOrderFieldCreatedAt: + case ComplianceCustomLinkOrderFieldCreatedAt: return page.NewCursorKey(c.ID, c.CreatedAt) - case ComplianceExternalURLOrderFieldRank: + case ComplianceCustomLinkOrderFieldRank: return page.NewCursorKey(c.ID, c.Rank) } panic(fmt.Sprintf("unsupported order by: %s", orderBy)) } -func (c *ComplianceExternalURL) AuthorizationAttributes( +func (c *ComplianceCustomLink) AuthorizationAttributes( ctx context.Context, conn pg.Querier, resourceIDs []gid.GID, ) (policy.AttributesByID, error) { - q := `SELECT id, organization_id FROM compliance_external_urls WHERE id = ANY(@resource_ids::text[])` + q := `SELECT id, organization_id FROM compliance_custom_links WHERE id = ANY(@resource_ids::text[])` args := pgx.StrictNamedArgs{ "resource_ids": resourceIDs, @@ -99,7 +99,7 @@ func (c *ComplianceExternalURL) AuthorizationAttributes( return attrsByID, nil } -func (c *ComplianceExternalURL) LoadByID( +func (c *ComplianceCustomLink) LoadByID( ctx context.Context, conn pg.Querier, scope Scoper, @@ -116,7 +116,7 @@ SELECT created_at, updated_at FROM - compliance_external_urls + compliance_custom_links WHERE %s AND id = @id @@ -129,16 +129,16 @@ LIMIT 1; rows, err := conn.Query(ctx, q, args) if err != nil { - return fmt.Errorf("cannot query compliance_external_urls: %w", err) + return fmt.Errorf("cannot query compliance_custom_links: %w", err) } - result, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[ComplianceExternalURL]) + result, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[ComplianceCustomLink]) if err != nil { if errors.Is(err, pgx.ErrNoRows) { return ErrResourceNotFound } - return fmt.Errorf("cannot collect compliance external URL: %w", err) + return fmt.Errorf("cannot collect compliance custom link: %w", err) } *c = result @@ -146,14 +146,14 @@ LIMIT 1; return nil } -func (c *ComplianceExternalURL) Insert( +func (c *ComplianceCustomLink) Insert( ctx context.Context, conn pg.Tx, scope Scoper, ) error { q := ` INSERT INTO - compliance_external_urls ( + compliance_custom_links ( id, tenant_id, organization_id, @@ -171,7 +171,7 @@ VALUES ( @trust_center_id, @name, @url, - (SELECT COALESCE(MAX(rank), 0) + 1 FROM compliance_external_urls WHERE trust_center_id = @trust_center_id), + (SELECT COALESCE(MAX(rank), 0) + 1 FROM compliance_custom_links WHERE trust_center_id = @trust_center_id), @created_at, @updated_at ) @@ -190,19 +190,19 @@ RETURNING rank; } if err := conn.QueryRow(ctx, q, args).Scan(&c.Rank); err != nil { - return fmt.Errorf("cannot insert compliance external URL: %w", err) + return fmt.Errorf("cannot insert compliance custom link: %w", err) } return nil } -func (c *ComplianceExternalURL) Update( +func (c *ComplianceCustomLink) Update( ctx context.Context, conn pg.Tx, scope Scoper, ) error { q := ` -UPDATE compliance_external_urls +UPDATE compliance_custom_links SET name = @name, url = @url, @@ -223,13 +223,13 @@ WHERE _, err := conn.Exec(ctx, q, args) if err != nil { - return fmt.Errorf("cannot update compliance external URL: %w", err) + return fmt.Errorf("cannot update compliance custom link: %w", err) } return nil } -func (c *ComplianceExternalURL) UpdateRank( +func (c *ComplianceCustomLink) UpdateRank( ctx context.Context, conn pg.Tx, scope Scoper, @@ -238,11 +238,11 @@ func (c *ComplianceExternalURL) UpdateRank( WITH old AS ( SELECT rank AS old_rank - FROM compliance_external_urls + FROM compliance_custom_links WHERE %s AND id = @id AND trust_center_id = @trust_center_id ) -UPDATE compliance_external_urls +UPDATE compliance_custom_links SET rank = CASE WHEN id = @id THEN @new_rank @@ -274,20 +274,20 @@ WHERE %s _, err := conn.Exec(ctx, q, args) if err != nil { - return fmt.Errorf("cannot update compliance external URL rank: %w", err) + return fmt.Errorf("cannot update compliance custom link rank: %w", err) } return nil } -func (c *ComplianceExternalURL) Delete( +func (c *ComplianceCustomLink) Delete( ctx context.Context, conn pg.Tx, scope Scoper, ) error { q := ` DELETE FROM - compliance_external_urls + compliance_custom_links WHERE %s AND id = @id; @@ -299,18 +299,18 @@ WHERE _, err := conn.Exec(ctx, q, args) if err != nil { - return fmt.Errorf("cannot delete compliance external URL: %w", err) + return fmt.Errorf("cannot delete compliance custom link: %w", err) } return nil } -func (c *ComplianceExternalURLs) LoadByTrustCenterID( +func (c *ComplianceCustomLinks) LoadByTrustCenterID( ctx context.Context, conn pg.Querier, scope Scoper, trustCenterID gid.GID, - cursor *page.Cursor[ComplianceExternalURLOrderField], + cursor *page.Cursor[ComplianceCustomLinkOrderField], ) error { q := ` SELECT @@ -323,7 +323,7 @@ SELECT created_at, updated_at FROM - compliance_external_urls + compliance_custom_links WHERE %s AND trust_center_id = @trust_center_id @@ -337,12 +337,12 @@ WHERE rows, err := conn.Query(ctx, q, args) if err != nil { - return fmt.Errorf("cannot query compliance_external_urls: %w", err) + return fmt.Errorf("cannot query compliance_custom_links: %w", err) } - results, err := pgx.CollectRows(rows, pgx.RowToAddrOfStructByName[ComplianceExternalURL]) + results, err := pgx.CollectRows(rows, pgx.RowToAddrOfStructByName[ComplianceCustomLink]) if err != nil { - return fmt.Errorf("cannot collect compliance external URLs: %w", err) + return fmt.Errorf("cannot collect compliance custom links: %w", err) } *c = results diff --git a/pkg/coredata/compliance_external_url_order_field.go b/pkg/coredata/compliance_custom_link_order_field.go similarity index 53% rename from pkg/coredata/compliance_external_url_order_field.go rename to pkg/coredata/compliance_custom_link_order_field.go index 481e48534..0f1b2030f 100644 --- a/pkg/coredata/compliance_external_url_order_field.go +++ b/pkg/coredata/compliance_custom_link_order_field.go @@ -28,51 +28,51 @@ import ( ) type ( - ComplianceExternalURLOrderField string + ComplianceCustomLinkOrderField string ) const ( - ComplianceExternalURLOrderFieldCreatedAt ComplianceExternalURLOrderField = "CREATED_AT" - ComplianceExternalURLOrderFieldRank ComplianceExternalURLOrderField = "RANK" + ComplianceCustomLinkOrderFieldCreatedAt ComplianceCustomLinkOrderField = "CREATED_AT" + ComplianceCustomLinkOrderFieldRank ComplianceCustomLinkOrderField = "RANK" ) var ( - _ page.OrderField = ComplianceExternalURLOrderField("") - _ fmt.Stringer = ComplianceExternalURLOrderField("") - _ encoding.TextMarshaler = ComplianceExternalURLOrderField("") - _ encoding.TextUnmarshaler = (*ComplianceExternalURLOrderField)(nil) + _ page.OrderField = ComplianceCustomLinkOrderField("") + _ fmt.Stringer = ComplianceCustomLinkOrderField("") + _ encoding.TextMarshaler = ComplianceCustomLinkOrderField("") + _ encoding.TextUnmarshaler = (*ComplianceCustomLinkOrderField)(nil) ) -func ComplianceExternalURLOrderFields() []ComplianceExternalURLOrderField { - return []ComplianceExternalURLOrderField{ - ComplianceExternalURLOrderFieldCreatedAt, - ComplianceExternalURLOrderFieldRank, +func ComplianceCustomLinkOrderFields() []ComplianceCustomLinkOrderField { + return []ComplianceCustomLinkOrderField{ + ComplianceCustomLinkOrderFieldCreatedAt, + ComplianceCustomLinkOrderFieldRank, } } -func (v ComplianceExternalURLOrderField) IsValid() bool { +func (v ComplianceCustomLinkOrderField) IsValid() bool { switch v { case - ComplianceExternalURLOrderFieldCreatedAt, - ComplianceExternalURLOrderFieldRank: + ComplianceCustomLinkOrderFieldCreatedAt, + ComplianceCustomLinkOrderFieldRank: return true } return false } -func (v ComplianceExternalURLOrderField) String() string { +func (v ComplianceCustomLinkOrderField) String() string { return string(v) } -func (v ComplianceExternalURLOrderField) MarshalText() ([]byte, error) { +func (v ComplianceCustomLinkOrderField) MarshalText() ([]byte, error) { return []byte(v.String()), nil } -func (v *ComplianceExternalURLOrderField) UnmarshalText(text []byte) error { - val := ComplianceExternalURLOrderField(text) +func (v *ComplianceCustomLinkOrderField) UnmarshalText(text []byte) error { + val := ComplianceCustomLinkOrderField(text) if !val.IsValid() { - return fmt.Errorf("invalid ComplianceExternalURLOrderField value: %q", string(text)) + return fmt.Errorf("invalid ComplianceCustomLinkOrderField value: %q", string(text)) } *v = val @@ -80,11 +80,11 @@ func (v *ComplianceExternalURLOrderField) UnmarshalText(text []byte) error { return nil } -func (p ComplianceExternalURLOrderField) Column() string { +func (p ComplianceCustomLinkOrderField) Column() string { switch p { - case ComplianceExternalURLOrderFieldCreatedAt: + case ComplianceCustomLinkOrderFieldCreatedAt: return "created_at" - case ComplianceExternalURLOrderFieldRank: + case ComplianceCustomLinkOrderFieldRank: return "rank" default: return string(p) diff --git a/pkg/coredata/migrations/20260710T081759Z.sql b/pkg/coredata/migrations/20260710T081759Z.sql new file mode 100644 index 000000000..17a3a1b32 --- /dev/null +++ b/pkg/coredata/migrations/20260710T081759Z.sql @@ -0,0 +1,19 @@ +-- Copyright (c) 2026 Probo Inc . +-- +-- 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 compliance_external_urls RENAME TO compliance_custom_links; + +ALTER TABLE compliance_custom_links +RENAME CONSTRAINT compliance_external_urls_trust_center_id_rank_key + TO compliance_custom_links_trust_center_id_rank_key; diff --git a/pkg/coredata/migrations/20260710T085314Z.sql b/pkg/coredata/migrations/20260710T085314Z.sql new file mode 100644 index 000000000..e1959fe9f --- /dev/null +++ b/pkg/coredata/migrations/20260710T085314Z.sql @@ -0,0 +1,34 @@ +-- Copyright (c) 2026 Probo Inc . +-- +-- 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 trust_centers + ADD COLUMN description TEXT, + ADD COLUMN website_url TEXT, + ADD COLUMN email CITEXT, + ADD COLUMN headquarter_address TEXT; + +UPDATE trust_centers tc +SET + description = o.description, + website_url = o.website_url, + email = o.email, + headquarter_address = o.headquarter_address +FROM organizations o +WHERE tc.organization_id = o.id; + +ALTER TABLE organizations + DROP COLUMN description, + DROP COLUMN website_url, + DROP COLUMN email, + DROP COLUMN headquarter_address; diff --git a/pkg/coredata/migrations/20260710T121004Z.sql b/pkg/coredata/migrations/20260710T121004Z.sql new file mode 100644 index 000000000..19d336d36 --- /dev/null +++ b/pkg/coredata/migrations/20260710T121004Z.sql @@ -0,0 +1,107 @@ +-- Copyright (c) 2026 Probo Inc . +-- +-- 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. + +-- Backfill managed default domains for compliance pages created before +-- default-domain provisioning existed. Hostnames use the managed base domain +-- suffix configured on the database (probo.trust_center_base_domain), falling +-- back to probopage.com for production installs. + +WITH pending_pages AS ( + SELECT + tc.id AS trust_center_id, + tc.tenant_id, + tc.organization_id, + tc.slug, + tc.created_at, + ( + tc.slug || '.' || COALESCE( + NULLIF(current_setting('probo.trust_center_base_domain', true), ''), + 'probopage.com' + ) + )::citext AS hostname + FROM trust_centers tc + WHERE tc.default_domain_id IS NULL +), +minted_certificates AS ( + INSERT INTO certificates ( + id, + tenant_id, + hostname, + status, + ssl_retry_count, + created_at, + updated_at + ) + SELECT + translate( + encode( + substring(decode(translate(pp.trust_center_id, '-_', '+/'), 'base64') FROM 1 FOR 8) + || int2send(104::smallint) + || int8send((floor(extract(epoch FROM clock_timestamp()) * 1000))::bigint) + || substring(decode(md5(random()::text || pp.trust_center_id), 'hex') FROM 1 FOR 6), + 'base64' + ), + '+/', + '-_' + ), + pp.tenant_id, + pp.hostname, + 'PENDING'::custom_domain_ssl_status, + 0, + pp.created_at, + clock_timestamp() + FROM pending_pages pp + RETURNING id, hostname, tenant_id +), +minted_domains AS ( + INSERT INTO custom_domains ( + id, + tenant_id, + organization_id, + domain, + managed, + certificate_id, + created_at, + updated_at + ) + SELECT + translate( + encode( + substring(decode(translate(mc.id, '-_', '+/'), 'base64') FROM 1 FOR 8) + || int2send(37::smallint) + || int8send((floor(extract(epoch FROM clock_timestamp()) * 1000))::bigint) + || substring(decode(md5(random()::text || mc.id), 'hex') FROM 1 FOR 6), + 'base64' + ), + '+/', + '-_' + ), + mc.tenant_id, + pp.organization_id, + pp.hostname, + true, + mc.id, + pp.created_at, + clock_timestamp() + FROM minted_certificates mc + JOIN pending_pages pp ON pp.hostname = mc.hostname + RETURNING id, domain +) +UPDATE trust_centers tc +SET + default_domain_id = md.id, + updated_at = clock_timestamp() +FROM minted_domains md +JOIN pending_pages pp ON pp.hostname = md.domain +WHERE tc.id = pp.trust_center_id; diff --git a/pkg/coredata/organization.go b/pkg/coredata/organization.go index 51083f96b..6614483fc 100644 --- a/pkg/coredata/organization.go +++ b/pkg/coredata/organization.go @@ -41,11 +41,6 @@ type ( Name string `db:"name"` LogoFileID *gid.GID `db:"logo_file_id"` HorizontalLogoFileID *gid.GID `db:"horizontal_logo_file_id"` - Description *string `db:"description"` - WebsiteURL *string `db:"website_url"` - Email *string `db:"email"` - HeadquarterAddress *string `db:"headquarter_address"` - CustomDomainID *gid.GID `db:"custom_domain_id"` CreatedAt time.Time `db:"created_at"` UpdatedAt time.Time `db:"updated_at"` } @@ -117,11 +112,6 @@ SELECT name, logo_file_id, horizontal_logo_file_id, - description, - website_url, - email, - headquarter_address, - custom_domain_id, created_at, updated_at FROM @@ -169,11 +159,6 @@ SELECT name, logo_file_id, horizontal_logo_file_id, - description, - website_url, - email, - headquarter_address, - custom_domain_id, created_at, updated_at FROM @@ -229,11 +214,6 @@ SELECT name, logo_file_id, horizontal_logo_file_id, - description, - website_url, - email, - headquarter_address, - custom_domain_id, created_at, updated_at FROM @@ -290,11 +270,6 @@ SELECT name, logo_file_id, horizontal_logo_file_id, - description, - website_url, - email, - headquarter_address, - custom_domain_id, created_at, updated_at FROM @@ -338,14 +313,9 @@ INSERT INTO organizations ( name, logo_file_id, horizontal_logo_file_id, - description, - website_url, - email, - headquarter_address, - custom_domain_id, created_at, updated_at -) VALUES (@tenant_id, @id, @name, @logo_file_id, @horizontal_logo_file_id, @description, @website_url, @email, @headquarter_address, @custom_domain_id, @created_at, @updated_at) +) VALUES (@tenant_id, @id, @name, @logo_file_id, @horizontal_logo_file_id, @created_at, @updated_at) ` args := pgx.StrictNamedArgs{ @@ -354,11 +324,6 @@ INSERT INTO organizations ( "name": o.Name, "logo_file_id": o.LogoFileID, "horizontal_logo_file_id": o.HorizontalLogoFileID, - "description": o.Description, - "website_url": o.WebsiteURL, - "email": o.Email, - "headquarter_address": o.HeadquarterAddress, - "custom_domain_id": o.CustomDomainID, "created_at": o.CreatedAt, "updated_at": o.UpdatedAt, } @@ -382,11 +347,6 @@ SET name = @name, logo_file_id = @logo_file_id, horizontal_logo_file_id = @horizontal_logo_file_id, - description = @description, - website_url = @website_url, - email = @email, - headquarter_address = @headquarter_address, - custom_domain_id = @custom_domain_id, updated_at = @updated_at WHERE %s @@ -400,11 +360,6 @@ WHERE "name": o.Name, "logo_file_id": o.LogoFileID, "horizontal_logo_file_id": o.HorizontalLogoFileID, - "description": o.Description, - "website_url": o.WebsiteURL, - "email": o.Email, - "headquarter_address": o.HeadquarterAddress, - "custom_domain_id": o.CustomDomainID, "updated_at": o.UpdatedAt, } @@ -437,55 +392,3 @@ WHERE id = @id return nil } - -func (o *Organization) LoadByCustomDomainID( - ctx context.Context, - conn pg.Querier, - scope Scoper, - customDomainID gid.GID, -) error { - q := ` -SELECT - tenant_id, - id, - name, - logo_file_id, - horizontal_logo_file_id, - description, - website_url, - email, - headquarter_address, - custom_domain_id, - created_at, - updated_at -FROM - organizations -WHERE - %s - AND custom_domain_id = @custom_domain_id -LIMIT 1 -` - - q = fmt.Sprintf(q, scope.SQLFragment()) - - args := pgx.StrictNamedArgs{"custom_domain_id": customDomainID} - maps.Copy(args, scope.SQLArguments()) - - rows, err := conn.Query(ctx, q, args) - if err != nil { - return fmt.Errorf("cannot query organization by custom domain: %w", err) - } - - organization, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[Organization]) - if err != nil { - if errors.Is(err, pgx.ErrNoRows) { - return ErrResourceNotFound - } - - return fmt.Errorf("cannot collect organization: %w", err) - } - - *o = organization - - return nil -} diff --git a/pkg/iam/organization_service.go b/pkg/iam/organization_service.go index 5212c1a85..55e71435e 100644 --- a/pkg/iam/organization_service.go +++ b/pkg/iam/organization_service.go @@ -69,10 +69,6 @@ type ( Name *string LogoFile *UploadedFile HorizontalLogoFile *UploadedFile - Description **string - WebsiteURL **string - Email **string - HeadquarterAddress **string } CreateSAMLConfigurationRequest struct { @@ -191,10 +187,6 @@ func (req UpdateOrganizationRequest) Validate() error { fv := filevalidation.NewValidator(filevalidation.WithCategories(filevalidation.CategoryImage)) v.Check(req.Name, "name", validator.SafeTextNoNewLine(255)) - v.Check(req.Description, "description", validator.SafeText(ContentMaxLength)) - v.Check(req.WebsiteURL, "website_url", validator.SafeText(2048)) - v.Check(req.Email, "email", validator.SafeText(255)) - v.Check(req.HeadquarterAddress, "headquarter_address", validator.SafeText(2048)) v.Check(req.LogoFile, "logo_file", validator.NotEmpty()) if req.LogoFile != nil { @@ -763,6 +755,28 @@ func (s *OrganizationService) CreateOrganization( return fmt.Errorf("cannot insert mailing list: %w", err) } + defaultDomainHostname := trustCenter.Slug + "." + s.trustCenterBaseDomain + + defaultDomain := coredata.NewCustomDomain( + tenantID, + organization.ID, + defaultDomainHostname, + true, + ) + + certificate, err := s.certManager.EnsureCertificate(ctx, tx, scope, defaultDomainHostname) + if err != nil { + return fmt.Errorf("cannot ensure certificate for default custom domain: %w", err) + } + + defaultDomain.CertificateID = &certificate.ID + + if err := defaultDomain.Insert(ctx, tx, scope); err != nil { + return fmt.Errorf("cannot insert default custom domain: %w", err) + } + + trustCenter.DefaultDomainID = &defaultDomain.ID + if err := trustCenter.Insert(ctx, tx, scope); err != nil { return fmt.Errorf("cannot insert trust center: %w", err) } @@ -905,28 +919,6 @@ func (s *OrganizationService) UpdateOrganization(ctx context.Context, organizati organization.Name = *req.Name } - if req.Description != nil { - organization.Description = *req.Description - } - - if req.WebsiteURL != nil { - organization.WebsiteURL = *req.WebsiteURL - } - - if req.Email != nil { - if *req.Email != nil { - if _, err := mail.ParseAddr(**req.Email); err != nil { - return fmt.Errorf("invalid email address: %w", err) - } - } - - organization.Email = *req.Email - } - - if req.HeadquarterAddress != nil { - organization.HeadquarterAddress = *req.HeadquarterAddress - } - if logoFile != nil { if err := logoFile.Insert(ctx, tx, scope); err != nil { return fmt.Errorf("cannot insert file: %w", err) diff --git a/pkg/probo/organization_service.go b/pkg/probo/organization_service.go index 33055159e..307ba0f49 100644 --- a/pkg/probo/organization_service.go +++ b/pkg/probo/organization_service.go @@ -25,7 +25,6 @@ import ( "errors" "fmt" "mime" - "net/mail" "path/filepath" "time" @@ -49,10 +48,6 @@ type ( Name *string File *File HorizontalLogoFile *File - Description **string - WebsiteURL **string - Email **string - HeadquarterAddress **string } UpdateOrganizationContextRequest struct { @@ -70,10 +65,6 @@ func (uor *UpdateOrganizationRequest) Validate() error { v.Check(uor.ID, "id", validator.Required(), validator.GID(coredata.OrganizationEntityType)) v.Check(uor.Name, "name", validator.SafeTextNoNewLine(TitleMaxLength)) - v.Check(uor.Description, "description", validator.SafeText(ContentMaxLength)) - v.Check(uor.WebsiteURL, "website_url", validator.SafeText(2048)) - v.Check(uor.Email, "email", validator.SafeText(255)) - v.Check(uor.HeadquarterAddress, "headquarter_address", validator.SafeText(2048)) v.Check(uor.File, "file", validator.NotEmpty()) v.Check(uor.HorizontalLogoFile, "horizontal_logo_file", validator.NotEmpty()) @@ -256,28 +247,6 @@ func (s OrganizationService) Update( organization.Name = *req.Name } - if req.Description != nil { - organization.Description = *req.Description - } - - if req.WebsiteURL != nil { - organization.WebsiteURL = *req.WebsiteURL - } - - if req.Email != nil { - if *req.Email != nil { - if _, err := mail.ParseAddress(**req.Email); err != nil { - return fmt.Errorf("invalid email address: %w", err) - } - } - - organization.Email = *req.Email - } - - if req.HeadquarterAddress != nil { - organization.HeadquarterAddress = *req.HeadquarterAddress - } - if err := organization.Update(ctx, scope, tx); err != nil { return fmt.Errorf("cannot update organization: %w", err) }