Add role management
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
@@ -47,13 +47,14 @@ func (a *UserAPIKeyMembership) Insert(
|
||||
) error {
|
||||
q := `
|
||||
INSERT INTO
|
||||
authz_api_keys_memberships (id, tenant_id, auth_user_api_key_id, membership_id, role, created_at, updated_at)
|
||||
authz_api_keys_memberships (id, tenant_id, auth_user_api_key_id, membership_id, role, organization_id, created_at, updated_at)
|
||||
VALUES (
|
||||
@id,
|
||||
@tenant_id,
|
||||
@auth_user_api_key_id,
|
||||
@membership_id,
|
||||
@role,
|
||||
@organization_id,
|
||||
@created_at,
|
||||
@updated_at
|
||||
)
|
||||
@@ -65,6 +66,7 @@ VALUES (
|
||||
"auth_user_api_key_id": a.UserAPIKeyID,
|
||||
"membership_id": a.MembershipID,
|
||||
"role": a.Role,
|
||||
"organization_id": a.OrganizationID,
|
||||
"created_at": a.CreatedAt,
|
||||
"updated_at": a.UpdatedAt,
|
||||
}
|
||||
@@ -127,6 +129,133 @@ ORDER BY akm.created_at DESC
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadRoleByAPIKeyAndEntityID loads an API key's role by querying any entity to extract its organization_id
|
||||
func (a *UserAPIKeyMembership) LoadRoleByAPIKeyAndEntityID(
|
||||
ctx context.Context,
|
||||
conn pg.Conn,
|
||||
scope Scoper,
|
||||
apiKeyID gid.GID,
|
||||
entityID gid.GID,
|
||||
) error {
|
||||
entityType := entityID.EntityType()
|
||||
|
||||
// For organization, the entity ID is the organization ID
|
||||
if entityType == OrganizationEntityType {
|
||||
return a.LoadByAPIKeyIDAndOrganizationID(ctx, conn, scope, apiKeyID, entityID)
|
||||
}
|
||||
|
||||
tableName, ok := EntityTable(entityType)
|
||||
if !ok {
|
||||
return fmt.Errorf("unsupported entity type for API key role lookup: %d", entityType)
|
||||
}
|
||||
|
||||
query := fmt.Sprintf(`
|
||||
SELECT
|
||||
akm.id,
|
||||
akm.auth_user_api_key_id,
|
||||
akm.membership_id,
|
||||
akm.role,
|
||||
akm.created_at,
|
||||
akm.updated_at
|
||||
FROM
|
||||
authz_api_keys_memberships akm
|
||||
INNER JOIN authz_memberships m ON m.id = akm.membership_id
|
||||
INNER JOIN %s e ON e.id = @entity_id
|
||||
WHERE
|
||||
%s
|
||||
AND akm.auth_user_api_key_id = @api_key_id
|
||||
AND m.organization_id = e.organization_id
|
||||
LIMIT 1;
|
||||
`, tableName, scope.SQLFragment())
|
||||
|
||||
args := pgx.NamedArgs{
|
||||
"api_key_id": apiKeyID,
|
||||
"entity_id": entityID,
|
||||
}
|
||||
maps.Copy(args, scope.SQLArguments())
|
||||
|
||||
rows, err := conn.Query(ctx, query, args)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot query API key membership by entity: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
if !rows.Next() {
|
||||
return fmt.Errorf("API key membership not found for key %s and entity %s", apiKeyID, entityID)
|
||||
}
|
||||
|
||||
var membership UserAPIKeyMembership
|
||||
err = rows.Scan(
|
||||
&membership.ID,
|
||||
&membership.UserAPIKeyID,
|
||||
&membership.MembershipID,
|
||||
&membership.Role,
|
||||
&membership.CreatedAt,
|
||||
&membership.UpdatedAt,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot scan API key membership: %w", err)
|
||||
}
|
||||
|
||||
*a = membership
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *UserAPIKeyMembership) LoadByAPIKeyIDAndOrganizationID(
|
||||
ctx context.Context,
|
||||
conn pg.Conn,
|
||||
scope Scoper,
|
||||
apiKeyID gid.GID,
|
||||
organizationID gid.GID,
|
||||
) error {
|
||||
q := `
|
||||
SELECT
|
||||
akm.id,
|
||||
akm.auth_user_api_key_id,
|
||||
akm.membership_id,
|
||||
akm.role,
|
||||
akm.created_at,
|
||||
akm.updated_at,
|
||||
m.organization_id,
|
||||
o.name as organization_name
|
||||
FROM
|
||||
authz_api_keys_memberships akm
|
||||
JOIN
|
||||
authz_memberships m ON akm.membership_id = m.id
|
||||
JOIN
|
||||
organizations o ON m.organization_id = o.id
|
||||
WHERE
|
||||
akm.auth_user_api_key_id = @api_key_id
|
||||
AND m.organization_id = @organization_id
|
||||
AND m.%s
|
||||
`
|
||||
|
||||
q = fmt.Sprintf(q, scope.SQLFragment())
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"api_key_id": apiKeyID,
|
||||
"organization_id": organizationID,
|
||||
}
|
||||
maps.Copy(args, scope.SQLArguments())
|
||||
|
||||
rows, err := conn.Query(ctx, q, args)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot query user api key membership: %w", err)
|
||||
}
|
||||
|
||||
membership, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[UserAPIKeyMembership])
|
||||
if err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
return fmt.Errorf("API key does not have access to organization")
|
||||
}
|
||||
return fmt.Errorf("cannot collect user api key membership: %w", err)
|
||||
}
|
||||
|
||||
*a = membership
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *UserAPIKeyMembership) Delete(
|
||||
ctx context.Context,
|
||||
conn pg.Conn,
|
||||
@@ -155,6 +284,56 @@ WHERE
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *UserAPIKeyMemberships) LoadByMembershipID(
|
||||
ctx context.Context,
|
||||
conn pg.Conn,
|
||||
scope Scoper,
|
||||
membershipID gid.GID,
|
||||
) error {
|
||||
q := `
|
||||
SELECT
|
||||
akm.id,
|
||||
akm.auth_user_api_key_id,
|
||||
akm.membership_id,
|
||||
akm.role,
|
||||
akm.created_at,
|
||||
akm.updated_at,
|
||||
m.organization_id,
|
||||
o.name as organization_name
|
||||
FROM
|
||||
authz_api_keys_memberships akm
|
||||
JOIN
|
||||
authz_memberships m ON akm.membership_id = m.id
|
||||
JOIN
|
||||
organizations o ON m.organization_id = o.id
|
||||
WHERE
|
||||
akm.membership_id = @membership_id
|
||||
AND m.%s
|
||||
ORDER BY akm.created_at DESC
|
||||
`
|
||||
|
||||
q = fmt.Sprintf(q, scope.SQLFragment())
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"membership_id": membershipID,
|
||||
}
|
||||
maps.Copy(args, scope.SQLArguments())
|
||||
|
||||
rows, err := conn.Query(ctx, q, args)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot query user api key memberships by membership id: %w", err)
|
||||
}
|
||||
|
||||
memberships, err := pgx.CollectRows(rows, pgx.RowToAddrOfStructByName[UserAPIKeyMembership])
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot collect user api key memberships: %w", err)
|
||||
}
|
||||
|
||||
*a = memberships
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeleteAllUserAPIKeyMembershipsByUserAPIKeyID(
|
||||
ctx context.Context,
|
||||
conn pg.Conn,
|
||||
|
||||
@@ -46,6 +46,7 @@ func (av AssetVendors) Merge(
|
||||
conn pg.Conn,
|
||||
scope Scoper,
|
||||
assetID gid.GID,
|
||||
organizationID gid.GID,
|
||||
vendorIDs []gid.GID,
|
||||
) error {
|
||||
q := `
|
||||
@@ -54,6 +55,7 @@ WITH vendor_ids AS (
|
||||
unnest(@vendor_ids::text[]) AS vendor_id,
|
||||
@tenant_id AS tenant_id,
|
||||
@asset_id AS asset_id,
|
||||
@organization_id AS organization_id,
|
||||
@created_at::timestamptz AS created_at
|
||||
)
|
||||
MERGE INTO asset_vendors AS tgt
|
||||
@@ -62,18 +64,19 @@ ON tgt.tenant_id = src.tenant_id
|
||||
AND tgt.asset_id = src.asset_id
|
||||
AND tgt.vendor_id = src.vendor_id
|
||||
WHEN NOT MATCHED
|
||||
THEN INSERT (tenant_id, asset_id, vendor_id, created_at)
|
||||
VALUES (src.tenant_id, src.asset_id, src.vendor_id, src.created_at)
|
||||
THEN INSERT (tenant_id, asset_id, vendor_id, organization_id, created_at)
|
||||
VALUES (src.tenant_id, src.asset_id, src.vendor_id, src.organization_id, src.created_at)
|
||||
WHEN NOT MATCHED BY SOURCE
|
||||
AND tgt.tenant_id = @tenant_id AND tgt.asset_id = @asset_id
|
||||
THEN DELETE
|
||||
`
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"asset_id": assetID,
|
||||
"created_at": time.Now(),
|
||||
"vendor_ids": vendorIDs,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"asset_id": assetID,
|
||||
"organization_id": organizationID,
|
||||
"created_at": time.Now(),
|
||||
"vendor_ids": vendorIDs,
|
||||
}
|
||||
|
||||
_, err := conn.Exec(ctx, q, args)
|
||||
@@ -89,26 +92,29 @@ func (av AssetVendors) Insert(
|
||||
conn pg.Conn,
|
||||
scope Scoper,
|
||||
assetID gid.GID,
|
||||
organizationID gid.GID,
|
||||
vendorIDs []gid.GID,
|
||||
) error {
|
||||
q := `
|
||||
WITH vendor_ids AS (
|
||||
SELECT unnest(@vendor_ids::text[]) AS vendor_id
|
||||
)
|
||||
INSERT INTO asset_vendors (tenant_id, asset_id, vendor_id, created_at)
|
||||
INSERT INTO asset_vendors (tenant_id, asset_id, vendor_id, organization_id, created_at)
|
||||
SELECT
|
||||
@tenant_id AS tenant_id,
|
||||
@asset_id AS asset_id,
|
||||
vendor_id,
|
||||
@organization_id AS organization_id,
|
||||
@created_at AS created_at
|
||||
FROM vendor_ids
|
||||
`
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"asset_id": assetID,
|
||||
"created_at": time.Now(),
|
||||
"vendor_ids": vendorIDs,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"asset_id": assetID,
|
||||
"organization_id": organizationID,
|
||||
"created_at": time.Now(),
|
||||
"vendor_ids": vendorIDs,
|
||||
}
|
||||
|
||||
_, err := conn.Exec(ctx, q, args)
|
||||
|
||||
@@ -31,6 +31,7 @@ import (
|
||||
type (
|
||||
Control struct {
|
||||
ID gid.GID `db:"id"`
|
||||
OrganizationID gid.GID `db:"organization_id"`
|
||||
SectionTitle string `db:"section_title"`
|
||||
FrameworkID gid.GID `db:"framework_id"`
|
||||
Name string `db:"name"`
|
||||
@@ -127,6 +128,7 @@ WITH ctrl AS (
|
||||
c.id,
|
||||
c.section_title,
|
||||
c.framework_id,
|
||||
c.organization_id,
|
||||
c.tenant_id,
|
||||
c.name,
|
||||
c.description,
|
||||
@@ -146,6 +148,7 @@ SELECT
|
||||
id,
|
||||
section_title,
|
||||
framework_id,
|
||||
organization_id,
|
||||
name,
|
||||
description,
|
||||
status,
|
||||
@@ -236,6 +239,7 @@ WITH ctrl AS (
|
||||
c.id,
|
||||
c.section_title,
|
||||
c.framework_id,
|
||||
c.organization_id,
|
||||
c.tenant_id,
|
||||
c.name,
|
||||
c.description,
|
||||
@@ -255,6 +259,7 @@ SELECT
|
||||
id,
|
||||
section_title,
|
||||
framework_id,
|
||||
organization_id,
|
||||
name,
|
||||
description,
|
||||
status,
|
||||
@@ -351,6 +356,7 @@ WITH ctrl AS (
|
||||
c.id,
|
||||
c.section_title,
|
||||
c.framework_id,
|
||||
c.organization_id,
|
||||
c.tenant_id,
|
||||
c.name,
|
||||
c.description,
|
||||
@@ -376,6 +382,7 @@ SELECT
|
||||
id,
|
||||
section_title,
|
||||
framework_id,
|
||||
organization_id,
|
||||
name,
|
||||
description,
|
||||
status,
|
||||
@@ -455,6 +462,7 @@ SELECT
|
||||
id,
|
||||
section_title,
|
||||
framework_id,
|
||||
organization_id,
|
||||
name,
|
||||
description,
|
||||
status,
|
||||
@@ -548,6 +556,7 @@ WITH ctrl AS (
|
||||
c.id,
|
||||
c.section_title,
|
||||
c.framework_id,
|
||||
c.organization_id,
|
||||
c.tenant_id,
|
||||
c.name,
|
||||
c.description,
|
||||
@@ -567,6 +576,7 @@ SELECT
|
||||
id,
|
||||
section_title,
|
||||
framework_id,
|
||||
organization_id,
|
||||
name,
|
||||
description,
|
||||
status,
|
||||
@@ -613,6 +623,7 @@ SELECT
|
||||
id,
|
||||
section_title,
|
||||
framework_id,
|
||||
organization_id,
|
||||
name,
|
||||
description,
|
||||
status,
|
||||
@@ -661,6 +672,7 @@ SELECT
|
||||
id,
|
||||
section_title,
|
||||
framework_id,
|
||||
organization_id,
|
||||
name,
|
||||
description,
|
||||
status,
|
||||
@@ -707,6 +719,7 @@ INSERT INTO
|
||||
controls (
|
||||
tenant_id,
|
||||
id,
|
||||
organization_id,
|
||||
framework_id,
|
||||
section_title,
|
||||
name,
|
||||
@@ -719,6 +732,7 @@ INSERT INTO
|
||||
VALUES (
|
||||
@tenant_id,
|
||||
@control_id,
|
||||
@organization_id,
|
||||
@framework_id,
|
||||
@section_title,
|
||||
@name,
|
||||
@@ -733,6 +747,7 @@ VALUES (
|
||||
args := pgx.StrictNamedArgs{
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"control_id": c.ID,
|
||||
"organization_id": c.OrganizationID,
|
||||
"framework_id": c.FrameworkID,
|
||||
"section_title": c.SectionTitle,
|
||||
"name": c.Name,
|
||||
@@ -884,6 +899,7 @@ WITH ctrl AS (
|
||||
c.id,
|
||||
c.section_title,
|
||||
c.framework_id,
|
||||
c.organization_id,
|
||||
c.tenant_id,
|
||||
c.name,
|
||||
c.description,
|
||||
@@ -903,6 +919,7 @@ SELECT
|
||||
id,
|
||||
section_title,
|
||||
framework_id,
|
||||
organization_id,
|
||||
name,
|
||||
description,
|
||||
status,
|
||||
@@ -994,6 +1011,7 @@ WITH ctrl AS (
|
||||
c.id,
|
||||
c.section_title,
|
||||
c.framework_id,
|
||||
c.organization_id,
|
||||
c.tenant_id,
|
||||
c.name,
|
||||
c.description,
|
||||
@@ -1013,6 +1031,7 @@ SELECT
|
||||
id,
|
||||
section_title,
|
||||
framework_id,
|
||||
organization_id,
|
||||
name,
|
||||
description,
|
||||
status,
|
||||
|
||||
@@ -27,9 +27,10 @@ import (
|
||||
|
||||
type (
|
||||
ControlAudit struct {
|
||||
ControlID gid.GID `db:"control_id"`
|
||||
AuditID gid.GID `db:"audit_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
ControlID gid.GID `db:"control_id"`
|
||||
AuditID gid.GID `db:"audit_id"`
|
||||
OrganizationID gid.GID `db:"organization_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
}
|
||||
|
||||
ControlAudits []*ControlAudit
|
||||
@@ -45,12 +46,14 @@ INSERT INTO
|
||||
controls_audits (
|
||||
control_id,
|
||||
audit_id,
|
||||
organization_id,
|
||||
tenant_id,
|
||||
created_at
|
||||
)
|
||||
VALUES (
|
||||
@control_id,
|
||||
@audit_id,
|
||||
@organization_id,
|
||||
@tenant_id,
|
||||
@created_at
|
||||
)
|
||||
@@ -58,10 +61,11 @@ ON CONFLICT (control_id, audit_id) DO NOTHING;
|
||||
`
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"control_id": ca.ControlID,
|
||||
"audit_id": ca.AuditID,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"created_at": ca.CreatedAt,
|
||||
"control_id": ca.ControlID,
|
||||
"audit_id": ca.AuditID,
|
||||
"organization_id": ca.OrganizationID,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"created_at": ca.CreatedAt,
|
||||
}
|
||||
_, err := conn.Exec(ctx, q, args)
|
||||
return err
|
||||
|
||||
@@ -29,10 +29,11 @@ import (
|
||||
|
||||
type (
|
||||
ControlDocument struct {
|
||||
ControlID gid.GID `db:"control_id"`
|
||||
DocumentID gid.GID `db:"document_id"`
|
||||
TenantID gid.TenantID `db:"tenant_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
ControlID gid.GID `db:"control_id"`
|
||||
DocumentID gid.GID `db:"document_id"`
|
||||
OrganizationID gid.GID `db:"organization_id"`
|
||||
TenantID gid.TenantID `db:"tenant_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
}
|
||||
|
||||
ControlDocuments []*ControlDocument
|
||||
@@ -57,22 +58,25 @@ INSERT INTO
|
||||
controls_documents (
|
||||
control_id,
|
||||
document_id,
|
||||
organization_id,
|
||||
tenant_id,
|
||||
created_at
|
||||
)
|
||||
VALUES (
|
||||
@control_id,
|
||||
@document_id,
|
||||
@organization_id,
|
||||
@tenant_id,
|
||||
@created_at
|
||||
);
|
||||
`
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"control_id": cp.ControlID,
|
||||
"document_id": cp.DocumentID,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"created_at": cp.CreatedAt,
|
||||
"control_id": cp.ControlID,
|
||||
"document_id": cp.DocumentID,
|
||||
"organization_id": cp.OrganizationID,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"created_at": cp.CreatedAt,
|
||||
}
|
||||
_, err := conn.Exec(ctx, q, args)
|
||||
|
||||
|
||||
@@ -20,17 +20,18 @@ import (
|
||||
"maps"
|
||||
"time"
|
||||
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"go.gearno.de/kit/pg"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
)
|
||||
|
||||
type (
|
||||
ControlMeasure struct {
|
||||
ControlID gid.GID `db:"control_id"`
|
||||
MeasureID gid.GID `db:"measure_id"`
|
||||
TenantID gid.TenantID `db:"tenant_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
ControlID gid.GID `db:"control_id"`
|
||||
MeasureID gid.GID `db:"measure_id"`
|
||||
OrganizationID gid.GID `db:"organization_id"`
|
||||
TenantID gid.TenantID `db:"tenant_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
}
|
||||
|
||||
ControlMeasures []*ControlMeasure
|
||||
@@ -46,12 +47,14 @@ INSERT INTO
|
||||
controls_measures (
|
||||
control_id,
|
||||
measure_id,
|
||||
organization_id,
|
||||
tenant_id,
|
||||
created_at
|
||||
)
|
||||
VALUES (
|
||||
@control_id,
|
||||
@measure_id,
|
||||
@organization_id,
|
||||
@tenant_id,
|
||||
@created_at
|
||||
)
|
||||
@@ -59,10 +62,11 @@ ON CONFLICT (control_id, measure_id) DO NOTHING;
|
||||
`
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"control_id": cm.ControlID,
|
||||
"measure_id": cm.MeasureID,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"created_at": cm.CreatedAt,
|
||||
"control_id": cm.ControlID,
|
||||
"measure_id": cm.MeasureID,
|
||||
"organization_id": cm.OrganizationID,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"created_at": cm.CreatedAt,
|
||||
}
|
||||
_, err := conn.Exec(ctx, q, args)
|
||||
return err
|
||||
|
||||
@@ -27,9 +27,10 @@ import (
|
||||
|
||||
type (
|
||||
ControlSnapshot struct {
|
||||
ControlID gid.GID `db:"control_id"`
|
||||
SnapshotID gid.GID `db:"snapshot_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
ControlID gid.GID `db:"control_id"`
|
||||
SnapshotID gid.GID `db:"snapshot_id"`
|
||||
OrganizationID gid.GID `db:"organization_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
}
|
||||
|
||||
ControlSnapshots []*ControlSnapshot
|
||||
@@ -45,12 +46,14 @@ INSERT INTO
|
||||
controls_snapshots (
|
||||
control_id,
|
||||
snapshot_id,
|
||||
organization_id,
|
||||
tenant_id,
|
||||
created_at
|
||||
)
|
||||
VALUES (
|
||||
@control_id,
|
||||
@snapshot_id,
|
||||
@organization_id,
|
||||
@tenant_id,
|
||||
@created_at
|
||||
)
|
||||
@@ -58,10 +61,11 @@ ON CONFLICT (control_id, snapshot_id) DO NOTHING;
|
||||
`
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"control_id": cs.ControlID,
|
||||
"snapshot_id": cs.SnapshotID,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"created_at": cs.CreatedAt,
|
||||
"control_id": cs.ControlID,
|
||||
"snapshot_id": cs.SnapshotID,
|
||||
"organization_id": cs.OrganizationID,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"created_at": cs.CreatedAt,
|
||||
}
|
||||
_, err := conn.Exec(ctx, q, args)
|
||||
return err
|
||||
|
||||
@@ -22,17 +22,18 @@ import (
|
||||
"maps"
|
||||
"time"
|
||||
|
||||
"go.probo.inc/probo/pkg/crypto/cipher"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgconn"
|
||||
"go.gearno.de/kit/pg"
|
||||
"go.probo.inc/probo/pkg/crypto/cipher"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
)
|
||||
|
||||
type (
|
||||
CustomDomain struct {
|
||||
ID gid.GID `db:"id"`
|
||||
OrganizationID gid.GID `db:"organization_id"`
|
||||
Domain string `db:"domain"`
|
||||
HTTPChallengeToken *string `db:"http_challenge_token"`
|
||||
HTTPChallengeKeyAuth *string `db:"http_challenge_key_auth"`
|
||||
@@ -159,6 +160,7 @@ func (cd *CustomDomain) LoadByID(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
domain,
|
||||
http_challenge_token,
|
||||
http_challenge_key_auth,
|
||||
@@ -211,6 +213,7 @@ func (cd *CustomDomain) LoadByIDForUpdate(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
domain,
|
||||
http_challenge_token,
|
||||
http_challenge_key_auth,
|
||||
@@ -263,6 +266,7 @@ func (cd *CustomDomain) LoadByDomain(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
domain,
|
||||
http_challenge_token,
|
||||
http_challenge_key_auth,
|
||||
@@ -320,6 +324,7 @@ func (cd *CustomDomain) Insert(
|
||||
INSERT INTO custom_domains (
|
||||
id,
|
||||
tenant_id,
|
||||
organization_id,
|
||||
domain,
|
||||
http_challenge_token,
|
||||
http_challenge_key_auth,
|
||||
@@ -337,6 +342,7 @@ INSERT INTO custom_domains (
|
||||
) VALUES (
|
||||
@id,
|
||||
@tenant_id,
|
||||
@organization_id,
|
||||
@domain,
|
||||
@http_challenge_token,
|
||||
@http_challenge_key_auth,
|
||||
@@ -357,6 +363,7 @@ INSERT INTO custom_domains (
|
||||
args := pgx.NamedArgs{
|
||||
"id": cd.ID,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"organization_id": cd.OrganizationID,
|
||||
"domain": cd.Domain,
|
||||
"http_challenge_token": cd.HTTPChallengeToken,
|
||||
"http_challenge_key_auth": cd.HTTPChallengeKeyAuth,
|
||||
@@ -487,6 +494,7 @@ func (cd *CustomDomain) LoadByHTTPChallengeToken(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
domain,
|
||||
http_challenge_token,
|
||||
http_challenge_key_auth,
|
||||
@@ -537,6 +545,7 @@ func (domains *CustomDomains) ListDomainsForRenewal(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
domain,
|
||||
http_challenge_token,
|
||||
http_challenge_key_auth,
|
||||
@@ -589,6 +598,7 @@ func (domains *CustomDomains) ListDomainsWithPendingHTTPChallenges(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
domain,
|
||||
http_challenge_token,
|
||||
http_challenge_key_auth,
|
||||
@@ -644,6 +654,7 @@ func (domains *CustomDomains) LoadActiveCertificates(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
domain,
|
||||
http_challenge_token,
|
||||
http_challenge_key_auth,
|
||||
@@ -693,6 +704,7 @@ func (domains *CustomDomains) ListStaleProvisioningDomains(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
domain,
|
||||
http_challenge_token,
|
||||
http_challenge_key_auth,
|
||||
|
||||
@@ -41,6 +41,7 @@ func (dv DatumVendors) Merge(
|
||||
conn pg.Conn,
|
||||
scope Scoper,
|
||||
datumID gid.GID,
|
||||
organizationID gid.GID,
|
||||
vendorIDs []gid.GID,
|
||||
) error {
|
||||
q := `
|
||||
@@ -49,6 +50,7 @@ WITH vendor_ids AS (
|
||||
unnest(@vendor_ids::text[]) AS vendor_id,
|
||||
@tenant_id AS tenant_id,
|
||||
@datum_id AS datum_id,
|
||||
@organization_id AS organization_id,
|
||||
@created_at::timestamptz AS created_at
|
||||
)
|
||||
MERGE INTO data_vendors AS tgt
|
||||
@@ -57,18 +59,19 @@ ON tgt.tenant_id = src.tenant_id
|
||||
AND tgt.datum_id = src.datum_id
|
||||
AND tgt.vendor_id = src.vendor_id
|
||||
WHEN NOT MATCHED THEN
|
||||
INSERT (tenant_id, datum_id, vendor_id, created_at)
|
||||
VALUES (src.tenant_id, src.datum_id, src.vendor_id, src.created_at)
|
||||
INSERT (tenant_id, datum_id, vendor_id, organization_id, created_at)
|
||||
VALUES (src.tenant_id, src.datum_id, src.vendor_id, src.organization_id, src.created_at)
|
||||
WHEN NOT MATCHED BY SOURCE
|
||||
AND tgt.tenant_id = @tenant_id AND tgt.datum_id = @datum_id
|
||||
THEN DELETE
|
||||
`
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"datum_id": datumID,
|
||||
"created_at": time.Now(),
|
||||
"vendor_ids": vendorIDs,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"datum_id": datumID,
|
||||
"organization_id": organizationID,
|
||||
"created_at": time.Now(),
|
||||
"vendor_ids": vendorIDs,
|
||||
}
|
||||
|
||||
_, err := conn.Exec(ctx, q, args)
|
||||
@@ -84,26 +87,29 @@ func (dv DatumVendors) Insert(
|
||||
conn pg.Conn,
|
||||
scope Scoper,
|
||||
datumID gid.GID,
|
||||
organizationID gid.GID,
|
||||
vendorIDs []gid.GID,
|
||||
) error {
|
||||
q := `
|
||||
WITH vendor_ids AS (
|
||||
SELECT unnest(@vendor_ids::text[]) AS vendor_id
|
||||
)
|
||||
INSERT INTO data_vendors (tenant_id, datum_id, vendor_id, created_at)
|
||||
INSERT INTO data_vendors (tenant_id, datum_id, vendor_id, organization_id, created_at)
|
||||
SELECT
|
||||
@tenant_id::text AS tenant_id,
|
||||
@datum_id::text AS datum_id,
|
||||
vendor_id,
|
||||
@organization_id::text AS organization_id,
|
||||
@created_at::timestamptz AS created_at
|
||||
FROM vendor_ids
|
||||
`
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"datum_id": datumID,
|
||||
"created_at": time.Now(),
|
||||
"vendor_ids": vendorIDs,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"datum_id": datumID,
|
||||
"organization_id": organizationID,
|
||||
"created_at": time.Now(),
|
||||
"vendor_ids": vendorIDs,
|
||||
}
|
||||
|
||||
_, err := conn.Exec(ctx, q, args)
|
||||
|
||||
@@ -21,16 +21,17 @@ import (
|
||||
"maps"
|
||||
"time"
|
||||
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgconn"
|
||||
"go.gearno.de/kit/pg"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
)
|
||||
|
||||
type (
|
||||
DocumentVersion struct {
|
||||
ID gid.GID `db:"id"`
|
||||
OrganizationID gid.GID `db:"organization_id"`
|
||||
DocumentID gid.GID `db:"document_id"`
|
||||
Title string `db:"title"`
|
||||
OwnerID gid.GID `db:"owner_id"`
|
||||
@@ -81,6 +82,7 @@ func (p *DocumentVersions) LoadByDocumentID(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
document_id,
|
||||
title,
|
||||
owner_id,
|
||||
@@ -140,6 +142,7 @@ func (p *DocumentVersion) LoadByID(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
document_id,
|
||||
title,
|
||||
owner_id,
|
||||
@@ -190,6 +193,7 @@ func (p DocumentVersion) Insert(
|
||||
INSERT INTO document_versions (
|
||||
tenant_id,
|
||||
id,
|
||||
organization_id,
|
||||
document_id,
|
||||
title,
|
||||
owner_id,
|
||||
@@ -204,6 +208,7 @@ INSERT INTO document_versions (
|
||||
VALUES (
|
||||
@tenant_id,
|
||||
@id,
|
||||
@organization_id,
|
||||
@document_id,
|
||||
@title,
|
||||
@owner_id,
|
||||
@@ -217,18 +222,19 @@ VALUES (
|
||||
)
|
||||
`
|
||||
args := pgx.StrictNamedArgs{
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"id": p.ID,
|
||||
"document_id": p.DocumentID,
|
||||
"title": p.Title,
|
||||
"owner_id": p.OwnerID,
|
||||
"version_number": p.VersionNumber,
|
||||
"classification": p.Classification,
|
||||
"content": p.Content,
|
||||
"changelog": p.Changelog,
|
||||
"status": p.Status,
|
||||
"created_at": p.CreatedAt,
|
||||
"updated_at": p.UpdatedAt,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"id": p.ID,
|
||||
"organization_id": p.OrganizationID,
|
||||
"document_id": p.DocumentID,
|
||||
"title": p.Title,
|
||||
"owner_id": p.OwnerID,
|
||||
"version_number": p.VersionNumber,
|
||||
"classification": p.Classification,
|
||||
"content": p.Content,
|
||||
"changelog": p.Changelog,
|
||||
"status": p.Status,
|
||||
"created_at": p.CreatedAt,
|
||||
"updated_at": p.UpdatedAt,
|
||||
}
|
||||
|
||||
_, err := conn.Exec(ctx, q, args)
|
||||
@@ -264,6 +270,7 @@ func (p *DocumentVersion) LoadByDocumentIDAndVersionNumber(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
document_id,
|
||||
title,
|
||||
owner_id,
|
||||
@@ -316,6 +323,7 @@ func (p *DocumentVersion) LoadLatestVersion(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
document_id,
|
||||
title,
|
||||
owner_id,
|
||||
@@ -366,6 +374,7 @@ func (p *DocumentVersion) LoadLatestPublishedVersion(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
document_id,
|
||||
title,
|
||||
owner_id,
|
||||
|
||||
@@ -21,16 +21,17 @@ import (
|
||||
"maps"
|
||||
"time"
|
||||
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgconn"
|
||||
"go.gearno.de/kit/pg"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
)
|
||||
|
||||
type (
|
||||
DocumentVersionSignature struct {
|
||||
ID gid.GID `json:"id"`
|
||||
OrganizationID gid.GID `json:"-"`
|
||||
DocumentVersionID gid.GID `json:"document_version_id"`
|
||||
State DocumentVersionSignatureState `json:"state"`
|
||||
SignedBy gid.GID `json:"signed_by"`
|
||||
@@ -87,6 +88,7 @@ func (pvs *DocumentVersionSignature) LoadByDocumentVersionIDAndSignatory(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
document_version_id,
|
||||
state,
|
||||
signed_by,
|
||||
@@ -132,6 +134,7 @@ func (pvs *DocumentVersionSignature) LoadByID(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
document_version_id,
|
||||
state,
|
||||
signed_by,
|
||||
@@ -175,6 +178,7 @@ func (pvs DocumentVersionSignature) Insert(
|
||||
INSERT INTO document_version_signatures (
|
||||
id,
|
||||
tenant_id,
|
||||
organization_id,
|
||||
document_version_id,
|
||||
state,
|
||||
signed_by,
|
||||
@@ -185,6 +189,7 @@ INSERT INTO document_version_signatures (
|
||||
) VALUES (
|
||||
@id,
|
||||
@tenant_id,
|
||||
@organization_id,
|
||||
@document_version_id,
|
||||
@state,
|
||||
@signed_by,
|
||||
@@ -198,6 +203,7 @@ INSERT INTO document_version_signatures (
|
||||
args := pgx.StrictNamedArgs{
|
||||
"id": pvs.ID,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"organization_id": pvs.OrganizationID,
|
||||
"document_version_id": pvs.DocumentVersionID,
|
||||
"state": pvs.State,
|
||||
"signed_by": pvs.SignedBy,
|
||||
@@ -234,6 +240,7 @@ func (pvss *DocumentVersionSignatures) LoadByDocumentVersionID(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
document_version_id,
|
||||
state,
|
||||
signed_by,
|
||||
@@ -346,6 +353,7 @@ func (pvss *DocumentVersionSignaturesWithPeople) LoadByDocumentVersionIDWithPeop
|
||||
WITH sigs AS (
|
||||
SELECT
|
||||
dvs.id,
|
||||
dvs.organization_id,
|
||||
dvs.tenant_id,
|
||||
dvs.document_version_id,
|
||||
dvs.state,
|
||||
@@ -367,6 +375,7 @@ WITH sigs AS (
|
||||
)
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
document_version_id,
|
||||
state,
|
||||
signed_by,
|
||||
|
||||
@@ -20,9 +20,9 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"go.gearno.de/kit/pg"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
@@ -68,3 +68,211 @@ const (
|
||||
UserAPIKeyMembershipEntityType uint16 = 44
|
||||
MeetingEntityType uint16 = 45
|
||||
)
|
||||
|
||||
type EntityInfo struct {
|
||||
Model string
|
||||
Table string
|
||||
}
|
||||
|
||||
var entityRegistry = map[uint16]EntityInfo{
|
||||
OrganizationEntityType: {
|
||||
Model: "Organization",
|
||||
Table: "organizations",
|
||||
},
|
||||
FrameworkEntityType: {
|
||||
Model: "Framework",
|
||||
Table: "frameworks",
|
||||
},
|
||||
MeasureEntityType: {
|
||||
Model: "Measure",
|
||||
Table: "measures",
|
||||
},
|
||||
TaskEntityType: {
|
||||
Model: "Task",
|
||||
Table: "tasks",
|
||||
},
|
||||
EvidenceEntityType: {
|
||||
Model: "Evidence",
|
||||
Table: "evidences",
|
||||
},
|
||||
ConnectorEntityType: {
|
||||
Model: "Connector",
|
||||
Table: "connectors",
|
||||
},
|
||||
VendorRiskAssessmentEntityType: {
|
||||
Model: "VendorRiskAssessment",
|
||||
Table: "vendor_risk_assessments",
|
||||
},
|
||||
VendorEntityType: {
|
||||
Model: "Vendor",
|
||||
Table: "vendors",
|
||||
},
|
||||
PeopleEntityType: {
|
||||
Model: "People",
|
||||
Table: "peoples",
|
||||
},
|
||||
VendorComplianceReportEntityType: {
|
||||
Model: "VendorComplianceReport",
|
||||
Table: "vendor_compliance_reports",
|
||||
},
|
||||
DocumentEntityType: {
|
||||
Model: "Document",
|
||||
Table: "documents",
|
||||
},
|
||||
UserEntityType: {
|
||||
Model: "User",
|
||||
Table: "auth_users",
|
||||
},
|
||||
SessionEntityType: {
|
||||
Model: "Session",
|
||||
Table: "auth_sessions",
|
||||
},
|
||||
EmailEntityType: {
|
||||
Model: "Email",
|
||||
Table: "auth_emails",
|
||||
},
|
||||
ControlEntityType: {
|
||||
Model: "Control",
|
||||
Table: "controls",
|
||||
},
|
||||
RiskEntityType: {
|
||||
Model: "Risk",
|
||||
Table: "risks",
|
||||
},
|
||||
DocumentVersionEntityType: {
|
||||
Model: "DocumentVersion",
|
||||
Table: "document_versions",
|
||||
},
|
||||
DocumentVersionSignatureEntityType: {
|
||||
Model: "DocumentVersionSignature",
|
||||
Table: "document_version_signatures",
|
||||
},
|
||||
AssetEntityType: {
|
||||
Model: "Asset",
|
||||
Table: "assets",
|
||||
},
|
||||
DatumEntityType: {
|
||||
Model: "Datum",
|
||||
Table: "data",
|
||||
},
|
||||
AuditEntityType: {
|
||||
Model: "Audit",
|
||||
Table: "audits",
|
||||
},
|
||||
ReportEntityType: {
|
||||
Model: "Report",
|
||||
Table: "reports",
|
||||
},
|
||||
TrustCenterEntityType: {
|
||||
Model: "TrustCenter",
|
||||
Table: "trust_centers",
|
||||
},
|
||||
TrustCenterAccessEntityType: {
|
||||
Model: "TrustCenterAccess",
|
||||
Table: "trust_center_accesses",
|
||||
},
|
||||
VendorBusinessAssociateAgreementEntityType: {
|
||||
Model: "VendorBusinessAssociateAgreement",
|
||||
Table: "vendor_business_associate_agreements",
|
||||
},
|
||||
FileEntityType: {
|
||||
Model: "File",
|
||||
Table: "files",
|
||||
},
|
||||
VendorContactEntityType: {
|
||||
Model: "VendorContact",
|
||||
Table: "vendor_contacts",
|
||||
},
|
||||
VendorDataPrivacyAgreementEntityType: {
|
||||
Model: "VendorDataPrivacyAgreement",
|
||||
Table: "vendor_data_privacy_agreements",
|
||||
},
|
||||
NonconformityEntityType: {
|
||||
Model: "Nonconformity",
|
||||
Table: "nonconformities",
|
||||
},
|
||||
ObligationEntityType: {
|
||||
Model: "Obligation",
|
||||
Table: "obligations",
|
||||
},
|
||||
VendorServiceEntityType: {
|
||||
Model: "VendorService",
|
||||
Table: "vendor_services",
|
||||
},
|
||||
SnapshotEntityType: {
|
||||
Model: "Snapshot",
|
||||
Table: "snapshots",
|
||||
},
|
||||
ContinualImprovementEntityType: {
|
||||
Model: "ContinualImprovement",
|
||||
Table: "continual_improvements",
|
||||
},
|
||||
ProcessingActivityEntityType: {
|
||||
Model: "ProcessingActivity",
|
||||
Table: "processing_activities",
|
||||
},
|
||||
ExportJobEntityType: {
|
||||
Model: "ExportJob",
|
||||
Table: "export_jobs",
|
||||
},
|
||||
TrustCenterReferenceEntityType: {
|
||||
Model: "TrustCenterReference",
|
||||
Table: "trust_center_references",
|
||||
},
|
||||
TrustCenterDocumentAccessEntityType: {
|
||||
Model: "",
|
||||
Table: "trust_center_document_accesses",
|
||||
},
|
||||
CustomDomainEntityType: {
|
||||
Model: "CustomDomain",
|
||||
Table: "custom_domains",
|
||||
},
|
||||
InvitationEntityType: {
|
||||
Model: "Invitation",
|
||||
Table: "authz_invitations",
|
||||
},
|
||||
MembershipEntityType: {
|
||||
Model: "Membership",
|
||||
Table: "authz_memberships",
|
||||
},
|
||||
SlackMessageEntityType: {
|
||||
Model: "SlackMessage",
|
||||
Table: "slack_messages",
|
||||
},
|
||||
TrustCenterFileEntityType: {
|
||||
Model: "TrustCenterFile",
|
||||
Table: "trust_center_files",
|
||||
},
|
||||
SAMLConfigurationEntityType: {
|
||||
Model: "SAMLConfiguration",
|
||||
Table: "auth_saml_configurations",
|
||||
},
|
||||
UserAPIKeyEntityType: {
|
||||
Model: "UserAPIKey",
|
||||
Table: "auth_user_api_keys",
|
||||
},
|
||||
UserAPIKeyMembershipEntityType: {
|
||||
Model: "UserAPIKeyMembership",
|
||||
Table: "authz_api_keys_memberships",
|
||||
},
|
||||
MeetingEntityType: {
|
||||
Model: "Meeting",
|
||||
Table: "meetings",
|
||||
},
|
||||
}
|
||||
|
||||
func EntityTable(entityType uint16) (string, bool) {
|
||||
info, ok := entityRegistry[entityType]
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
return info.Table, true
|
||||
}
|
||||
|
||||
func EntityModel(entityType uint16) (string, bool) {
|
||||
info, ok := entityRegistry[entityType]
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
return info.Model, true
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import (
|
||||
type (
|
||||
Evidence struct {
|
||||
ID gid.GID `db:"id"`
|
||||
OrganizationID gid.GID `db:"organization_id"`
|
||||
MeasureID gid.GID `db:"measure_id"`
|
||||
TaskID *gid.GID `db:"task_id"`
|
||||
State EvidenceState `db:"state"`
|
||||
@@ -141,6 +142,7 @@ INSERT INTO
|
||||
evidences (
|
||||
tenant_id,
|
||||
id,
|
||||
organization_id,
|
||||
measure_id,
|
||||
task_id,
|
||||
reference_id,
|
||||
@@ -155,6 +157,7 @@ INSERT INTO
|
||||
VALUES (
|
||||
@tenant_id,
|
||||
@evidence_id,
|
||||
@organization_id,
|
||||
@measure_id,
|
||||
@task_id,
|
||||
@reference_id,
|
||||
@@ -171,6 +174,7 @@ VALUES (
|
||||
args := pgx.StrictNamedArgs{
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"evidence_id": e.ID,
|
||||
"organization_id": e.OrganizationID,
|
||||
"measure_id": e.MeasureID,
|
||||
"task_id": e.TaskID,
|
||||
"reference_id": e.ReferenceID,
|
||||
@@ -208,6 +212,7 @@ func (e *Evidence) LoadByID(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
task_id,
|
||||
measure_id,
|
||||
reference_id,
|
||||
@@ -288,6 +293,7 @@ func (e *Evidences) LoadByMeasureID(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
measure_id,
|
||||
task_id,
|
||||
reference_id,
|
||||
@@ -369,6 +375,7 @@ func (e *Evidences) LoadByTaskID(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
measure_id,
|
||||
task_id,
|
||||
reference_id,
|
||||
|
||||
@@ -8,14 +8,15 @@ import (
|
||||
"maps"
|
||||
"time"
|
||||
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"go.gearno.de/kit/pg"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
)
|
||||
|
||||
type (
|
||||
ExportJob struct {
|
||||
ID gid.GID `db:"id"`
|
||||
OrganizationID gid.GID `db:"organization_id"`
|
||||
Type ExportJobType `db:"type"`
|
||||
Arguments json.RawMessage `db:"arguments"`
|
||||
Error *string `db:"error"`
|
||||
@@ -54,6 +55,7 @@ func (ej *ExportJob) Insert(
|
||||
q := `
|
||||
INSERT INTO export_jobs (
|
||||
id,
|
||||
organization_id,
|
||||
tenant_id,
|
||||
type,
|
||||
arguments,
|
||||
@@ -63,6 +65,7 @@ INSERT INTO export_jobs (
|
||||
created_at
|
||||
) VALUES (
|
||||
@id,
|
||||
@organization_id,
|
||||
@tenant_id,
|
||||
@type,
|
||||
@arguments,
|
||||
@@ -73,6 +76,7 @@ INSERT INTO export_jobs (
|
||||
)`
|
||||
args := pgx.StrictNamedArgs{
|
||||
"id": ej.ID,
|
||||
"organization_id": ej.OrganizationID,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"type": ej.Type,
|
||||
"arguments": ej.Arguments,
|
||||
@@ -126,6 +130,7 @@ func (ej *ExportJob) LoadByID(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
type,
|
||||
arguments,
|
||||
error,
|
||||
@@ -167,6 +172,7 @@ func (ej *ExportJob) LoadNextPendingForUpdateSkipLocked(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
type,
|
||||
arguments,
|
||||
error,
|
||||
|
||||
@@ -21,23 +21,24 @@ import (
|
||||
"maps"
|
||||
"time"
|
||||
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgconn"
|
||||
"go.gearno.de/kit/pg"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
)
|
||||
|
||||
type (
|
||||
File struct {
|
||||
ID gid.GID `db:"id"`
|
||||
BucketName string `db:"bucket_name"`
|
||||
MimeType string `db:"mime_type"`
|
||||
FileName string `db:"file_name"`
|
||||
FileKey string `db:"file_key"`
|
||||
FileSize int64 `db:"file_size"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
DeletedAt *time.Time `db:"deleted_at"`
|
||||
ID gid.GID `db:"id"`
|
||||
OrganizationID gid.GID `db:"organization_id"`
|
||||
BucketName string `db:"bucket_name"`
|
||||
MimeType string `db:"mime_type"`
|
||||
FileName string `db:"file_name"`
|
||||
FileKey string `db:"file_key"`
|
||||
FileSize int64 `db:"file_size"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
DeletedAt *time.Time `db:"deleted_at"`
|
||||
}
|
||||
|
||||
Files []*File
|
||||
@@ -68,6 +69,7 @@ func (f *File) LoadByID(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
bucket_name,
|
||||
mime_type,
|
||||
file_name,
|
||||
@@ -119,6 +121,7 @@ INSERT INTO
|
||||
files (
|
||||
id,
|
||||
tenant_id,
|
||||
organization_id,
|
||||
bucket_name,
|
||||
mime_type,
|
||||
file_name,
|
||||
@@ -131,6 +134,7 @@ INSERT INTO
|
||||
VALUES (
|
||||
@file_id,
|
||||
@tenant_id,
|
||||
@organization_id,
|
||||
@bucket_name,
|
||||
@mime_type,
|
||||
@file_name,
|
||||
@@ -143,16 +147,17 @@ VALUES (
|
||||
`
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"file_id": f.ID,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"bucket_name": f.BucketName,
|
||||
"mime_type": f.MimeType,
|
||||
"file_name": f.FileName,
|
||||
"file_key": f.FileKey,
|
||||
"file_size": f.FileSize,
|
||||
"created_at": f.CreatedAt,
|
||||
"updated_at": f.UpdatedAt,
|
||||
"deleted_at": f.DeletedAt,
|
||||
"file_id": f.ID,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"organization_id": f.OrganizationID,
|
||||
"bucket_name": f.BucketName,
|
||||
"mime_type": f.MimeType,
|
||||
"file_name": f.FileName,
|
||||
"file_key": f.FileKey,
|
||||
"file_size": f.FileSize,
|
||||
"created_at": f.CreatedAt,
|
||||
"updated_at": f.UpdatedAt,
|
||||
"deleted_at": f.DeletedAt,
|
||||
}
|
||||
_, err := conn.Exec(ctx, q, args)
|
||||
|
||||
|
||||
@@ -21,10 +21,10 @@ import (
|
||||
"maps"
|
||||
"time"
|
||||
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"go.gearno.de/kit/pg"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -33,7 +33,7 @@ type (
|
||||
OrganizationID gid.GID `db:"organization_id"`
|
||||
Email string `db:"email"`
|
||||
FullName string `db:"full_name"`
|
||||
Role Role `db:"role"`
|
||||
Role MembershipRole `db:"role"`
|
||||
Status InvitationStatus `db:"status"`
|
||||
ExpiresAt time.Time `db:"expires_at"`
|
||||
AcceptedAt *time.Time `db:"accepted_at"`
|
||||
@@ -43,11 +43,11 @@ type (
|
||||
Invitations []*Invitation
|
||||
|
||||
InvitationData struct {
|
||||
InvitationID gid.GID `json:"invitation_id"`
|
||||
OrganizationID gid.GID `json:"organization_id"`
|
||||
Email string `json:"email"`
|
||||
FullName string `json:"full_name"`
|
||||
Role Role `json:"role"`
|
||||
InvitationID gid.GID `json:"invitation_id"`
|
||||
OrganizationID gid.GID `json:"organization_id"`
|
||||
Email string `json:"email"`
|
||||
FullName string `json:"full_name"`
|
||||
Role MembershipRole `json:"role"`
|
||||
}
|
||||
|
||||
ErrInvitationNotFound struct {
|
||||
|
||||
@@ -19,20 +19,19 @@ import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Role string
|
||||
type MembershipRole string
|
||||
|
||||
const (
|
||||
RoleOwner Role = "OWNER"
|
||||
RoleAdmin Role = "ADMIN"
|
||||
RoleMember Role = "MEMBER"
|
||||
RoleViewer Role = "VIEWER"
|
||||
MembershipRoleOwner MembershipRole = "OWNER"
|
||||
MembershipRoleAdmin MembershipRole = "ADMIN"
|
||||
MembershipRoleViewer MembershipRole = "VIEWER"
|
||||
)
|
||||
|
||||
func (r Role) String() string {
|
||||
func (r MembershipRole) String() string {
|
||||
return string(r)
|
||||
}
|
||||
|
||||
func (r *Role) Scan(value any) error {
|
||||
func (r *MembershipRole) Scan(value any) error {
|
||||
var s string
|
||||
switch v := value.(type) {
|
||||
case string:
|
||||
@@ -40,24 +39,22 @@ func (r *Role) Scan(value any) error {
|
||||
case []byte:
|
||||
s = string(v)
|
||||
default:
|
||||
return fmt.Errorf("unsupported type for Role: %T", value)
|
||||
return fmt.Errorf("unsupported type for MembershipRole: %T", value)
|
||||
}
|
||||
|
||||
switch s {
|
||||
case "OWNER":
|
||||
*r = RoleOwner
|
||||
*r = MembershipRoleOwner
|
||||
case "ADMIN":
|
||||
*r = RoleAdmin
|
||||
case "MEMBER":
|
||||
*r = RoleMember
|
||||
*r = MembershipRoleAdmin
|
||||
case "VIEWER":
|
||||
*r = RoleViewer
|
||||
*r = MembershipRoleViewer
|
||||
default:
|
||||
return fmt.Errorf("invalid Role value: %q", s)
|
||||
return fmt.Errorf("invalid MembershipRole value: %q", s)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r Role) Value() (driver.Value, error) {
|
||||
func (r MembershipRole) Value() (driver.Value, error) {
|
||||
return r.String(), nil
|
||||
}
|
||||
@@ -19,25 +19,26 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"maps"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgconn"
|
||||
"go.gearno.de/kit/pg"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
)
|
||||
|
||||
type (
|
||||
Membership struct {
|
||||
ID gid.GID `db:"id"`
|
||||
UserID gid.GID `db:"user_id"`
|
||||
OrganizationID gid.GID `db:"organization_id"`
|
||||
Role Role `db:"role"`
|
||||
FullName string `db:"full_name"`
|
||||
EmailAddress string `db:"email_address"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
ID gid.GID `db:"id"`
|
||||
UserID gid.GID `db:"user_id"`
|
||||
OrganizationID gid.GID `db:"organization_id"`
|
||||
Role MembershipRole `db:"role"`
|
||||
FullName string `db:"full_name"`
|
||||
EmailAddress string `db:"email_address"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
}
|
||||
|
||||
Memberships []*Membership
|
||||
@@ -185,6 +186,83 @@ JOIN
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadRoleByUserAndEntityID loads a user's role by querying any entity to extract its organization_id
|
||||
func (m *Membership) LoadRoleByUserAndEntityID(
|
||||
ctx context.Context,
|
||||
conn pg.Conn,
|
||||
scope Scoper,
|
||||
userID gid.GID,
|
||||
entityID gid.GID,
|
||||
) error {
|
||||
entityType := entityID.EntityType()
|
||||
|
||||
// For organization, the entity ID is the organization ID
|
||||
if entityType == OrganizationEntityType {
|
||||
return m.LoadByUserAndOrg(ctx, conn, scope, userID, entityID)
|
||||
}
|
||||
|
||||
tableName, ok := EntityTable(entityType)
|
||||
if !ok {
|
||||
return fmt.Errorf("unsupported entity type for role lookup: %d", entityType)
|
||||
}
|
||||
|
||||
// Build scope fragment with table alias to avoid ambiguity
|
||||
scopeFragment := scope.SQLFragment()
|
||||
// Replace column references with table-qualified versions
|
||||
scopeFragment = strings.ReplaceAll(scopeFragment, "tenant_id =", "m.tenant_id =")
|
||||
|
||||
query := fmt.Sprintf(`
|
||||
SELECT
|
||||
m.id,
|
||||
m.user_id,
|
||||
m.organization_id,
|
||||
m.role,
|
||||
m.created_at,
|
||||
m.updated_at
|
||||
FROM
|
||||
authz_memberships m
|
||||
INNER JOIN %s e ON e.id = @entity_id
|
||||
WHERE
|
||||
%s
|
||||
AND m.user_id = @user_id
|
||||
AND m.organization_id = e.organization_id
|
||||
LIMIT 1;
|
||||
`, tableName, scopeFragment)
|
||||
|
||||
args := pgx.NamedArgs{
|
||||
"user_id": userID,
|
||||
"entity_id": entityID,
|
||||
}
|
||||
maps.Copy(args, scope.SQLArguments())
|
||||
|
||||
rows, err := conn.Query(ctx, query, args)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot query membership by entity: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
if !rows.Next() {
|
||||
return &ErrMembershipNotFound{UserID: userID, OrgID: entityID}
|
||||
}
|
||||
|
||||
var membership Membership
|
||||
err = rows.Scan(
|
||||
&membership.ID,
|
||||
&membership.UserID,
|
||||
&membership.OrganizationID,
|
||||
&membership.Role,
|
||||
&membership.CreatedAt,
|
||||
&membership.UpdatedAt,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot scan membership: %w", err)
|
||||
}
|
||||
|
||||
*m = membership
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Membership) LoadByUserAndOrg(
|
||||
ctx context.Context,
|
||||
conn pg.Conn,
|
||||
@@ -195,17 +273,17 @@ func (m *Membership) LoadByUserAndOrg(
|
||||
query := `
|
||||
WITH mbr AS (
|
||||
SELECT
|
||||
id,
|
||||
user_id,
|
||||
organization_id,
|
||||
role,
|
||||
created_at,
|
||||
updated_at
|
||||
am.id,
|
||||
am.user_id,
|
||||
am.organization_id,
|
||||
am.role,
|
||||
am.created_at,
|
||||
am.updated_at
|
||||
FROM
|
||||
authz_memberships
|
||||
authz_memberships am
|
||||
WHERE
|
||||
user_id = @user_id
|
||||
AND organization_id = @organization_id
|
||||
am.user_id = @user_id
|
||||
AND am.organization_id = @organization_id
|
||||
AND %s
|
||||
)
|
||||
SELECT
|
||||
@@ -223,7 +301,12 @@ JOIN
|
||||
users u ON mbr.user_id = u.id
|
||||
`
|
||||
|
||||
query = fmt.Sprintf(query, scope.SQLFragment())
|
||||
// Build scope fragment with table alias
|
||||
scopeFragment := scope.SQLFragment()
|
||||
// Replace column references with table-qualified versions
|
||||
scopeFragment = strings.ReplaceAll(scopeFragment, "tenant_id =", "am.tenant_id =")
|
||||
|
||||
query = fmt.Sprintf(query, scopeFragment)
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"user_id": userID,
|
||||
@@ -468,67 +551,3 @@ WHERE
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func LoadUserIDsByOrganizationID(
|
||||
ctx context.Context,
|
||||
conn pg.Conn,
|
||||
scope Scoper,
|
||||
organizationID gid.GID,
|
||||
) ([]gid.GID, error) {
|
||||
query := `
|
||||
SELECT user_id
|
||||
FROM authz_memberships
|
||||
WHERE organization_id = @organization_id AND %s
|
||||
`
|
||||
query = fmt.Sprintf(query, scope.SQLFragment())
|
||||
args := pgx.StrictNamedArgs{"organization_id": organizationID}
|
||||
maps.Copy(args, scope.SQLArguments())
|
||||
|
||||
rows, err := conn.Query(ctx, query, args)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot query memberships: %w", err)
|
||||
}
|
||||
|
||||
var userIDs []gid.GID
|
||||
for rows.Next() {
|
||||
var userID gid.GID
|
||||
if err := rows.Scan(&userID); err != nil {
|
||||
rows.Close()
|
||||
return nil, fmt.Errorf("cannot scan user_id: %w", err)
|
||||
}
|
||||
userIDs = append(userIDs, userID)
|
||||
}
|
||||
rows.Close()
|
||||
|
||||
return userIDs, nil
|
||||
}
|
||||
|
||||
func UpdateMembershipUserID(
|
||||
ctx context.Context,
|
||||
conn pg.Conn,
|
||||
scope Scoper,
|
||||
oldUserID gid.GID,
|
||||
newUserID gid.GID,
|
||||
organizationID gid.GID,
|
||||
) error {
|
||||
query := `
|
||||
UPDATE authz_memberships
|
||||
SET user_id = @new_user_id, updated_at = @updated_at
|
||||
WHERE user_id = @old_user_id AND organization_id = @organization_id AND %s
|
||||
`
|
||||
query = fmt.Sprintf(query, scope.SQLFragment())
|
||||
args := pgx.StrictNamedArgs{
|
||||
"new_user_id": newUserID,
|
||||
"old_user_id": oldUserID,
|
||||
"organization_id": organizationID,
|
||||
"updated_at": time.Now(),
|
||||
}
|
||||
maps.Copy(args, scope.SQLArguments())
|
||||
|
||||
_, err := conn.Exec(ctx, query, args)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot update membership: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
210
pkg/coredata/migrations/20251109T214255Z.sql
Normal file
210
pkg/coredata/migrations/20251109T214255Z.sql
Normal file
@@ -0,0 +1,210 @@
|
||||
-- Set all existing memberships to OWNER role
|
||||
UPDATE authz_memberships SET role = 'OWNER';
|
||||
|
||||
ALTER TABLE controls ADD COLUMN IF NOT EXISTS organization_id TEXT;
|
||||
UPDATE controls
|
||||
SET organization_id = organizations.id
|
||||
FROM organizations
|
||||
WHERE controls.tenant_id = organizations.tenant_id
|
||||
AND controls.organization_id IS NULL;
|
||||
ALTER TABLE controls ALTER COLUMN organization_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE evidences ADD COLUMN IF NOT EXISTS organization_id TEXT;
|
||||
UPDATE evidences
|
||||
SET organization_id = organizations.id
|
||||
FROM organizations
|
||||
WHERE evidences.tenant_id = organizations.tenant_id
|
||||
AND evidences.organization_id IS NULL;
|
||||
ALTER TABLE evidences ALTER COLUMN organization_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE files ADD COLUMN IF NOT EXISTS organization_id TEXT;
|
||||
UPDATE files
|
||||
SET organization_id = organizations.id
|
||||
FROM organizations
|
||||
WHERE files.tenant_id = organizations.tenant_id
|
||||
AND files.organization_id IS NULL;
|
||||
ALTER TABLE files ALTER COLUMN organization_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE document_versions ADD COLUMN IF NOT EXISTS organization_id TEXT;
|
||||
UPDATE document_versions
|
||||
SET organization_id = organizations.id
|
||||
FROM organizations
|
||||
WHERE document_versions.tenant_id = organizations.tenant_id
|
||||
AND document_versions.organization_id IS NULL;
|
||||
ALTER TABLE document_versions ALTER COLUMN organization_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE document_version_signatures ADD COLUMN IF NOT EXISTS organization_id TEXT;
|
||||
UPDATE document_version_signatures
|
||||
SET organization_id = organizations.id
|
||||
FROM organizations
|
||||
WHERE document_version_signatures.tenant_id = organizations.tenant_id
|
||||
AND document_version_signatures.organization_id IS NULL;
|
||||
ALTER TABLE document_version_signatures ALTER COLUMN organization_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE trust_center_references ADD COLUMN IF NOT EXISTS organization_id TEXT;
|
||||
UPDATE trust_center_references
|
||||
SET organization_id = organizations.id
|
||||
FROM organizations
|
||||
WHERE trust_center_references.tenant_id = organizations.tenant_id
|
||||
AND trust_center_references.organization_id IS NULL;
|
||||
ALTER TABLE trust_center_references ALTER COLUMN organization_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE trust_center_accesses ADD COLUMN IF NOT EXISTS organization_id TEXT;
|
||||
UPDATE trust_center_accesses
|
||||
SET organization_id = organizations.id
|
||||
FROM organizations
|
||||
WHERE trust_center_accesses.tenant_id = organizations.tenant_id
|
||||
AND trust_center_accesses.organization_id IS NULL;
|
||||
ALTER TABLE trust_center_accesses ALTER COLUMN organization_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE trust_center_document_accesses ADD COLUMN IF NOT EXISTS organization_id TEXT;
|
||||
UPDATE trust_center_document_accesses
|
||||
SET organization_id = organizations.id
|
||||
FROM organizations
|
||||
WHERE trust_center_document_accesses.tenant_id = organizations.tenant_id
|
||||
AND trust_center_document_accesses.organization_id IS NULL;
|
||||
ALTER TABLE trust_center_document_accesses ALTER COLUMN organization_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE vendor_services ADD COLUMN IF NOT EXISTS organization_id TEXT;
|
||||
UPDATE vendor_services
|
||||
SET organization_id = organizations.id
|
||||
FROM organizations
|
||||
WHERE vendor_services.tenant_id = organizations.tenant_id
|
||||
AND vendor_services.organization_id IS NULL;
|
||||
ALTER TABLE vendor_services ALTER COLUMN organization_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE vendor_contacts ADD COLUMN IF NOT EXISTS organization_id TEXT;
|
||||
UPDATE vendor_contacts
|
||||
SET organization_id = organizations.id
|
||||
FROM organizations
|
||||
WHERE vendor_contacts.tenant_id = organizations.tenant_id
|
||||
AND vendor_contacts.organization_id IS NULL;
|
||||
ALTER TABLE vendor_contacts ALTER COLUMN organization_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE vendor_risk_assessments ADD COLUMN IF NOT EXISTS organization_id TEXT;
|
||||
UPDATE vendor_risk_assessments
|
||||
SET organization_id = organizations.id
|
||||
FROM organizations
|
||||
WHERE vendor_risk_assessments.tenant_id = organizations.tenant_id
|
||||
AND vendor_risk_assessments.organization_id IS NULL;
|
||||
ALTER TABLE vendor_risk_assessments ALTER COLUMN organization_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE reports ADD COLUMN IF NOT EXISTS organization_id TEXT;
|
||||
UPDATE reports
|
||||
SET organization_id = organizations.id
|
||||
FROM organizations
|
||||
WHERE reports.tenant_id = organizations.tenant_id
|
||||
AND reports.organization_id IS NULL;
|
||||
ALTER TABLE reports ALTER COLUMN organization_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE custom_domains ADD COLUMN IF NOT EXISTS organization_id TEXT;
|
||||
UPDATE custom_domains
|
||||
SET organization_id = organizations.id
|
||||
FROM organizations
|
||||
WHERE custom_domains.tenant_id = organizations.tenant_id
|
||||
AND custom_domains.organization_id IS NULL;
|
||||
ALTER TABLE custom_domains ALTER COLUMN organization_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE asset_vendors ADD COLUMN IF NOT EXISTS organization_id TEXT;
|
||||
UPDATE asset_vendors
|
||||
SET organization_id = organizations.id
|
||||
FROM organizations
|
||||
WHERE asset_vendors.tenant_id = organizations.tenant_id
|
||||
AND asset_vendors.organization_id IS NULL;
|
||||
ALTER TABLE asset_vendors ALTER COLUMN organization_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE authz_api_keys_memberships ADD COLUMN IF NOT EXISTS organization_id TEXT;
|
||||
UPDATE authz_api_keys_memberships
|
||||
SET organization_id = organizations.id
|
||||
FROM organizations
|
||||
WHERE authz_api_keys_memberships.tenant_id = organizations.tenant_id
|
||||
AND authz_api_keys_memberships.organization_id IS NULL;
|
||||
ALTER TABLE authz_api_keys_memberships ALTER COLUMN organization_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE controls_audits ADD COLUMN IF NOT EXISTS organization_id TEXT;
|
||||
UPDATE controls_audits
|
||||
SET organization_id = organizations.id
|
||||
FROM organizations
|
||||
WHERE controls_audits.tenant_id = organizations.tenant_id
|
||||
AND controls_audits.organization_id IS NULL;
|
||||
ALTER TABLE controls_audits ALTER COLUMN organization_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE controls_documents ADD COLUMN IF NOT EXISTS organization_id TEXT;
|
||||
UPDATE controls_documents
|
||||
SET organization_id = organizations.id
|
||||
FROM organizations
|
||||
WHERE controls_documents.tenant_id = organizations.tenant_id
|
||||
AND controls_documents.organization_id IS NULL;
|
||||
ALTER TABLE controls_documents ALTER COLUMN organization_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE controls_measures ADD COLUMN IF NOT EXISTS organization_id TEXT;
|
||||
UPDATE controls_measures
|
||||
SET organization_id = organizations.id
|
||||
FROM organizations
|
||||
WHERE controls_measures.tenant_id = organizations.tenant_id
|
||||
AND controls_measures.organization_id IS NULL;
|
||||
ALTER TABLE controls_measures ALTER COLUMN organization_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE controls_snapshots ADD COLUMN IF NOT EXISTS organization_id TEXT;
|
||||
UPDATE controls_snapshots
|
||||
SET organization_id = organizations.id
|
||||
FROM organizations
|
||||
WHERE controls_snapshots.tenant_id = organizations.tenant_id
|
||||
AND controls_snapshots.organization_id IS NULL;
|
||||
ALTER TABLE controls_snapshots ALTER COLUMN organization_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE data_vendors ADD COLUMN IF NOT EXISTS organization_id TEXT;
|
||||
UPDATE data_vendors
|
||||
SET organization_id = organizations.id
|
||||
FROM organizations
|
||||
WHERE data_vendors.tenant_id = organizations.tenant_id
|
||||
AND data_vendors.organization_id IS NULL;
|
||||
ALTER TABLE data_vendors ALTER COLUMN organization_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE export_jobs ADD COLUMN IF NOT EXISTS organization_id TEXT;
|
||||
UPDATE export_jobs
|
||||
SET organization_id = organizations.id
|
||||
FROM organizations
|
||||
WHERE export_jobs.tenant_id = organizations.tenant_id
|
||||
AND export_jobs.organization_id IS NULL;
|
||||
ALTER TABLE export_jobs ALTER COLUMN organization_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE processing_activity_vendors ADD COLUMN IF NOT EXISTS organization_id TEXT;
|
||||
UPDATE processing_activity_vendors
|
||||
SET organization_id = organizations.id
|
||||
FROM organizations
|
||||
WHERE processing_activity_vendors.tenant_id = organizations.tenant_id
|
||||
AND processing_activity_vendors.organization_id IS NULL;
|
||||
ALTER TABLE processing_activity_vendors ALTER COLUMN organization_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE risks_documents ADD COLUMN IF NOT EXISTS organization_id TEXT;
|
||||
UPDATE risks_documents
|
||||
SET organization_id = organizations.id
|
||||
FROM organizations
|
||||
WHERE risks_documents.tenant_id = organizations.tenant_id
|
||||
AND risks_documents.organization_id IS NULL;
|
||||
ALTER TABLE risks_documents ALTER COLUMN organization_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE risks_measures ADD COLUMN IF NOT EXISTS organization_id TEXT;
|
||||
UPDATE risks_measures
|
||||
SET organization_id = organizations.id
|
||||
FROM organizations
|
||||
WHERE risks_measures.tenant_id = organizations.tenant_id
|
||||
AND risks_measures.organization_id IS NULL;
|
||||
ALTER TABLE risks_measures ALTER COLUMN organization_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE risks_obligations ADD COLUMN IF NOT EXISTS organization_id TEXT;
|
||||
UPDATE risks_obligations
|
||||
SET organization_id = organizations.id
|
||||
FROM organizations
|
||||
WHERE risks_obligations.tenant_id = organizations.tenant_id
|
||||
AND risks_obligations.organization_id IS NULL;
|
||||
ALTER TABLE risks_obligations ALTER COLUMN organization_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE vendor_compliance_reports ADD COLUMN IF NOT EXISTS organization_id TEXT;
|
||||
UPDATE vendor_compliance_reports
|
||||
SET organization_id = organizations.id
|
||||
FROM organizations
|
||||
WHERE vendor_compliance_reports.tenant_id = organizations.tenant_id
|
||||
AND vendor_compliance_reports.organization_id IS NULL;
|
||||
ALTER TABLE vendor_compliance_reports ALTER COLUMN organization_id SET NOT NULL;
|
||||
@@ -237,6 +237,63 @@ ORDER BY
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Organizations) LoadAllByUserIDWithRole(
|
||||
ctx context.Context,
|
||||
conn pg.Conn,
|
||||
userID gid.GID,
|
||||
role MembershipRole,
|
||||
) error {
|
||||
q := `
|
||||
WITH user_org AS (
|
||||
SELECT
|
||||
organization_id
|
||||
FROM
|
||||
authz_memberships
|
||||
WHERE
|
||||
user_id = @user_id
|
||||
AND role = @role
|
||||
)
|
||||
SELECT
|
||||
tenant_id,
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
website_url,
|
||||
email,
|
||||
headquarter_address,
|
||||
custom_domain_id,
|
||||
logo_file_id,
|
||||
horizontal_logo_file_id,
|
||||
created_at,
|
||||
updated_at
|
||||
FROM
|
||||
organizations
|
||||
INNER JOIN
|
||||
user_org ON organizations.id = user_org.organization_id
|
||||
ORDER BY
|
||||
name ASC
|
||||
`
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"user_id": userID,
|
||||
"role": role,
|
||||
}
|
||||
|
||||
rows, err := conn.Query(ctx, q, args)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot query organizations: %w", err)
|
||||
}
|
||||
|
||||
organizations, err := pgx.CollectRows(rows, pgx.RowToAddrOfStructByName[Organization])
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot collect organizations: %w", err)
|
||||
}
|
||||
|
||||
*o = organizations
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Organizations) LoadAllByUserAPIKeyID(
|
||||
ctx context.Context,
|
||||
conn pg.Conn,
|
||||
|
||||
@@ -20,21 +20,22 @@ import (
|
||||
"maps"
|
||||
"time"
|
||||
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"go.gearno.de/kit/pg"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
)
|
||||
|
||||
type (
|
||||
Report struct {
|
||||
ID gid.GID `db:"id"`
|
||||
ObjectKey string `db:"object_key"`
|
||||
MimeType string `db:"mime_type"`
|
||||
Filename string `db:"filename"`
|
||||
Size int64 `db:"size"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
ID gid.GID `db:"id"`
|
||||
OrganizationID gid.GID `db:"organization_id"`
|
||||
ObjectKey string `db:"object_key"`
|
||||
MimeType string `db:"mime_type"`
|
||||
Filename string `db:"filename"`
|
||||
Size int64 `db:"size"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
}
|
||||
|
||||
Reports []*Report
|
||||
@@ -49,6 +50,7 @@ func (r *Report) LoadByID(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
object_key,
|
||||
mime_type,
|
||||
filename,
|
||||
@@ -92,6 +94,7 @@ func (r *Report) Insert(
|
||||
INSERT INTO reports (
|
||||
id,
|
||||
tenant_id,
|
||||
organization_id,
|
||||
object_key,
|
||||
mime_type,
|
||||
filename,
|
||||
@@ -101,6 +104,7 @@ INSERT INTO reports (
|
||||
) VALUES (
|
||||
@id,
|
||||
@tenant_id,
|
||||
@organization_id,
|
||||
@object_key,
|
||||
@mime_type,
|
||||
@filename,
|
||||
@@ -111,14 +115,15 @@ INSERT INTO reports (
|
||||
`
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"id": r.ID,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"object_key": r.ObjectKey,
|
||||
"mime_type": r.MimeType,
|
||||
"filename": r.Filename,
|
||||
"size": r.Size,
|
||||
"created_at": r.CreatedAt,
|
||||
"updated_at": r.UpdatedAt,
|
||||
"id": r.ID,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"organization_id": r.OrganizationID,
|
||||
"object_key": r.ObjectKey,
|
||||
"mime_type": r.MimeType,
|
||||
"filename": r.Filename,
|
||||
"size": r.Size,
|
||||
"created_at": r.CreatedAt,
|
||||
"updated_at": r.UpdatedAt,
|
||||
}
|
||||
|
||||
_, err := conn.Exec(ctx, q, args)
|
||||
|
||||
@@ -27,10 +27,11 @@ import (
|
||||
|
||||
type (
|
||||
RiskDocument struct {
|
||||
RiskID gid.GID `db:"risk_id"`
|
||||
DocumentID gid.GID `db:"document_id"`
|
||||
TenantID gid.TenantID `db:"tenant_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
RiskID gid.GID `db:"risk_id"`
|
||||
DocumentID gid.GID `db:"document_id"`
|
||||
OrganizationID gid.GID `db:"organization_id"`
|
||||
TenantID gid.TenantID `db:"tenant_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
}
|
||||
|
||||
RiskDocuments []*RiskDocument
|
||||
@@ -46,22 +47,25 @@ INSERT INTO
|
||||
risks_documents (
|
||||
risk_id,
|
||||
document_id,
|
||||
organization_id,
|
||||
tenant_id,
|
||||
created_at
|
||||
)
|
||||
VALUES (
|
||||
@risk_id,
|
||||
@document_id,
|
||||
@organization_id,
|
||||
@tenant_id,
|
||||
@created_at
|
||||
);
|
||||
`
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"risk_id": rp.RiskID,
|
||||
"document_id": rp.DocumentID,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"created_at": rp.CreatedAt,
|
||||
"risk_id": rp.RiskID,
|
||||
"document_id": rp.DocumentID,
|
||||
"organization_id": rp.OrganizationID,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"created_at": rp.CreatedAt,
|
||||
}
|
||||
_, err := conn.Exec(ctx, q, args)
|
||||
return err
|
||||
|
||||
@@ -20,17 +20,18 @@ import (
|
||||
"maps"
|
||||
"time"
|
||||
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"go.gearno.de/kit/pg"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
)
|
||||
|
||||
type (
|
||||
RiskMeasure struct {
|
||||
RiskID gid.GID `db:"risk_id"`
|
||||
MeasureID gid.GID `db:"measure_id"`
|
||||
TenantID gid.TenantID `db:"tenant_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
RiskID gid.GID `db:"risk_id"`
|
||||
MeasureID gid.GID `db:"measure_id"`
|
||||
OrganizationID gid.GID `db:"organization_id"`
|
||||
TenantID gid.TenantID `db:"tenant_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
}
|
||||
|
||||
RiskMeasures []*RiskMeasure
|
||||
@@ -46,22 +47,25 @@ INSERT INTO
|
||||
risks_measures (
|
||||
risk_id,
|
||||
measure_id,
|
||||
organization_id,
|
||||
tenant_id,
|
||||
created_at
|
||||
)
|
||||
VALUES (
|
||||
@risk_id,
|
||||
@measure_id,
|
||||
@organization_id,
|
||||
@tenant_id,
|
||||
@created_at
|
||||
);
|
||||
`
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"risk_id": rm.RiskID,
|
||||
"measure_id": rm.MeasureID,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"created_at": rm.CreatedAt,
|
||||
"risk_id": rm.RiskID,
|
||||
"measure_id": rm.MeasureID,
|
||||
"organization_id": rm.OrganizationID,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"created_at": rm.CreatedAt,
|
||||
}
|
||||
_, err := conn.Exec(ctx, q, args)
|
||||
return err
|
||||
|
||||
@@ -27,9 +27,10 @@ import (
|
||||
|
||||
type (
|
||||
RiskObligation struct {
|
||||
RiskID gid.GID `db:"risk_id"`
|
||||
ObligationID gid.GID `db:"obligation_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
RiskID gid.GID `db:"risk_id"`
|
||||
ObligationID gid.GID `db:"obligation_id"`
|
||||
OrganizationID gid.GID `db:"organization_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
}
|
||||
|
||||
RiskObligations []*RiskObligation
|
||||
@@ -44,21 +45,24 @@ func (ro RiskObligation) Insert(
|
||||
INSERT INTO risks_obligations (
|
||||
risk_id,
|
||||
obligation_id,
|
||||
organization_id,
|
||||
tenant_id,
|
||||
created_at
|
||||
) VALUES (
|
||||
@risk_id,
|
||||
@obligation_id,
|
||||
@organization_id,
|
||||
@tenant_id,
|
||||
@created_at
|
||||
)
|
||||
`
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"risk_id": ro.RiskID,
|
||||
"obligation_id": ro.ObligationID,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"created_at": ro.CreatedAt,
|
||||
"risk_id": ro.RiskID,
|
||||
"obligation_id": ro.ObligationID,
|
||||
"organization_id": ro.OrganizationID,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"created_at": ro.CreatedAt,
|
||||
}
|
||||
|
||||
_, err := conn.Exec(ctx, q, args)
|
||||
|
||||
@@ -21,9 +21,9 @@ import (
|
||||
"maps"
|
||||
"time"
|
||||
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"go.gearno.de/kit/pg"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
@@ -22,16 +22,17 @@ import (
|
||||
"maps"
|
||||
"time"
|
||||
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgconn"
|
||||
"go.gearno.de/kit/pg"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
)
|
||||
|
||||
type (
|
||||
TrustCenterAccess struct {
|
||||
ID gid.GID `db:"id"`
|
||||
OrganizationID gid.GID `db:"organization_id"`
|
||||
TenantID gid.TenantID `db:"tenant_id"`
|
||||
TrustCenterID gid.GID `db:"trust_center_id"`
|
||||
Email string `db:"email"`
|
||||
@@ -82,6 +83,7 @@ func (tca *TrustCenterAccess) LoadByID(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
tenant_id,
|
||||
trust_center_id,
|
||||
email,
|
||||
@@ -135,6 +137,7 @@ func (tca *TrustCenterAccess) LoadByTrustCenterIDAndEmail(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
tenant_id,
|
||||
trust_center_id,
|
||||
email,
|
||||
@@ -191,6 +194,7 @@ func (tca *TrustCenterAccess) Insert(
|
||||
INSERT INTO trust_center_accesses (
|
||||
id,
|
||||
tenant_id,
|
||||
organization_id,
|
||||
trust_center_id,
|
||||
email,
|
||||
name,
|
||||
@@ -201,6 +205,7 @@ INSERT INTO trust_center_accesses (
|
||||
) VALUES (
|
||||
@id,
|
||||
@tenant_id,
|
||||
@organization_id,
|
||||
@trust_center_id,
|
||||
@email,
|
||||
@name,
|
||||
@@ -214,6 +219,7 @@ INSERT INTO trust_center_accesses (
|
||||
args := pgx.StrictNamedArgs{
|
||||
"id": tca.ID,
|
||||
"tenant_id": tca.TenantID,
|
||||
"organization_id": tca.OrganizationID,
|
||||
"trust_center_id": tca.TrustCenterID,
|
||||
"email": tca.Email,
|
||||
"name": tca.Name,
|
||||
@@ -317,6 +323,7 @@ func (tcas *TrustCenterAccesses) LoadByTrustCenterID(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
tenant_id,
|
||||
trust_center_id,
|
||||
email,
|
||||
|
||||
@@ -21,16 +21,17 @@ import (
|
||||
"maps"
|
||||
"time"
|
||||
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgconn"
|
||||
"go.gearno.de/kit/pg"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
)
|
||||
|
||||
type (
|
||||
TrustCenterDocumentAccess struct {
|
||||
ID gid.GID `db:"id"`
|
||||
OrganizationID gid.GID `db:"organization_id"`
|
||||
TrustCenterAccessID gid.GID `db:"trust_center_access_id"`
|
||||
DocumentID *gid.GID `db:"document_id"`
|
||||
ReportID *gid.GID `db:"report_id"`
|
||||
@@ -78,6 +79,7 @@ func (tcda *TrustCenterDocumentAccess) LoadByID(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
trust_center_access_id,
|
||||
document_id,
|
||||
report_id,
|
||||
@@ -127,6 +129,7 @@ func (tcda *TrustCenterDocumentAccess) LoadByTrustCenterAccessIDAndDocumentID(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
trust_center_access_id,
|
||||
document_id,
|
||||
report_id,
|
||||
@@ -177,6 +180,7 @@ func (tcda *TrustCenterDocumentAccess) LoadByTrustCenterAccessIDAndReportID(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
trust_center_access_id,
|
||||
document_id,
|
||||
report_id,
|
||||
@@ -226,6 +230,7 @@ func (tcda *TrustCenterDocumentAccess) Insert(
|
||||
INSERT INTO trust_center_document_accesses (
|
||||
id,
|
||||
tenant_id,
|
||||
organization_id,
|
||||
trust_center_access_id,
|
||||
document_id,
|
||||
report_id,
|
||||
@@ -237,6 +242,7 @@ INSERT INTO trust_center_document_accesses (
|
||||
) VALUES (
|
||||
@id,
|
||||
@tenant_id,
|
||||
@organization_id,
|
||||
@trust_center_access_id,
|
||||
@document_id,
|
||||
@report_id,
|
||||
@@ -251,6 +257,7 @@ INSERT INTO trust_center_document_accesses (
|
||||
args := pgx.StrictNamedArgs{
|
||||
"id": tcda.ID,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"organization_id": tcda.OrganizationID,
|
||||
"trust_center_access_id": tcda.TrustCenterAccessID,
|
||||
"document_id": tcda.DocumentID,
|
||||
"report_id": tcda.ReportID,
|
||||
@@ -512,6 +519,7 @@ final_items AS (
|
||||
SELECT
|
||||
COALESCE(tcda.id, ai.item_id) AS id,
|
||||
tcda.tenant_id,
|
||||
(SELECT organization_id FROM organization) AS organization_id,
|
||||
@trust_center_access_id AS trust_center_access_id,
|
||||
ai.document_id,
|
||||
ai.report_id,
|
||||
@@ -532,6 +540,7 @@ final_items AS (
|
||||
)
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
trust_center_access_id,
|
||||
document_id,
|
||||
report_id,
|
||||
@@ -576,6 +585,7 @@ func (tcdas *TrustCenterDocumentAccesses) LoadAllByTrustCenterAccessID(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
trust_center_access_id,
|
||||
document_id,
|
||||
report_id,
|
||||
@@ -717,6 +727,7 @@ func (tcdas TrustCenterDocumentAccesses) BulkInsertDocumentAccesses(
|
||||
conn pg.Conn,
|
||||
scope Scoper,
|
||||
trustCenterAccessID gid.GID,
|
||||
organizationID gid.GID,
|
||||
documentIDs []gid.GID,
|
||||
requested bool,
|
||||
createdAt time.Time,
|
||||
@@ -730,6 +741,7 @@ WITH document_access_data AS (
|
||||
SELECT
|
||||
generate_gid(decode_base64_unpadded(@tenant_id), @trust_center_document_access_entity_type) AS id,
|
||||
@tenant_id AS tenant_id,
|
||||
@organization_id AS organization_id,
|
||||
@trust_center_access_id AS trust_center_access_id,
|
||||
unnest(@document_ids::text[]) AS document_id,
|
||||
null::text AS report_id,
|
||||
@@ -740,7 +752,7 @@ WITH document_access_data AS (
|
||||
@updated_at::timestamptz AS updated_at
|
||||
)
|
||||
INSERT INTO trust_center_document_accesses (
|
||||
id, tenant_id, trust_center_access_id, document_id, report_id, trust_center_file_id, active, requested, created_at, updated_at
|
||||
id, tenant_id, organization_id, trust_center_access_id, document_id, report_id, trust_center_file_id, active, requested, created_at, updated_at
|
||||
)
|
||||
SELECT * FROM document_access_data
|
||||
ON CONFLICT DO NOTHING
|
||||
@@ -748,6 +760,7 @@ ON CONFLICT DO NOTHING
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"organization_id": organizationID,
|
||||
"trust_center_access_id": trustCenterAccessID,
|
||||
"document_ids": documentIDs,
|
||||
"trust_center_document_access_entity_type": TrustCenterDocumentAccessEntityType,
|
||||
@@ -768,6 +781,7 @@ func (tcdas TrustCenterDocumentAccesses) BulkInsertReportAccesses(
|
||||
conn pg.Conn,
|
||||
scope Scoper,
|
||||
trustCenterAccessID gid.GID,
|
||||
organizationID gid.GID,
|
||||
reportIDs []gid.GID,
|
||||
requested bool,
|
||||
createdAt time.Time,
|
||||
@@ -781,6 +795,7 @@ WITH report_access_data AS (
|
||||
SELECT
|
||||
generate_gid(decode_base64_unpadded(@tenant_id), @trust_center_document_access_entity_type) AS id,
|
||||
@tenant_id AS tenant_id,
|
||||
@organization_id AS organization_id,
|
||||
@trust_center_access_id AS trust_center_access_id,
|
||||
null::text AS document_id,
|
||||
unnest(@report_ids::text[]) AS report_id,
|
||||
@@ -791,14 +806,15 @@ WITH report_access_data AS (
|
||||
@updated_at::timestamptz AS updated_at
|
||||
)
|
||||
INSERT INTO trust_center_document_accesses (
|
||||
id, tenant_id, trust_center_access_id, document_id, report_id, trust_center_file_id, active, requested, created_at, updated_at
|
||||
id, tenant_id, organization_id, trust_center_access_id, document_id, report_id, trust_center_file_id, active, requested, created_at, updated_at
|
||||
)
|
||||
SELECT * FROM report_access_data
|
||||
ON CONFLICT DO NOTHING
|
||||
`
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"organization_id": organizationID,
|
||||
"trust_center_document_access_entity_type": TrustCenterDocumentAccessEntityType,
|
||||
"trust_center_access_id": trustCenterAccessID,
|
||||
"report_ids": reportIDs,
|
||||
@@ -903,6 +919,7 @@ func (tcdas TrustCenterDocumentAccesses) BulkInsertTrustCenterFileAccesses(
|
||||
conn pg.Conn,
|
||||
scope Scoper,
|
||||
trustCenterAccessID gid.GID,
|
||||
organizationID gid.GID,
|
||||
trustCenterFileIDs []gid.GID,
|
||||
requested bool,
|
||||
createdAt time.Time,
|
||||
@@ -912,6 +929,7 @@ WITH trust_center_file_access_data AS (
|
||||
SELECT
|
||||
generate_gid(decode_base64_unpadded(@tenant_id), @trust_center_document_access_entity_type) AS id,
|
||||
@tenant_id AS tenant_id,
|
||||
@organization_id AS organization_id,
|
||||
@trust_center_access_id AS trust_center_access_id,
|
||||
null::text AS document_id,
|
||||
null::text AS report_id,
|
||||
@@ -922,14 +940,15 @@ WITH trust_center_file_access_data AS (
|
||||
@updated_at::timestamptz AS updated_at
|
||||
)
|
||||
INSERT INTO trust_center_document_accesses (
|
||||
id, tenant_id, trust_center_access_id, document_id, report_id, trust_center_file_id, active, requested, created_at, updated_at
|
||||
id, tenant_id, organization_id, trust_center_access_id, document_id, report_id, trust_center_file_id, active, requested, created_at, updated_at
|
||||
)
|
||||
SELECT * FROM trust_center_file_access_data
|
||||
ON CONFLICT DO NOTHING
|
||||
`
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"organization_id": organizationID,
|
||||
"trust_center_document_access_entity_type": TrustCenterDocumentAccessEntityType,
|
||||
"trust_center_access_id": trustCenterAccessID,
|
||||
"trust_center_file_ids": trustCenterFileIDs,
|
||||
|
||||
@@ -30,15 +30,16 @@ import (
|
||||
|
||||
type (
|
||||
TrustCenterReference struct {
|
||||
ID gid.GID `db:"id"`
|
||||
TrustCenterID gid.GID `db:"trust_center_id"`
|
||||
Name string `db:"name"`
|
||||
Description *string `db:"description"`
|
||||
WebsiteURL string `db:"website_url"`
|
||||
LogoFileID gid.GID `db:"logo_file_id"`
|
||||
Rank int `db:"rank"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
ID gid.GID `db:"id"`
|
||||
OrganizationID gid.GID `db:"organization_id"`
|
||||
TrustCenterID gid.GID `db:"trust_center_id"`
|
||||
Name string `db:"name"`
|
||||
Description *string `db:"description"`
|
||||
WebsiteURL string `db:"website_url"`
|
||||
LogoFileID gid.GID `db:"logo_file_id"`
|
||||
Rank int `db:"rank"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
}
|
||||
|
||||
TrustCenterReferences []*TrustCenterReference
|
||||
@@ -83,6 +84,7 @@ func (t *TrustCenterReference) LoadByID(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
trust_center_id,
|
||||
name,
|
||||
description,
|
||||
@@ -128,6 +130,7 @@ INSERT INTO
|
||||
trust_center_references (
|
||||
tenant_id,
|
||||
id,
|
||||
organization_id,
|
||||
trust_center_id,
|
||||
name,
|
||||
description,
|
||||
@@ -140,6 +143,7 @@ INSERT INTO
|
||||
VALUES (
|
||||
@tenant_id,
|
||||
@id,
|
||||
@organization_id,
|
||||
@trust_center_id,
|
||||
@name,
|
||||
@description,
|
||||
@@ -155,6 +159,7 @@ RETURNING rank;
|
||||
args := pgx.StrictNamedArgs{
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"id": t.ID,
|
||||
"organization_id": t.OrganizationID,
|
||||
"trust_center_id": t.TrustCenterID,
|
||||
"name": t.Name,
|
||||
"description": t.Description,
|
||||
@@ -308,6 +313,7 @@ func (t *TrustCenterReferences) LoadByTrustCenterID(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
trust_center_id,
|
||||
name,
|
||||
description,
|
||||
|
||||
@@ -28,16 +28,17 @@ import (
|
||||
|
||||
type (
|
||||
VendorComplianceReport struct {
|
||||
ID gid.GID
|
||||
VendorID gid.GID
|
||||
ReportDate time.Time
|
||||
ValidUntil *time.Time
|
||||
ReportName string
|
||||
ReportFileId *gid.GID
|
||||
SnapshotID *gid.GID
|
||||
SourceID *gid.GID
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
ID gid.GID `db:"id"`
|
||||
OrganizationID gid.GID `db:"organization_id"`
|
||||
VendorID gid.GID `db:"vendor_id"`
|
||||
ReportDate time.Time `db:"report_date"`
|
||||
ValidUntil *time.Time `db:"valid_until"`
|
||||
ReportName string `db:"report_name"`
|
||||
ReportFileId *gid.GID `db:"report_file_id"`
|
||||
SnapshotID *gid.GID `db:"snapshot_id"`
|
||||
SourceID *gid.GID `db:"source_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
}
|
||||
|
||||
VendorComplianceReports []*VendorComplianceReport
|
||||
@@ -157,6 +158,7 @@ func (vcr *VendorComplianceReport) Insert(
|
||||
INSERT INTO
|
||||
vendor_compliance_reports (
|
||||
id,
|
||||
organization_id,
|
||||
tenant_id,
|
||||
vendor_id,
|
||||
report_date,
|
||||
@@ -168,6 +170,7 @@ INSERT INTO
|
||||
)
|
||||
VALUES (
|
||||
@id,
|
||||
@organization_id,
|
||||
@tenant_id,
|
||||
@vendor_id,
|
||||
@report_date,
|
||||
@@ -179,15 +182,16 @@ VALUES (
|
||||
)
|
||||
`
|
||||
args := pgx.NamedArgs{
|
||||
"id": vcr.ID,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"vendor_id": vcr.VendorID,
|
||||
"report_date": vcr.ReportDate,
|
||||
"valid_until": vcr.ValidUntil,
|
||||
"report_name": vcr.ReportName,
|
||||
"report_file_id": vcr.ReportFileId,
|
||||
"created_at": vcr.CreatedAt,
|
||||
"updated_at": vcr.UpdatedAt,
|
||||
"id": vcr.ID,
|
||||
"organization_id": vcr.OrganizationID,
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"vendor_id": vcr.VendorID,
|
||||
"report_date": vcr.ReportDate,
|
||||
"valid_until": vcr.ValidUntil,
|
||||
"report_name": vcr.ReportName,
|
||||
"report_file_id": vcr.ReportFileId,
|
||||
"created_at": vcr.CreatedAt,
|
||||
"updated_at": vcr.UpdatedAt,
|
||||
}
|
||||
|
||||
_, err := conn.Exec(ctx, q, args)
|
||||
|
||||
@@ -21,24 +21,25 @@ import (
|
||||
"maps"
|
||||
"time"
|
||||
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"go.gearno.de/kit/pg"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
)
|
||||
|
||||
type (
|
||||
VendorContact struct {
|
||||
ID gid.GID `db:"id"`
|
||||
VendorID gid.GID `db:"vendor_id"`
|
||||
FullName *string `db:"full_name"`
|
||||
Email *string `db:"email"`
|
||||
Phone *string `db:"phone"`
|
||||
Role *string `db:"role"`
|
||||
SnapshotID *gid.GID `db:"snapshot_id"`
|
||||
SourceID *gid.GID `db:"source_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
ID gid.GID `db:"id"`
|
||||
OrganizationID gid.GID `db:"organization_id"`
|
||||
VendorID gid.GID `db:"vendor_id"`
|
||||
FullName *string `db:"full_name"`
|
||||
Email *string `db:"email"`
|
||||
Phone *string `db:"phone"`
|
||||
Role *string `db:"role"`
|
||||
SnapshotID *gid.GID `db:"snapshot_id"`
|
||||
SourceID *gid.GID `db:"source_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
}
|
||||
|
||||
VendorContacts []*VendorContact
|
||||
@@ -74,6 +75,7 @@ func (vc *VendorContact) LoadByID(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
vendor_id,
|
||||
full_name,
|
||||
email,
|
||||
@@ -126,6 +128,7 @@ func (vc *VendorContacts) LoadByVendorID(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
vendor_id,
|
||||
full_name,
|
||||
email,
|
||||
@@ -176,6 +179,7 @@ INSERT INTO
|
||||
vendor_contacts (
|
||||
tenant_id,
|
||||
id,
|
||||
organization_id,
|
||||
vendor_id,
|
||||
full_name,
|
||||
email,
|
||||
@@ -187,6 +191,7 @@ INSERT INTO
|
||||
VALUES (
|
||||
@tenant_id,
|
||||
@vendor_contact_id,
|
||||
@organization_id,
|
||||
@vendor_id,
|
||||
@full_name,
|
||||
@email,
|
||||
@@ -200,6 +205,7 @@ VALUES (
|
||||
args := pgx.StrictNamedArgs{
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"vendor_contact_id": vc.ID,
|
||||
"organization_id": vc.OrganizationID,
|
||||
"vendor_id": vc.VendorID,
|
||||
"full_name": vc.FullName,
|
||||
"email": vc.Email,
|
||||
|
||||
@@ -20,16 +20,17 @@ import (
|
||||
"maps"
|
||||
"time"
|
||||
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"go.gearno.de/kit/pg"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
)
|
||||
|
||||
type (
|
||||
// RiskAssessment represents a point-in-time risk assessment for a vendor
|
||||
VendorRiskAssessment struct {
|
||||
ID gid.GID `db:"id"`
|
||||
OrganizationID gid.GID `db:"organization_id"`
|
||||
VendorID gid.GID `db:"vendor_id"`
|
||||
ExpiresAt time.Time `db:"expires_at"`
|
||||
DataSensitivity DataSensitivity `db:"data_sensitivity"`
|
||||
@@ -66,6 +67,7 @@ INSERT INTO
|
||||
vendor_risk_assessments (
|
||||
tenant_id,
|
||||
id,
|
||||
organization_id,
|
||||
vendor_id,
|
||||
expires_at,
|
||||
data_sensitivity,
|
||||
@@ -77,6 +79,7 @@ INSERT INTO
|
||||
VALUES (
|
||||
@tenant_id,
|
||||
@id,
|
||||
@organization_id,
|
||||
@vendor_id,
|
||||
@expires_at,
|
||||
@data_sensitivity,
|
||||
@@ -90,6 +93,7 @@ VALUES (
|
||||
args := pgx.StrictNamedArgs{
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"id": r.ID,
|
||||
"organization_id": r.OrganizationID,
|
||||
"vendor_id": r.VendorID,
|
||||
"expires_at": r.ExpiresAt,
|
||||
"data_sensitivity": r.DataSensitivity,
|
||||
@@ -112,6 +116,7 @@ func (r *VendorRiskAssessment) LoadByID(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
vendor_id,
|
||||
expires_at,
|
||||
data_sensitivity,
|
||||
@@ -160,6 +165,7 @@ func (r *VendorRiskAssessment) LoadLatestByVendorID(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
vendor_id,
|
||||
expires_at,
|
||||
data_sensitivity,
|
||||
@@ -211,6 +217,7 @@ func (r *VendorRiskAssessments) LoadByVendorID(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
vendor_id,
|
||||
expires_at,
|
||||
data_sensitivity,
|
||||
|
||||
@@ -21,22 +21,23 @@ import (
|
||||
"maps"
|
||||
"time"
|
||||
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"go.gearno.de/kit/pg"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
)
|
||||
|
||||
type (
|
||||
VendorService struct {
|
||||
ID gid.GID `db:"id"`
|
||||
VendorID gid.GID `db:"vendor_id"`
|
||||
Name string `db:"name"`
|
||||
Description *string `db:"description"`
|
||||
SnapshotID *gid.GID `db:"snapshot_id"`
|
||||
SourceID *gid.GID `db:"source_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
ID gid.GID `db:"id"`
|
||||
OrganizationID gid.GID `db:"organization_id"`
|
||||
VendorID gid.GID `db:"vendor_id"`
|
||||
Name string `db:"name"`
|
||||
Description *string `db:"description"`
|
||||
SnapshotID *gid.GID `db:"snapshot_id"`
|
||||
SourceID *gid.GID `db:"source_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
}
|
||||
|
||||
VendorServices []*VendorService
|
||||
@@ -70,6 +71,7 @@ func (vs *VendorService) LoadByID(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
vendor_id,
|
||||
name,
|
||||
description,
|
||||
@@ -120,6 +122,7 @@ func (vs *VendorServices) LoadByVendorID(
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
vendor_id,
|
||||
name,
|
||||
description,
|
||||
@@ -168,6 +171,7 @@ INSERT INTO
|
||||
vendor_services (
|
||||
tenant_id,
|
||||
id,
|
||||
organization_id,
|
||||
vendor_id,
|
||||
name,
|
||||
description,
|
||||
@@ -177,6 +181,7 @@ INSERT INTO
|
||||
VALUES (
|
||||
@tenant_id,
|
||||
@vendor_service_id,
|
||||
@organization_id,
|
||||
@vendor_id,
|
||||
@name,
|
||||
@description,
|
||||
@@ -188,6 +193,7 @@ VALUES (
|
||||
args := pgx.StrictNamedArgs{
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"vendor_service_id": vs.ID,
|
||||
"organization_id": vs.OrganizationID,
|
||||
"vendor_id": vs.VendorID,
|
||||
"name": vs.Name,
|
||||
"description": vs.Description,
|
||||
|
||||
Reference in New Issue
Block a user