Fix e2e tests

Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
Émile Ré
2026-02-18 12:05:53 +04:00
parent b49747f3ba
commit ab5fe8e5e2
30 changed files with 874 additions and 715 deletions

View File

@@ -20,15 +20,14 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.probo.inc/probo/e2e/internal/factory"
"go.probo.inc/probo/e2e/internal/testutil" "go.probo.inc/probo/e2e/internal/testutil"
) )
func TestAsset_Create(t *testing.T) { func TestAsset_Create(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
profileID := factory.CreateUser(owner)
// TODO: right now we need to invite and accept invite to get new profile.
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID()
const query = ` const query = `
mutation($input: CreateAssetInput!) { mutation($input: CreateAssetInput!) {
@@ -71,7 +70,7 @@ func TestAsset_Create(t *testing.T) {
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"name": "Production Database Server", "name": "Production Database Server",
"amount": 5, "amount": 5,
"ownerId": profileID.String(), "ownerId": profileID,
"assetType": "VIRTUAL", "assetType": "VIRTUAL",
"dataTypesStored": "Customer PII, Financial Records", "dataTypesStored": "Customer PII, Financial Records",
}, },
@@ -84,15 +83,14 @@ func TestAsset_Create(t *testing.T) {
assert.Equal(t, 5, asset.Amount) assert.Equal(t, 5, asset.Amount)
assert.Equal(t, "VIRTUAL", asset.AssetType) assert.Equal(t, "VIRTUAL", asset.AssetType)
assert.Equal(t, "Customer PII, Financial Records", asset.DataTypesStored) assert.Equal(t, "Customer PII, Financial Records", asset.DataTypesStored)
assert.Equal(t, profileID.String(), asset.Owner.ID) assert.Equal(t, profileID, asset.Owner.ID)
} }
func TestAsset_Update(t *testing.T) { func TestAsset_Update(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID()
const createQuery = ` const createQuery = `
mutation($input: CreateAssetInput!) { mutation($input: CreateAssetInput!) {
@@ -121,7 +119,7 @@ func TestAsset_Update(t *testing.T) {
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"name": "Test Asset", "name": "Test Asset",
"amount": 10, "amount": 10,
"ownerId": profileID.String(), "ownerId": profileID,
"assetType": "VIRTUAL", "assetType": "VIRTUAL",
"dataTypesStored": "Test data", "dataTypesStored": "Test data",
}, },
@@ -172,8 +170,7 @@ func TestAsset_Delete(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID()
const createQuery = ` const createQuery = `
mutation($input: CreateAssetInput!) { mutation($input: CreateAssetInput!) {
@@ -202,7 +199,7 @@ func TestAsset_Delete(t *testing.T) {
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"name": "Asset to delete", "name": "Asset to delete",
"amount": 1, "amount": 1,
"ownerId": profileID.String(), "ownerId": profileID,
"assetType": "VIRTUAL", "assetType": "VIRTUAL",
"dataTypesStored": "None", "dataTypesStored": "None",
}, },
@@ -237,8 +234,7 @@ func TestAsset_List(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID()
// Create multiple assets // Create multiple assets
for i := 0; i < 3; i++ { for i := 0; i < 3; i++ {
@@ -269,7 +265,7 @@ func TestAsset_List(t *testing.T) {
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"name": fmt.Sprintf("Asset %c", 'A'+i), "name": fmt.Sprintf("Asset %c", 'A'+i),
"amount": i + 1, "amount": i + 1,
"ownerId": profileID.String(), "ownerId": profileID,
"assetType": "VIRTUAL", "assetType": "VIRTUAL",
"dataTypesStored": "Test data", "dataTypesStored": "Test data",
}, },
@@ -324,8 +320,7 @@ func TestAsset_Types(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID()
assetTypes := []string{"PHYSICAL", "VIRTUAL"} assetTypes := []string{"PHYSICAL", "VIRTUAL"}
@@ -360,7 +355,7 @@ func TestAsset_Types(t *testing.T) {
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"name": "Asset " + assetType, "name": "Asset " + assetType,
"amount": 1, "amount": 1,
"ownerId": profileID.String(), "ownerId": profileID,
"assetType": assetType, "assetType": assetType,
"dataTypesStored": "Test data", "dataTypesStored": "Test data",
}, },

View File

@@ -21,14 +21,14 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.probo.inc/probo/e2e/internal/factory"
"go.probo.inc/probo/e2e/internal/testutil" "go.probo.inc/probo/e2e/internal/testutil"
) )
func TestContinualImprovement_Create(t *testing.T) { func TestContinualImprovement_Create(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID()
query := ` query := `
mutation CreateContinualImprovement($input: CreateContinualImprovementInput!) { mutation CreateContinualImprovement($input: CreateContinualImprovementInput!) {
@@ -68,7 +68,7 @@ func TestContinualImprovement_Create(t *testing.T) {
"referenceId": fmt.Sprintf("CI-%d", time.Now().UnixNano()), "referenceId": fmt.Sprintf("CI-%d", time.Now().UnixNano()),
"description": "Improve security training program", "description": "Improve security training program",
"source": "Internal Audit", "source": "Internal Audit",
"ownerId": profileID.String(), "ownerId": profileID,
"status": "OPEN", "status": "OPEN",
"priority": "HIGH", "priority": "HIGH",
}, },
@@ -86,8 +86,7 @@ func TestContinualImprovement_Create(t *testing.T) {
func TestContinualImprovement_Update(t *testing.T) { func TestContinualImprovement_Update(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID()
createQuery := ` createQuery := `
mutation CreateContinualImprovement($input: CreateContinualImprovementInput!) { mutation CreateContinualImprovement($input: CreateContinualImprovementInput!) {
@@ -116,7 +115,7 @@ func TestContinualImprovement_Update(t *testing.T) {
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"referenceId": fmt.Sprintf("CI-UPDATE-%d", time.Now().UnixNano()), "referenceId": fmt.Sprintf("CI-UPDATE-%d", time.Now().UnixNano()),
"description": "Original description", "description": "Original description",
"ownerId": profileID.String(), "ownerId": profileID,
"status": "OPEN", "status": "OPEN",
"priority": "LOW", "priority": "LOW",
}, },
@@ -167,8 +166,7 @@ func TestContinualImprovement_Update(t *testing.T) {
func TestContinualImprovement_Delete(t *testing.T) { func TestContinualImprovement_Delete(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID()
createQuery := ` createQuery := `
mutation CreateContinualImprovement($input: CreateContinualImprovementInput!) { mutation CreateContinualImprovement($input: CreateContinualImprovementInput!) {
@@ -196,7 +194,7 @@ func TestContinualImprovement_Delete(t *testing.T) {
"input": map[string]any{ "input": map[string]any{
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"referenceId": fmt.Sprintf("CI-DELETE-%d", time.Now().UnixNano()), "referenceId": fmt.Sprintf("CI-DELETE-%d", time.Now().UnixNano()),
"ownerId": profileID.String(), "ownerId": profileID,
"status": "OPEN", "status": "OPEN",
"priority": "LOW", "priority": "LOW",
}, },
@@ -230,8 +228,7 @@ func TestContinualImprovement_Delete(t *testing.T) {
func TestContinualImprovement_List(t *testing.T) { func TestContinualImprovement_List(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID()
createQuery := ` createQuery := `
mutation CreateContinualImprovement($input: CreateContinualImprovementInput!) { mutation CreateContinualImprovement($input: CreateContinualImprovementInput!) {
@@ -251,7 +248,7 @@ func TestContinualImprovement_List(t *testing.T) {
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"referenceId": fmt.Sprintf("CI-LIST-%d-%d", i, time.Now().UnixNano()), "referenceId": fmt.Sprintf("CI-LIST-%d-%d", i, time.Now().UnixNano()),
"description": fmt.Sprintf("Improvement %d", i), "description": fmt.Sprintf("Improvement %d", i),
"ownerId": profileID.String(), "ownerId": profileID,
"status": "OPEN", "status": "OPEN",
"priority": "MEDIUM", "priority": "MEDIUM",
}, },
@@ -305,8 +302,7 @@ func TestContinualImprovement_List(t *testing.T) {
func TestContinualImprovement_StatusAndPriorityValues(t *testing.T) { func TestContinualImprovement_StatusAndPriorityValues(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID()
t.Run("status values", func(t *testing.T) { t.Run("status values", func(t *testing.T) {
statuses := []string{"OPEN", "IN_PROGRESS", "CLOSED"} statuses := []string{"OPEN", "IN_PROGRESS", "CLOSED"}
@@ -341,7 +337,7 @@ func TestContinualImprovement_StatusAndPriorityValues(t *testing.T) {
"input": map[string]any{ "input": map[string]any{
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"referenceId": fmt.Sprintf("CI-STATUS-%s-%d", status, time.Now().UnixNano()), "referenceId": fmt.Sprintf("CI-STATUS-%s-%d", status, time.Now().UnixNano()),
"ownerId": profileID.String(), "ownerId": profileID,
"status": status, "status": status,
"priority": "LOW", "priority": "LOW",
}, },
@@ -385,7 +381,7 @@ func TestContinualImprovement_StatusAndPriorityValues(t *testing.T) {
"input": map[string]any{ "input": map[string]any{
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"referenceId": fmt.Sprintf("CI-PRIORITY-%s-%d", priority, time.Now().UnixNano()), "referenceId": fmt.Sprintf("CI-PRIORITY-%s-%d", priority, time.Now().UnixNano()),
"ownerId": profileID.String(), "ownerId": profileID,
"status": "OPEN", "status": "OPEN",
"priority": priority, "priority": priority,
}, },

View File

@@ -29,8 +29,7 @@ import (
func TestDatum_Create(t *testing.T) { func TestDatum_Create(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID()
tests := []struct { tests := []struct {
name string name string
@@ -103,7 +102,7 @@ func TestDatum_Create(t *testing.T) {
input := map[string]any{ input := map[string]any{
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"ownerId": profileID.String(), "ownerId": profileID,
} }
for k, v := range tt.input { for k, v := range tt.input {
input[k] = v input[k] = v
@@ -140,8 +139,7 @@ func TestDatum_Create(t *testing.T) {
func TestDatum_Create_Validation(t *testing.T) { func TestDatum_Create_Validation(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID()
tests := []struct { tests := []struct {
name string name string
@@ -277,8 +275,7 @@ func TestDatum_Create_Validation(t *testing.T) {
func TestDatum_Update(t *testing.T) { func TestDatum_Update(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID()
tests := []struct { tests := []struct {
name string name string
@@ -290,7 +287,7 @@ func TestDatum_Update(t *testing.T) {
{ {
name: "update name", name: "update name",
setup: func() string { setup: func() string {
return factory.NewDatum(owner, profileID.String()). return factory.NewDatum(owner, profileID).
WithName("Datum to Update"). WithName("Datum to Update").
Create() Create()
}, },
@@ -306,7 +303,7 @@ func TestDatum_Update(t *testing.T) {
{ {
name: "update to PUBLIC classification", name: "update to PUBLIC classification",
setup: func() string { setup: func() string {
return factory.NewDatum(owner, profileID.String()). return factory.NewDatum(owner, profileID).
WithName("Classification Test"). WithName("Classification Test").
WithDataClassification("INTERNAL"). WithDataClassification("INTERNAL").
Create() Create()
@@ -320,7 +317,7 @@ func TestDatum_Update(t *testing.T) {
{ {
name: "update to SECRET classification", name: "update to SECRET classification",
setup: func() string { setup: func() string {
return factory.NewDatum(owner, profileID.String()). return factory.NewDatum(owner, profileID).
WithName("Classification Test"). WithName("Classification Test").
Create() Create()
}, },
@@ -375,9 +372,8 @@ func TestDatum_Update(t *testing.T) {
func TestDatum_Update_Validation(t *testing.T) { func TestDatum_Update_Validation(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() baseDatumID := factory.NewDatum(owner, profileID).WithName("Validation Test Datum").Create()
baseDatumID := factory.NewDatum(owner, profileID.String()).WithName("Validation Test Datum").Create()
tests := []struct { tests := []struct {
name string name string
@@ -491,11 +487,10 @@ func TestDatum_Update_Validation(t *testing.T) {
func TestDatum_Delete(t *testing.T) { func TestDatum_Delete(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID()
t.Run("delete existing datum", func(t *testing.T) { t.Run("delete existing datum", func(t *testing.T) {
datumID := factory.NewDatum(owner, profileID.String()).WithName("Datum to Delete").Create() datumID := factory.NewDatum(owner, profileID).WithName("Datum to Delete").Create()
query := ` query := `
mutation DeleteDatum($input: DeleteDatumInput!) { mutation DeleteDatum($input: DeleteDatumInput!) {
@@ -557,12 +552,11 @@ func TestDatum_Delete_Validation(t *testing.T) {
func TestDatum_List(t *testing.T) { func TestDatum_List(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID()
datumNames := []string{"Datum A", "Datum B", "Datum C"} datumNames := []string{"Datum A", "Datum B", "Datum C"}
for _, name := range datumNames { for _, name := range datumNames {
factory.NewDatum(owner, profileID.String()).WithName(name).Create() factory.NewDatum(owner, profileID).WithName(name).Create()
} }
query := ` query := `
@@ -630,8 +624,7 @@ func TestDatum_Query(t *testing.T) {
func TestDatum_Timestamps(t *testing.T) { func TestDatum_Timestamps(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID()
t.Run("createdAt and updatedAt are set on create", func(t *testing.T) { t.Run("createdAt and updatedAt are set on create", func(t *testing.T) {
beforeCreate := time.Now().Add(-time.Second) beforeCreate := time.Now().Add(-time.Second)
@@ -665,7 +658,7 @@ func TestDatum_Timestamps(t *testing.T) {
err := owner.Execute(query, map[string]any{ err := owner.Execute(query, map[string]any{
"input": map[string]any{ "input": map[string]any{
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"ownerId": profileID.String(), "ownerId": profileID,
"name": "Timestamp Test Datum", "name": "Timestamp Test Datum",
"dataClassification": "INTERNAL", "dataClassification": "INTERNAL",
}, },
@@ -677,7 +670,7 @@ func TestDatum_Timestamps(t *testing.T) {
}) })
t.Run("updatedAt changes on update", func(t *testing.T) { t.Run("updatedAt changes on update", func(t *testing.T) {
datumID := factory.NewDatum(owner, profileID.String()).WithName("Timestamp Update Test").Create() datumID := factory.NewDatum(owner, profileID).WithName("Timestamp Update Test").Create()
getQuery := ` getQuery := `
query($id: ID!) { query($id: ID!) {
@@ -741,9 +734,8 @@ func TestDatum_Timestamps(t *testing.T) {
func TestDatum_SubResolvers(t *testing.T) { func TestDatum_SubResolvers(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() datumID := factory.NewDatum(owner, profileID).WithName("SubResolver Test Datum").Create()
datumID := factory.NewDatum(owner, profileID.String()).WithName("SubResolver Test Datum").Create()
t.Run("owner sub-resolver", func(t *testing.T) { t.Run("owner sub-resolver", func(t *testing.T) {
query := ` query := `
@@ -772,7 +764,7 @@ func TestDatum_SubResolvers(t *testing.T) {
err := owner.Execute(query, map[string]any{"id": datumID}, &result) err := owner.Execute(query, map[string]any{"id": datumID}, &result)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, profileID.String(), result.Node.Owner.ID) assert.Equal(t, profileID, result.Node.Owner.ID)
}) })
t.Run("organization sub-resolver", func(t *testing.T) { t.Run("organization sub-resolver", func(t *testing.T) {
@@ -813,8 +805,7 @@ func TestDatum_RBAC(t *testing.T) {
t.Run("create", func(t *testing.T) { t.Run("create", func(t *testing.T) {
t.Run("owner can create", func(t *testing.T) { t.Run("owner can create", func(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID()
_, err := owner.Do(` _, err := owner.Do(`
mutation CreateDatum($input: CreateDatumInput!) { mutation CreateDatum($input: CreateDatumInput!) {
@@ -825,7 +816,7 @@ func TestDatum_RBAC(t *testing.T) {
`, map[string]any{ `, map[string]any{
"input": map[string]any{ "input": map[string]any{
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"ownerId": profileID.String(), "ownerId": profileID,
"name": "RBAC Test Datum", "name": "RBAC Test Datum",
"dataClassification": "INTERNAL", "dataClassification": "INTERNAL",
}, },
@@ -836,8 +827,7 @@ func TestDatum_RBAC(t *testing.T) {
t.Run("admin can create", func(t *testing.T) { t.Run("admin can create", func(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
admin := testutil.NewClientInOrg(t, testutil.RoleAdmin, owner) admin := testutil.NewClientInOrg(t, testutil.RoleAdmin, owner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID()
_, err := admin.Do(` _, err := admin.Do(`
mutation CreateDatum($input: CreateDatumInput!) { mutation CreateDatum($input: CreateDatumInput!) {
@@ -848,7 +838,7 @@ func TestDatum_RBAC(t *testing.T) {
`, map[string]any{ `, map[string]any{
"input": map[string]any{ "input": map[string]any{
"organizationId": admin.GetOrganizationID().String(), "organizationId": admin.GetOrganizationID().String(),
"ownerId": profileID.String(), "ownerId": profileID,
"name": "RBAC Test Datum", "name": "RBAC Test Datum",
"dataClassification": "INTERNAL", "dataClassification": "INTERNAL",
}, },
@@ -859,8 +849,7 @@ func TestDatum_RBAC(t *testing.T) {
t.Run("viewer cannot create", func(t *testing.T) { t.Run("viewer cannot create", func(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
viewer := testutil.NewClientInOrg(t, testutil.RoleViewer, owner) viewer := testutil.NewClientInOrg(t, testutil.RoleViewer, owner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID()
_, err := viewer.Do(` _, err := viewer.Do(`
mutation CreateDatum($input: CreateDatumInput!) { mutation CreateDatum($input: CreateDatumInput!) {
@@ -871,7 +860,7 @@ func TestDatum_RBAC(t *testing.T) {
`, map[string]any{ `, map[string]any{
"input": map[string]any{ "input": map[string]any{
"organizationId": viewer.GetOrganizationID().String(), "organizationId": viewer.GetOrganizationID().String(),
"ownerId": profileID.String(), "ownerId": profileID,
"name": "RBAC Test Datum", "name": "RBAC Test Datum",
"dataClassification": "INTERNAL", "dataClassification": "INTERNAL",
}, },
@@ -883,9 +872,8 @@ func TestDatum_RBAC(t *testing.T) {
t.Run("update", func(t *testing.T) { t.Run("update", func(t *testing.T) {
t.Run("owner can update", func(t *testing.T) { t.Run("owner can update", func(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() datumID := factory.NewDatum(owner, profileID).WithName("RBAC Update Test").Create()
datumID := factory.NewDatum(owner, profileID.String()).WithName("RBAC Update Test").Create()
_, err := owner.Do(` _, err := owner.Do(`
mutation UpdateDatum($input: UpdateDatumInput!) { mutation UpdateDatum($input: UpdateDatumInput!) {
@@ -905,9 +893,8 @@ func TestDatum_RBAC(t *testing.T) {
t.Run("admin can update", func(t *testing.T) { t.Run("admin can update", func(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
admin := testutil.NewClientInOrg(t, testutil.RoleAdmin, owner) admin := testutil.NewClientInOrg(t, testutil.RoleAdmin, owner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() datumID := factory.NewDatum(owner, profileID).WithName("RBAC Update Test").Create()
datumID := factory.NewDatum(owner, profileID.String()).WithName("RBAC Update Test").Create()
_, err := admin.Do(` _, err := admin.Do(`
mutation UpdateDatum($input: UpdateDatumInput!) { mutation UpdateDatum($input: UpdateDatumInput!) {
@@ -927,9 +914,8 @@ func TestDatum_RBAC(t *testing.T) {
t.Run("viewer cannot update", func(t *testing.T) { t.Run("viewer cannot update", func(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
viewer := testutil.NewClientInOrg(t, testutil.RoleViewer, owner) viewer := testutil.NewClientInOrg(t, testutil.RoleViewer, owner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() datumID := factory.NewDatum(owner, profileID).WithName("RBAC Update Test").Create()
datumID := factory.NewDatum(owner, profileID.String()).WithName("RBAC Update Test").Create()
_, err := viewer.Do(` _, err := viewer.Do(`
mutation UpdateDatum($input: UpdateDatumInput!) { mutation UpdateDatum($input: UpdateDatumInput!) {
@@ -950,9 +936,8 @@ func TestDatum_RBAC(t *testing.T) {
t.Run("delete", func(t *testing.T) { t.Run("delete", func(t *testing.T) {
t.Run("owner can delete", func(t *testing.T) { t.Run("owner can delete", func(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() datumID := factory.NewDatum(owner, profileID).WithName("RBAC Delete Test").Create()
datumID := factory.NewDatum(owner, profileID.String()).WithName("RBAC Delete Test").Create()
_, err := owner.Do(` _, err := owner.Do(`
mutation DeleteDatum($input: DeleteDatumInput!) { mutation DeleteDatum($input: DeleteDatumInput!) {
@@ -969,9 +954,8 @@ func TestDatum_RBAC(t *testing.T) {
t.Run("admin can delete", func(t *testing.T) { t.Run("admin can delete", func(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
admin := testutil.NewClientInOrg(t, testutil.RoleAdmin, owner) admin := testutil.NewClientInOrg(t, testutil.RoleAdmin, owner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() datumID := factory.NewDatum(owner, profileID).WithName("RBAC Delete Test").Create()
datumID := factory.NewDatum(owner, profileID.String()).WithName("RBAC Delete Test").Create()
_, err := admin.Do(` _, err := admin.Do(`
mutation DeleteDatum($input: DeleteDatumInput!) { mutation DeleteDatum($input: DeleteDatumInput!) {
@@ -988,9 +972,8 @@ func TestDatum_RBAC(t *testing.T) {
t.Run("viewer cannot delete", func(t *testing.T) { t.Run("viewer cannot delete", func(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
viewer := testutil.NewClientInOrg(t, testutil.RoleViewer, owner) viewer := testutil.NewClientInOrg(t, testutil.RoleViewer, owner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() datumID := factory.NewDatum(owner, profileID).WithName("RBAC Delete Test").Create()
datumID := factory.NewDatum(owner, profileID.String()).WithName("RBAC Delete Test").Create()
_, err := viewer.Do(` _, err := viewer.Do(`
mutation DeleteDatum($input: DeleteDatumInput!) { mutation DeleteDatum($input: DeleteDatumInput!) {
@@ -1008,9 +991,8 @@ func TestDatum_RBAC(t *testing.T) {
t.Run("read", func(t *testing.T) { t.Run("read", func(t *testing.T) {
t.Run("owner can read", func(t *testing.T) { t.Run("owner can read", func(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() datumID := factory.NewDatum(owner, profileID).WithName("RBAC Read Test").Create()
datumID := factory.NewDatum(owner, profileID.String()).WithName("RBAC Read Test").Create()
var result struct { var result struct {
Node *struct { Node *struct {
@@ -1033,9 +1015,8 @@ func TestDatum_RBAC(t *testing.T) {
t.Run("admin can read", func(t *testing.T) { t.Run("admin can read", func(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
admin := testutil.NewClientInOrg(t, testutil.RoleAdmin, owner) admin := testutil.NewClientInOrg(t, testutil.RoleAdmin, owner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() datumID := factory.NewDatum(owner, profileID).WithName("RBAC Read Test").Create()
datumID := factory.NewDatum(owner, profileID.String()).WithName("RBAC Read Test").Create()
var result struct { var result struct {
Node *struct { Node *struct {
@@ -1058,9 +1039,8 @@ func TestDatum_RBAC(t *testing.T) {
t.Run("viewer can read", func(t *testing.T) { t.Run("viewer can read", func(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
viewer := testutil.NewClientInOrg(t, testutil.RoleViewer, owner) viewer := testutil.NewClientInOrg(t, testutil.RoleViewer, owner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() datumID := factory.NewDatum(owner, profileID).WithName("RBAC Read Test").Create()
datumID := factory.NewDatum(owner, profileID.String()).WithName("RBAC Read Test").Create()
var result struct { var result struct {
Node *struct { Node *struct {
@@ -1085,8 +1065,7 @@ func TestDatum_RBAC(t *testing.T) {
func TestDatum_MaxLength_Validation(t *testing.T) { func TestDatum_MaxLength_Validation(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID()
longName := strings.Repeat("a", 1001) longName := strings.Repeat("a", 1001)
@@ -1104,7 +1083,7 @@ func TestDatum_MaxLength_Validation(t *testing.T) {
_, err := owner.Do(query, map[string]any{ _, err := owner.Do(query, map[string]any{
"input": map[string]any{ "input": map[string]any{
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"ownerId": profileID.String(), "ownerId": profileID,
"name": longName, "name": longName,
"dataClassification": "INTERNAL", "dataClassification": "INTERNAL",
}, },
@@ -1114,7 +1093,7 @@ func TestDatum_MaxLength_Validation(t *testing.T) {
}) })
t.Run("update", func(t *testing.T) { t.Run("update", func(t *testing.T) {
datumID := factory.NewDatum(owner, profileID.String()).WithName("Max Length Test").Create() datumID := factory.NewDatum(owner, profileID).WithName("Max Length Test").Create()
query := ` query := `
mutation UpdateDatum($input: UpdateDatumInput!) { mutation UpdateDatum($input: UpdateDatumInput!) {
@@ -1138,11 +1117,10 @@ func TestDatum_MaxLength_Validation(t *testing.T) {
func TestDatum_Pagination(t *testing.T) { func TestDatum_Pagination(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID()
for i := 0; i < 5; i++ { for i := 0; i < 5; i++ {
factory.NewDatum(owner, profileID.String()). factory.NewDatum(owner, profileID).
WithName(fmt.Sprintf("Pagination Datum %d", i)). WithName(fmt.Sprintf("Pagination Datum %d", i)).
Create() Create()
} }
@@ -1288,9 +1266,8 @@ func TestDatum_TenantIsolation(t *testing.T) {
org1Owner := testutil.NewClient(t, testutil.RoleOwner) org1Owner := testutil.NewClient(t, testutil.RoleOwner)
org2Owner := testutil.NewClient(t, testutil.RoleOwner) org2Owner := testutil.NewClient(t, testutil.RoleOwner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(org1Owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, org1Owner).GetProfileID() datumID := factory.NewDatum(org1Owner, profileID).WithName("Org1 Datum").Create()
datumID := factory.NewDatum(org1Owner, profileID.String()).WithName("Org1 Datum").Create()
t.Run("cannot read datum from another organization", func(t *testing.T) { t.Run("cannot read datum from another organization", func(t *testing.T) {
query := ` query := `
@@ -1396,11 +1373,10 @@ func TestDatum_TenantIsolation(t *testing.T) {
func TestDatum_Ordering(t *testing.T) { func TestDatum_Ordering(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// TODO: right now we need to invite and accept invite to get new profile. profileID := factory.CreateUser(owner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID()
factory.NewDatum(owner, profileID.String()).WithName("AAA Order Test").Create() factory.NewDatum(owner, profileID).WithName("AAA Order Test").Create()
factory.NewDatum(owner, profileID.String()).WithName("ZZZ Order Test").Create() factory.NewDatum(owner, profileID).WithName("ZZZ Order Test").Create()
t.Run("order by created_at descending", func(t *testing.T) { t.Run("order by created_at descending", func(t *testing.T) {
query := ` query := `

View File

@@ -29,7 +29,7 @@ import (
func TestDocument_Create(t *testing.T) { func TestDocument_Create(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
approverProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() approverProfileID := factory.CreateUser(owner)
tests := []struct { tests := []struct {
name string name string
@@ -113,7 +113,7 @@ func TestDocument_Create(t *testing.T) {
input := map[string]any{ input := map[string]any{
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"approverIds": []string{approverProfileID.String()}, "approverIds": []string{approverProfileID},
} }
for k, v := range tt.input { for k, v := range tt.input {
input[k] = v input[k] = v
@@ -151,7 +151,7 @@ func TestDocument_Create(t *testing.T) {
func TestDocument_Create_Validation(t *testing.T) { func TestDocument_Create_Validation(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
approverProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() approverProfileID := factory.CreateUser(owner)
tests := []struct { tests := []struct {
name string name string
@@ -293,7 +293,7 @@ func TestDocument_Create_Validation(t *testing.T) {
input["organizationId"] = owner.GetOrganizationID().String() input["organizationId"] = owner.GetOrganizationID().String()
} }
if !tt.skipApprover { if !tt.skipApprover {
input["approverIds"] = []string{approverProfileID.String()} input["approverIds"] = []string{approverProfileID}
} }
for k, v := range tt.input { for k, v := range tt.input {
input[k] = v input[k] = v
@@ -309,7 +309,7 @@ func TestDocument_Create_Validation(t *testing.T) {
func TestDocument_Update(t *testing.T) { func TestDocument_Update(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
approverProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() approverProfileID := factory.CreateUser(owner)
tests := []struct { tests := []struct {
name string name string
@@ -321,7 +321,7 @@ func TestDocument_Update(t *testing.T) {
{ {
name: "update title", name: "update title",
setup: func() string { setup: func() string {
return factory.NewDocument(owner, approverProfileID.String()). return factory.NewDocument(owner, approverProfileID).
WithTitle("Document to Update"). WithTitle("Document to Update").
Create() Create()
}, },
@@ -337,7 +337,7 @@ func TestDocument_Update(t *testing.T) {
{ {
name: "update document type", name: "update document type",
setup: func() string { setup: func() string {
return factory.NewDocument(owner, approverProfileID.String()). return factory.NewDocument(owner, approverProfileID).
WithTitle("Type Test"). WithTitle("Type Test").
WithDocumentType("POLICY"). WithDocumentType("POLICY").
Create() Create()
@@ -393,8 +393,8 @@ func TestDocument_Update(t *testing.T) {
func TestDocument_Update_Validation(t *testing.T) { func TestDocument_Update_Validation(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
approverProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() approverProfileID := factory.CreateUser(owner)
baseDocumentID := factory.NewDocument(owner, approverProfileID.String()).WithTitle("Validation Test Document").Create() baseDocumentID := factory.NewDocument(owner, approverProfileID).WithTitle("Validation Test Document").Create()
tests := []struct { tests := []struct {
name string name string
@@ -484,10 +484,10 @@ func TestDocument_Update_Validation(t *testing.T) {
func TestDocument_Delete(t *testing.T) { func TestDocument_Delete(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
approverProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() approverProfileID := factory.CreateUser(owner)
t.Run("delete existing document", func(t *testing.T) { t.Run("delete existing document", func(t *testing.T) {
documentID := factory.NewDocument(owner, approverProfileID.String()).WithTitle("Document to Delete").Create() documentID := factory.NewDocument(owner, approverProfileID).WithTitle("Document to Delete").Create()
query := ` query := `
mutation DeleteDocument($input: DeleteDocumentInput!) { mutation DeleteDocument($input: DeleteDocumentInput!) {
@@ -549,11 +549,11 @@ func TestDocument_Delete_Validation(t *testing.T) {
func TestDocument_List(t *testing.T) { func TestDocument_List(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
approverProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() approverProfileID := factory.CreateUser(owner)
documentTitles := []string{"Document A", "Document B", "Document C"} documentTitles := []string{"Document A", "Document B", "Document C"}
for _, title := range documentTitles { for _, title := range documentTitles {
factory.NewDocument(owner, approverProfileID.String()).WithTitle(title).Create() factory.NewDocument(owner, approverProfileID).WithTitle(title).Create()
} }
query := ` query := `
@@ -621,7 +621,7 @@ func TestDocument_Query(t *testing.T) {
func TestDocument_Timestamps(t *testing.T) { func TestDocument_Timestamps(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
approverProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() approverProfileID := factory.CreateUser(owner)
t.Run("createdAt and updatedAt are set on create", func(t *testing.T) { t.Run("createdAt and updatedAt are set on create", func(t *testing.T) {
beforeCreate := time.Now().Add(-time.Second) beforeCreate := time.Now().Add(-time.Second)
@@ -655,7 +655,7 @@ func TestDocument_Timestamps(t *testing.T) {
err := owner.Execute(query, map[string]any{ err := owner.Execute(query, map[string]any{
"input": map[string]any{ "input": map[string]any{
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"approverIds": []string{approverProfileID.String()}, "approverIds": []string{approverProfileID},
"title": "Timestamp Test Document", "title": "Timestamp Test Document",
"content": "Test content", "content": "Test content",
"documentType": "POLICY", "documentType": "POLICY",
@@ -669,7 +669,7 @@ func TestDocument_Timestamps(t *testing.T) {
}) })
t.Run("updatedAt changes on update", func(t *testing.T) { t.Run("updatedAt changes on update", func(t *testing.T) {
documentID := factory.NewDocument(owner, approverProfileID.String()).WithTitle("Timestamp Update Test").Create() documentID := factory.NewDocument(owner, approverProfileID).WithTitle("Timestamp Update Test").Create()
getQuery := ` getQuery := `
query($id: ID!) { query($id: ID!) {
@@ -733,8 +733,8 @@ func TestDocument_Timestamps(t *testing.T) {
func TestDocument_SubResolvers(t *testing.T) { func TestDocument_SubResolvers(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
approverProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() approverProfileID := factory.CreateUser(owner)
documentID := factory.NewDocument(owner, approverProfileID.String()).WithTitle("SubResolver Test Document").Create() documentID := factory.NewDocument(owner, approverProfileID).WithTitle("SubResolver Test Document").Create()
t.Run("approvers sub-resolver", func(t *testing.T) { t.Run("approvers sub-resolver", func(t *testing.T) {
query := ` query := `
@@ -775,7 +775,7 @@ func TestDocument_SubResolvers(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, 1, result.Node.Approvers.TotalCount) assert.Equal(t, 1, result.Node.Approvers.TotalCount)
require.Len(t, result.Node.Approvers.Edges, 1) require.Len(t, result.Node.Approvers.Edges, 1)
assert.Equal(t, approverProfileID.String(), result.Node.Approvers.Edges[0].Node.ID) assert.Equal(t, approverProfileID, result.Node.Approvers.Edges[0].Node.ID)
}) })
t.Run("organization sub-resolver", func(t *testing.T) { t.Run("organization sub-resolver", func(t *testing.T) {
@@ -816,7 +816,7 @@ func TestDocument_RBAC(t *testing.T) {
t.Run("create", func(t *testing.T) { t.Run("create", func(t *testing.T) {
t.Run("owner can create", func(t *testing.T) { t.Run("owner can create", func(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
approverProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() approverProfileID := factory.CreateUser(owner)
_, err := owner.Do(` _, err := owner.Do(`
mutation CreateDocument($input: CreateDocumentInput!) { mutation CreateDocument($input: CreateDocumentInput!) {
@@ -827,7 +827,7 @@ func TestDocument_RBAC(t *testing.T) {
`, map[string]any{ `, map[string]any{
"input": map[string]any{ "input": map[string]any{
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"approverIds": []string{approverProfileID.String()}, "approverIds": []string{approverProfileID},
"title": "RBAC Test Document", "title": "RBAC Test Document",
"content": "Test content", "content": "Test content",
"documentType": "POLICY", "documentType": "POLICY",
@@ -840,7 +840,7 @@ func TestDocument_RBAC(t *testing.T) {
t.Run("admin can create", func(t *testing.T) { t.Run("admin can create", func(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
admin := testutil.NewClientInOrg(t, testutil.RoleAdmin, owner) admin := testutil.NewClientInOrg(t, testutil.RoleAdmin, owner)
approverProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() approverProfileID := factory.CreateUser(owner)
_, err := admin.Do(` _, err := admin.Do(`
mutation CreateDocument($input: CreateDocumentInput!) { mutation CreateDocument($input: CreateDocumentInput!) {
@@ -851,7 +851,7 @@ func TestDocument_RBAC(t *testing.T) {
`, map[string]any{ `, map[string]any{
"input": map[string]any{ "input": map[string]any{
"organizationId": admin.GetOrganizationID().String(), "organizationId": admin.GetOrganizationID().String(),
"approverIds": []string{approverProfileID.String()}, "approverIds": []string{approverProfileID},
"title": "RBAC Test Document", "title": "RBAC Test Document",
"content": "Test content", "content": "Test content",
"documentType": "POLICY", "documentType": "POLICY",
@@ -864,7 +864,7 @@ func TestDocument_RBAC(t *testing.T) {
t.Run("viewer cannot create", func(t *testing.T) { t.Run("viewer cannot create", func(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
viewer := testutil.NewClientInOrg(t, testutil.RoleViewer, owner) viewer := testutil.NewClientInOrg(t, testutil.RoleViewer, owner)
approverProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() approverProfileID := factory.CreateUser(owner)
_, err := viewer.Do(` _, err := viewer.Do(`
mutation CreateDocument($input: CreateDocumentInput!) { mutation CreateDocument($input: CreateDocumentInput!) {
@@ -875,7 +875,7 @@ func TestDocument_RBAC(t *testing.T) {
`, map[string]any{ `, map[string]any{
"input": map[string]any{ "input": map[string]any{
"organizationId": viewer.GetOrganizationID().String(), "organizationId": viewer.GetOrganizationID().String(),
"approverIds": []string{approverProfileID.String()}, "approverIds": []string{approverProfileID},
"title": "RBAC Test Document", "title": "RBAC Test Document",
"content": "Test content", "content": "Test content",
"documentType": "POLICY", "documentType": "POLICY",
@@ -889,8 +889,8 @@ func TestDocument_RBAC(t *testing.T) {
t.Run("update", func(t *testing.T) { t.Run("update", func(t *testing.T) {
t.Run("owner can update", func(t *testing.T) { t.Run("owner can update", func(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
approverProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() approverProfileID := factory.CreateUser(owner)
documentID := factory.NewDocument(owner, approverProfileID.String()).WithTitle("RBAC Update Test").Create() documentID := factory.NewDocument(owner, approverProfileID).WithTitle("RBAC Update Test").Create()
_, err := owner.Do(` _, err := owner.Do(`
mutation UpdateDocument($input: UpdateDocumentInput!) { mutation UpdateDocument($input: UpdateDocumentInput!) {
@@ -910,8 +910,8 @@ func TestDocument_RBAC(t *testing.T) {
t.Run("admin can update", func(t *testing.T) { t.Run("admin can update", func(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
admin := testutil.NewClientInOrg(t, testutil.RoleAdmin, owner) admin := testutil.NewClientInOrg(t, testutil.RoleAdmin, owner)
approverProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() approverProfileID := factory.CreateUser(owner)
documentID := factory.NewDocument(owner, approverProfileID.String()).WithTitle("RBAC Update Test").Create() documentID := factory.NewDocument(owner, approverProfileID).WithTitle("RBAC Update Test").Create()
_, err := admin.Do(` _, err := admin.Do(`
mutation UpdateDocument($input: UpdateDocumentInput!) { mutation UpdateDocument($input: UpdateDocumentInput!) {
@@ -931,8 +931,8 @@ func TestDocument_RBAC(t *testing.T) {
t.Run("viewer cannot update", func(t *testing.T) { t.Run("viewer cannot update", func(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
viewer := testutil.NewClientInOrg(t, testutil.RoleViewer, owner) viewer := testutil.NewClientInOrg(t, testutil.RoleViewer, owner)
approverProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() approverProfileID := factory.CreateUser(owner)
documentID := factory.NewDocument(owner, approverProfileID.String()).WithTitle("RBAC Update Test").Create() documentID := factory.NewDocument(owner, approverProfileID).WithTitle("RBAC Update Test").Create()
_, err := viewer.Do(` _, err := viewer.Do(`
mutation UpdateDocument($input: UpdateDocumentInput!) { mutation UpdateDocument($input: UpdateDocumentInput!) {
@@ -953,8 +953,8 @@ func TestDocument_RBAC(t *testing.T) {
t.Run("delete", func(t *testing.T) { t.Run("delete", func(t *testing.T) {
t.Run("owner can delete", func(t *testing.T) { t.Run("owner can delete", func(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
approverProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() approverProfileID := factory.CreateUser(owner)
documentID := factory.NewDocument(owner, approverProfileID.String()).WithTitle("RBAC Delete Test").Create() documentID := factory.NewDocument(owner, approverProfileID).WithTitle("RBAC Delete Test").Create()
_, err := owner.Do(` _, err := owner.Do(`
mutation DeleteDocument($input: DeleteDocumentInput!) { mutation DeleteDocument($input: DeleteDocumentInput!) {
@@ -971,8 +971,8 @@ func TestDocument_RBAC(t *testing.T) {
t.Run("admin can delete", func(t *testing.T) { t.Run("admin can delete", func(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
admin := testutil.NewClientInOrg(t, testutil.RoleAdmin, owner) admin := testutil.NewClientInOrg(t, testutil.RoleAdmin, owner)
approverProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() approverProfileID := factory.CreateUser(owner)
documentID := factory.NewDocument(owner, approverProfileID.String()).WithTitle("RBAC Delete Test").Create() documentID := factory.NewDocument(owner, approverProfileID).WithTitle("RBAC Delete Test").Create()
_, err := admin.Do(` _, err := admin.Do(`
mutation DeleteDocument($input: DeleteDocumentInput!) { mutation DeleteDocument($input: DeleteDocumentInput!) {
@@ -989,8 +989,8 @@ func TestDocument_RBAC(t *testing.T) {
t.Run("viewer cannot delete", func(t *testing.T) { t.Run("viewer cannot delete", func(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
viewer := testutil.NewClientInOrg(t, testutil.RoleViewer, owner) viewer := testutil.NewClientInOrg(t, testutil.RoleViewer, owner)
approverProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() approverProfileID := factory.CreateUser(owner)
documentID := factory.NewDocument(owner, approverProfileID.String()).WithTitle("RBAC Delete Test").Create() documentID := factory.NewDocument(owner, approverProfileID).WithTitle("RBAC Delete Test").Create()
_, err := viewer.Do(` _, err := viewer.Do(`
mutation DeleteDocument($input: DeleteDocumentInput!) { mutation DeleteDocument($input: DeleteDocumentInput!) {
@@ -1008,8 +1008,8 @@ func TestDocument_RBAC(t *testing.T) {
t.Run("read", func(t *testing.T) { t.Run("read", func(t *testing.T) {
t.Run("owner can read", func(t *testing.T) { t.Run("owner can read", func(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
approverProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() approverProfileID := factory.CreateUser(owner)
documentID := factory.NewDocument(owner, approverProfileID.String()).WithTitle("RBAC Read Test").Create() documentID := factory.NewDocument(owner, approverProfileID).WithTitle("RBAC Read Test").Create()
var result struct { var result struct {
Node *struct { Node *struct {
@@ -1032,8 +1032,8 @@ func TestDocument_RBAC(t *testing.T) {
t.Run("admin can read", func(t *testing.T) { t.Run("admin can read", func(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
admin := testutil.NewClientInOrg(t, testutil.RoleAdmin, owner) admin := testutil.NewClientInOrg(t, testutil.RoleAdmin, owner)
approverProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() approverProfileID := factory.CreateUser(owner)
documentID := factory.NewDocument(owner, approverProfileID.String()).WithTitle("RBAC Read Test").Create() documentID := factory.NewDocument(owner, approverProfileID).WithTitle("RBAC Read Test").Create()
var result struct { var result struct {
Node *struct { Node *struct {
@@ -1056,8 +1056,8 @@ func TestDocument_RBAC(t *testing.T) {
t.Run("viewer can read", func(t *testing.T) { t.Run("viewer can read", func(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
viewer := testutil.NewClientInOrg(t, testutil.RoleViewer, owner) viewer := testutil.NewClientInOrg(t, testutil.RoleViewer, owner)
approverProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() approverProfileID := factory.CreateUser(owner)
documentID := factory.NewDocument(owner, approverProfileID.String()).WithTitle("RBAC Read Test").Create() documentID := factory.NewDocument(owner, approverProfileID).WithTitle("RBAC Read Test").Create()
var result struct { var result struct {
Node *struct { Node *struct {
@@ -1082,7 +1082,7 @@ func TestDocument_RBAC(t *testing.T) {
func TestDocument_MaxLength_Validation(t *testing.T) { func TestDocument_MaxLength_Validation(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
approverProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() approverProfileID := factory.CreateUser(owner)
longTitle := strings.Repeat("a", 1001) longTitle := strings.Repeat("a", 1001)
@@ -1100,7 +1100,7 @@ func TestDocument_MaxLength_Validation(t *testing.T) {
_, err := owner.Do(query, map[string]any{ _, err := owner.Do(query, map[string]any{
"input": map[string]any{ "input": map[string]any{
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"approverIds": []string{approverProfileID.String()}, "approverIds": []string{approverProfileID},
"title": longTitle, "title": longTitle,
"content": "Test content", "content": "Test content",
"documentType": "POLICY", "documentType": "POLICY",
@@ -1112,7 +1112,7 @@ func TestDocument_MaxLength_Validation(t *testing.T) {
}) })
t.Run("update", func(t *testing.T) { t.Run("update", func(t *testing.T) {
documentID := factory.NewDocument(owner, approverProfileID.String()).WithTitle("Max Length Test").Create() documentID := factory.NewDocument(owner, approverProfileID).WithTitle("Max Length Test").Create()
query := ` query := `
mutation UpdateDocument($input: UpdateDocumentInput!) { mutation UpdateDocument($input: UpdateDocumentInput!) {
@@ -1136,10 +1136,10 @@ func TestDocument_MaxLength_Validation(t *testing.T) {
func TestDocument_Pagination(t *testing.T) { func TestDocument_Pagination(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
approverProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() approverProfileID := factory.CreateUser(owner)
for i := 0; i < 5; i++ { for i := 0; i < 5; i++ {
factory.NewDocument(owner, approverProfileID.String()). factory.NewDocument(owner, approverProfileID).
WithTitle(fmt.Sprintf("Pagination Document %d", i)). WithTitle(fmt.Sprintf("Pagination Document %d", i)).
Create() Create()
} }
@@ -1285,8 +1285,8 @@ func TestDocument_TenantIsolation(t *testing.T) {
org1Owner := testutil.NewClient(t, testutil.RoleOwner) org1Owner := testutil.NewClient(t, testutil.RoleOwner)
org2Owner := testutil.NewClient(t, testutil.RoleOwner) org2Owner := testutil.NewClient(t, testutil.RoleOwner)
approverProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, org1Owner).GetProfileID() approverProfileID := factory.CreateUser(org1Owner)
documentID := factory.NewDocument(org1Owner, approverProfileID.String()).WithTitle("Org1 Document").Create() documentID := factory.NewDocument(org1Owner, approverProfileID).WithTitle("Org1 Document").Create()
t.Run("cannot read document from another organization", func(t *testing.T) { t.Run("cannot read document from another organization", func(t *testing.T) {
query := ` query := `
@@ -1392,10 +1392,10 @@ func TestDocument_TenantIsolation(t *testing.T) {
func TestDocument_Ordering(t *testing.T) { func TestDocument_Ordering(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
approverProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() approverProfileID := factory.CreateUser(owner)
factory.NewDocument(owner, approverProfileID.String()).WithTitle("AAA Order Test").Create() factory.NewDocument(owner, approverProfileID).WithTitle("AAA Order Test").Create()
factory.NewDocument(owner, approverProfileID.String()).WithTitle("ZZZ Order Test").Create() factory.NewDocument(owner, approverProfileID).WithTitle("ZZZ Order Test").Create()
t.Run("order by created_at descending", func(t *testing.T) { t.Run("order by created_at descending", func(t *testing.T) {
query := ` query := `

View File

@@ -19,13 +19,14 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.probo.inc/probo/e2e/internal/factory"
"go.probo.inc/probo/e2e/internal/testutil" "go.probo.inc/probo/e2e/internal/testutil"
) )
// createTestDocument creates a document and returns its ID and the document version ID // createTestDocument creates a document and returns its ID and the document version ID
func createTestDocument(t *testing.T, owner *testutil.Client) (docID string, docVersionID string) { func createTestDocument(t *testing.T, owner *testutil.Client) (docID string, docVersionID string) {
t.Helper() t.Helper()
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() profileID := factory.CreateUser(owner)
query := ` query := `
mutation CreateDocument($input: CreateDocumentInput!) { mutation CreateDocument($input: CreateDocumentInput!) {
@@ -68,7 +69,7 @@ func createTestDocument(t *testing.T, owner *testutil.Client) (docID string, doc
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"title": "Test Document", "title": "Test Document",
"content": "Initial content", "content": "Initial content",
"approverIds": []string{profileID.String()}, "approverIds": []string{profileID},
"documentType": "POLICY", "documentType": "POLICY",
"classification": "INTERNAL", "classification": "INTERNAL",
}, },
@@ -263,7 +264,7 @@ func TestDocumentVersion_RequestSignature(t *testing.T) {
publishedVersionID := publishResult.PublishDocumentVersion.DocumentVersion.ID publishedVersionID := publishResult.PublishDocumentVersion.DocumentVersion.ID
// Create a person to sign // Create a person to sign
signerProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() signerProfileID := factory.CreateUser(owner)
query := ` query := `
mutation RequestSignature($input: RequestSignatureInput!) { mutation RequestSignature($input: RequestSignatureInput!) {
@@ -300,14 +301,14 @@ func TestDocumentVersion_RequestSignature(t *testing.T) {
err = owner.Execute(query, map[string]any{ err = owner.Execute(query, map[string]any{
"input": map[string]any{ "input": map[string]any{
"documentVersionId": publishedVersionID, "documentVersionId": publishedVersionID,
"signatoryId": signerProfileID.String(), "signatoryId": signerProfileID,
}, },
}, &result) }, &result)
require.NoError(t, err) require.NoError(t, err)
assert.NotEmpty(t, result.RequestSignature.DocumentVersionSignatureEdge.Node.ID) assert.NotEmpty(t, result.RequestSignature.DocumentVersionSignatureEdge.Node.ID)
assert.Equal(t, "REQUESTED", result.RequestSignature.DocumentVersionSignatureEdge.Node.State) assert.Equal(t, "REQUESTED", result.RequestSignature.DocumentVersionSignatureEdge.Node.State)
assert.Equal(t, signerProfileID.String(), result.RequestSignature.DocumentVersionSignatureEdge.Node.SignedBy.ID) assert.Equal(t, signerProfileID, result.RequestSignature.DocumentVersionSignatureEdge.Node.SignedBy.ID)
} }
func TestDocumentVersion_BulkPublish(t *testing.T) { func TestDocumentVersion_BulkPublish(t *testing.T) {
@@ -382,8 +383,8 @@ func TestDocumentVersion_BulkRequestSignatures(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
// Create multiple signers // Create multiple signers
signer1ProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() signer1ProfileID := factory.CreateUser(owner)
signer2ProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() signer2ProfileID := factory.CreateUser(owner)
query := ` query := `
mutation BulkRequestSignatures($input: BulkRequestSignaturesInput!) { mutation BulkRequestSignatures($input: BulkRequestSignaturesInput!) {
@@ -412,7 +413,7 @@ func TestDocumentVersion_BulkRequestSignatures(t *testing.T) {
err = owner.Execute(query, map[string]any{ err = owner.Execute(query, map[string]any{
"input": map[string]any{ "input": map[string]any{
"documentIds": []string{docID}, "documentIds": []string{docID},
"signatoryIds": []string{signer1ProfileID.String(), signer2ProfileID.String()}, "signatoryIds": []string{signer1ProfileID, signer2ProfileID},
}, },
}, &result) }, &result)
require.NoError(t, err) require.NoError(t, err)

View File

@@ -19,6 +19,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.probo.inc/probo/e2e/internal/factory"
"go.probo.inc/probo/e2e/internal/testutil" "go.probo.inc/probo/e2e/internal/testutil"
) )
@@ -367,7 +368,7 @@ func TestControlDocumentMapping_CreateDelete(t *testing.T) {
controlID := createControlResult.CreateControl.ControlEdge.Node.ID controlID := createControlResult.CreateControl.ControlEdge.Node.ID
// Create a document // Create a document
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() profileID := factory.CreateUser(owner)
var createDocumentResult struct { var createDocumentResult struct {
CreateDocument struct { CreateDocument struct {
DocumentEdge struct { DocumentEdge struct {
@@ -392,7 +393,7 @@ func TestControlDocumentMapping_CreateDelete(t *testing.T) {
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"title": "Document for Control Mapping", "title": "Document for Control Mapping",
"content": "Document content", "content": "Document content",
"approverIds": []string{profileID.String()}, "approverIds": []string{profileID},
"documentType": "POLICY", "documentType": "POLICY",
"classification": "INTERNAL", "classification": "INTERNAL",
}, },
@@ -755,7 +756,7 @@ func TestRiskDocumentMapping_CreateDelete(t *testing.T) {
riskID := createRiskResult.CreateRisk.RiskEdge.Node.ID riskID := createRiskResult.CreateRisk.RiskEdge.Node.ID
// Create a document // Create a document
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() profileID := factory.CreateUser(owner)
var createDocumentResult struct { var createDocumentResult struct {
CreateDocument struct { CreateDocument struct {
DocumentEdge struct { DocumentEdge struct {
@@ -780,7 +781,7 @@ func TestRiskDocumentMapping_CreateDelete(t *testing.T) {
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"title": "Document for Risk Mapping", "title": "Document for Risk Mapping",
"content": "Document content", "content": "Document content",
"approverIds": []string{profileID.String()}, "approverIds": []string{profileID},
"documentType": "POLICY", "documentType": "POLICY",
"classification": "INTERNAL", "classification": "INTERNAL",
}, },
@@ -869,7 +870,7 @@ func TestRiskObligationMapping_CreateDelete(t *testing.T) {
riskID := createRiskResult.CreateRisk.RiskEdge.Node.ID riskID := createRiskResult.CreateRisk.RiskEdge.Node.ID
// Create an obligation // Create an obligation
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() profileID := factory.CreateUser(owner)
var createObligationResult struct { var createObligationResult struct {
CreateObligation struct { CreateObligation struct {
ObligationEdge struct { ObligationEdge struct {
@@ -894,7 +895,7 @@ func TestRiskObligationMapping_CreateDelete(t *testing.T) {
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"area": "Risk Management", "area": "Risk Management",
"requirement": "Obligation for Risk Mapping", "requirement": "Obligation for Risk Mapping",
"ownerId": profileID.String(), "ownerId": profileID,
"status": "NON_COMPLIANT", "status": "NON_COMPLIANT",
"type": "LEGAL", "type": "LEGAL",
}, },

View File

@@ -690,8 +690,8 @@ func TestMeeting_SubResolvers_WithData(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
attendee1ProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() attendee1ProfileID := factory.CreateUser(owner)
attendee2ProfileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() attendee2ProfileID := factory.CreateUser(owner)
var result struct { var result struct {
CreateMeeting struct { CreateMeeting struct {
@@ -730,7 +730,7 @@ func TestMeeting_SubResolvers_WithData(t *testing.T) {
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"name": "Meeting With Attendees", "name": "Meeting With Attendees",
"date": time.Now().Format(time.RFC3339Nano), "date": time.Now().Format(time.RFC3339Nano),
"attendeeIds": []string{attendee1ProfileID.String(), attendee2ProfileID.String()}, "attendeeIds": []string{attendee1ProfileID, attendee2ProfileID},
}, },
}, &result) }, &result)
require.NoError(t, err) require.NoError(t, err)

View File

@@ -21,6 +21,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.probo.inc/probo/e2e/internal/factory"
"go.probo.inc/probo/e2e/internal/testutil" "go.probo.inc/probo/e2e/internal/testutil"
) )
@@ -99,7 +100,7 @@ func createAuditForNC(t *testing.T, owner *testutil.Client, name string) string
func TestNonconformity_Create(t *testing.T) { func TestNonconformity_Create(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() profileID := factory.CreateUser(owner)
auditID := createAuditForNC(t, owner, "NC Test Audit") auditID := createAuditForNC(t, owner, "NC Test Audit")
query := ` query := `
@@ -142,7 +143,7 @@ func TestNonconformity_Create(t *testing.T) {
"auditId": auditID, "auditId": auditID,
"rootCause": "Insufficient access controls", "rootCause": "Insufficient access controls",
"correctiveAction": "Implement MFA", "correctiveAction": "Implement MFA",
"ownerId": profileID.String(), "ownerId": profileID,
"status": "OPEN", "status": "OPEN",
}, },
}, &result) }, &result)
@@ -158,7 +159,7 @@ func TestNonconformity_Create(t *testing.T) {
func TestNonconformity_Update(t *testing.T) { func TestNonconformity_Update(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() profileID := factory.CreateUser(owner)
auditID := createAuditForNC(t, owner, "NC Update Test Audit") auditID := createAuditForNC(t, owner, "NC Update Test Audit")
// Create a nonconformity to update // Create a nonconformity to update
@@ -190,7 +191,7 @@ func TestNonconformity_Update(t *testing.T) {
"referenceId": fmt.Sprintf("NC-UPDATE-%d", time.Now().UnixNano()), "referenceId": fmt.Sprintf("NC-UPDATE-%d", time.Now().UnixNano()),
"auditId": auditID, "auditId": auditID,
"rootCause": "Original root cause", "rootCause": "Original root cause",
"ownerId": profileID.String(), "ownerId": profileID,
"status": "OPEN", "status": "OPEN",
}, },
}, &createResult) }, &createResult)
@@ -241,7 +242,7 @@ func TestNonconformity_Update(t *testing.T) {
func TestNonconformity_Delete(t *testing.T) { func TestNonconformity_Delete(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() profileID := factory.CreateUser(owner)
auditID := createAuditForNC(t, owner, "NC Delete Test Audit") auditID := createAuditForNC(t, owner, "NC Delete Test Audit")
// Create a nonconformity to delete // Create a nonconformity to delete
@@ -273,7 +274,7 @@ func TestNonconformity_Delete(t *testing.T) {
"referenceId": fmt.Sprintf("NC-DELETE-%d", time.Now().UnixNano()), "referenceId": fmt.Sprintf("NC-DELETE-%d", time.Now().UnixNano()),
"auditId": auditID, "auditId": auditID,
"rootCause": "Test root cause", "rootCause": "Test root cause",
"ownerId": profileID.String(), "ownerId": profileID,
"status": "OPEN", "status": "OPEN",
}, },
}, &createResult) }, &createResult)
@@ -306,7 +307,7 @@ func TestNonconformity_Delete(t *testing.T) {
func TestNonconformity_List(t *testing.T) { func TestNonconformity_List(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() profileID := factory.CreateUser(owner)
auditID := createAuditForNC(t, owner, "NC List Test Audit") auditID := createAuditForNC(t, owner, "NC List Test Audit")
// Create multiple nonconformities // Create multiple nonconformities
@@ -339,7 +340,7 @@ func TestNonconformity_List(t *testing.T) {
"referenceId": fmt.Sprintf("NC-LIST-%d-%d", i, time.Now().UnixNano()), "referenceId": fmt.Sprintf("NC-LIST-%d-%d", i, time.Now().UnixNano()),
"auditId": auditID, "auditId": auditID,
"rootCause": fmt.Sprintf("Root cause %d", i), "rootCause": fmt.Sprintf("Root cause %d", i),
"ownerId": profileID.String(), "ownerId": profileID,
"status": "OPEN", "status": "OPEN",
}, },
}, &createResult) }, &createResult)
@@ -390,7 +391,7 @@ func TestNonconformity_List(t *testing.T) {
func TestNonconformity_StatusValues(t *testing.T) { func TestNonconformity_StatusValues(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() profileID := factory.CreateUser(owner)
auditID := createAuditForNC(t, owner, "NC Status Test Audit") auditID := createAuditForNC(t, owner, "NC Status Test Audit")
statuses := []string{"OPEN", "IN_PROGRESS", "CLOSED"} statuses := []string{"OPEN", "IN_PROGRESS", "CLOSED"}
@@ -427,7 +428,7 @@ func TestNonconformity_StatusValues(t *testing.T) {
"referenceId": fmt.Sprintf("NC-STATUS-%s-%d", status, time.Now().UnixNano()), "referenceId": fmt.Sprintf("NC-STATUS-%s-%d", status, time.Now().UnixNano()),
"auditId": auditID, "auditId": auditID,
"rootCause": "Test root cause", "rootCause": "Test root cause",
"ownerId": profileID.String(), "ownerId": profileID,
"status": status, "status": status,
}, },
}, &result) }, &result)

View File

@@ -19,13 +19,14 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.probo.inc/probo/e2e/internal/factory"
"go.probo.inc/probo/e2e/internal/testutil" "go.probo.inc/probo/e2e/internal/testutil"
) )
func TestObligation_Create(t *testing.T) { func TestObligation_Create(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() profileID := factory.CreateUser(owner)
query := ` query := `
mutation CreateObligation($input: CreateObligationInput!) { mutation CreateObligation($input: CreateObligationInput!) {
@@ -66,7 +67,7 @@ func TestObligation_Create(t *testing.T) {
"source": "GDPR Article 5", "source": "GDPR Article 5",
"requirement": "Data must be processed lawfully", "requirement": "Data must be processed lawfully",
"regulator": "ICO", "regulator": "ICO",
"ownerId": profileID.String(), "ownerId": profileID,
"status": "NON_COMPLIANT", "status": "NON_COMPLIANT",
"type": "LEGAL", "type": "LEGAL",
}, },
@@ -84,7 +85,7 @@ func TestObligation_Create(t *testing.T) {
func TestObligation_Update(t *testing.T) { func TestObligation_Update(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() profileID := factory.CreateUser(owner)
// Create an obligation to update // Create an obligation to update
createQuery := ` createQuery := `
@@ -113,7 +114,7 @@ func TestObligation_Update(t *testing.T) {
"input": map[string]any{ "input": map[string]any{
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"area": "Original Area", "area": "Original Area",
"ownerId": profileID.String(), "ownerId": profileID,
"status": "NON_COMPLIANT", "status": "NON_COMPLIANT",
"type": "LEGAL", "type": "LEGAL",
}, },
@@ -161,7 +162,7 @@ func TestObligation_Update(t *testing.T) {
func TestObligation_Delete(t *testing.T) { func TestObligation_Delete(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() profileID := factory.CreateUser(owner)
// Create an obligation to delete // Create an obligation to delete
createQuery := ` createQuery := `
@@ -190,7 +191,7 @@ func TestObligation_Delete(t *testing.T) {
"input": map[string]any{ "input": map[string]any{
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"area": "Obligation to Delete", "area": "Obligation to Delete",
"ownerId": profileID.String(), "ownerId": profileID,
"status": "NON_COMPLIANT", "status": "NON_COMPLIANT",
"type": "LEGAL", "type": "LEGAL",
}, },
@@ -225,7 +226,7 @@ func TestObligation_Delete(t *testing.T) {
func TestObligation_List(t *testing.T) { func TestObligation_List(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() profileID := factory.CreateUser(owner)
// Create multiple obligations // Create multiple obligations
areas := []string{"Area A", "Area B", "Area C"} areas := []string{"Area A", "Area B", "Area C"}
@@ -256,7 +257,7 @@ func TestObligation_List(t *testing.T) {
"input": map[string]any{ "input": map[string]any{
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"area": area, "area": area,
"ownerId": profileID.String(), "ownerId": profileID,
"status": "NON_COMPLIANT", "status": "NON_COMPLIANT",
"type": "LEGAL", "type": "LEGAL",
}, },
@@ -309,7 +310,7 @@ func TestObligation_List(t *testing.T) {
func TestObligation_StatusValues(t *testing.T) { func TestObligation_StatusValues(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() profileID := factory.CreateUser(owner)
statuses := []string{"NON_COMPLIANT", "PARTIALLY_COMPLIANT", "COMPLIANT"} statuses := []string{"NON_COMPLIANT", "PARTIALLY_COMPLIANT", "COMPLIANT"}
@@ -343,7 +344,7 @@ func TestObligation_StatusValues(t *testing.T) {
"input": map[string]any{ "input": map[string]any{
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"area": "Status Test " + status, "area": "Status Test " + status,
"ownerId": profileID.String(), "ownerId": profileID,
"status": status, "status": status,
"type": "LEGAL", "type": "LEGAL",
}, },

View File

@@ -221,11 +221,11 @@ const (
} }
}` }`
listMembersQuery = ` listUsersQuery = `
query GetMembers($id: ID!) { query GetProfiles($id: ID!) {
node(id: $id) { node(id: $id) {
... on Organization { ... on Organization {
members(first: 10) { totalCount } profiles(first: 10) { totalCount }
} }
} }
}` }`
@@ -1063,10 +1063,10 @@ func TestRBAC(t *testing.T) {
useConnect: true, useConnect: true,
}, },
{ {
name: "owner can list members", name: "owner can list users",
role: "owner", role: "owner",
client: owner, client: owner,
query: listMembersQuery, query: listUsersQuery,
variables: func() map[string]any { variables: func() map[string]any {
return map[string]any{"id": owner.GetOrganizationID().String()} return map[string]any{"id": owner.GetOrganizationID().String()}
}, },
@@ -1074,10 +1074,10 @@ func TestRBAC(t *testing.T) {
useConnect: true, useConnect: true,
}, },
{ {
name: "admin can list members", name: "admin can list users",
role: "admin", role: "admin",
client: admin, client: admin,
query: listMembersQuery, query: listUsersQuery,
variables: func() map[string]any { variables: func() map[string]any {
return map[string]any{"id": owner.GetOrganizationID().String()} return map[string]any{"id": owner.GetOrganizationID().String()}
}, },
@@ -1085,10 +1085,10 @@ func TestRBAC(t *testing.T) {
useConnect: true, useConnect: true,
}, },
{ {
name: "viewer can list members", name: "viewer can list users",
role: "viewer", role: "viewer",
client: viewer, client: viewer,
query: listMembersQuery, query: listUsersQuery,
variables: func() map[string]any { variables: func() map[string]any {
return map[string]any{"id": owner.GetOrganizationID().String()} return map[string]any{"id": owner.GetOrganizationID().String()}
}, },

View File

@@ -881,7 +881,7 @@ func TestRisk_OmittableOwner(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// Create a people for owner assignment // Create a people for owner assignment
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() profileID := factory.CreateUser(owner)
riskID := factory.NewRisk(owner).WithName("Owner Test Risk").Create() riskID := factory.NewRisk(owner).WithName("Owner Test Risk").Create()
t.Run("set owner", func(t *testing.T) { t.Run("set owner", func(t *testing.T) {
@@ -914,11 +914,11 @@ func TestRisk_OmittableOwner(t *testing.T) {
err := owner.Execute(query, map[string]any{ err := owner.Execute(query, map[string]any{
"input": map[string]any{ "input": map[string]any{
"id": riskID, "id": riskID,
"ownerId": profileID.String(), "ownerId": profileID,
}, },
}, &result) }, &result)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, profileID.String(), result.UpdateRisk.Risk.Owner.ID) assert.Equal(t, profileID, result.UpdateRisk.Risk.Owner.ID)
}) })
t.Run("clear owner with null", func(t *testing.T) { t.Run("clear owner with null", func(t *testing.T) {

View File

@@ -30,7 +30,7 @@ func TestTask_Assign(t *testing.T) {
// Create measure and task // Create measure and task
measureID := factory.NewMeasure(owner).Create() measureID := factory.NewMeasure(owner).Create()
taskID := factory.NewTask(owner, measureID).Create() taskID := factory.NewTask(owner, measureID).Create()
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() profileID := factory.CreateUser(owner)
query := ` query := `
mutation UpdateTask($input: UpdateTaskInput!) { mutation UpdateTask($input: UpdateTaskInput!) {
@@ -61,13 +61,13 @@ func TestTask_Assign(t *testing.T) {
err := owner.Execute(query, map[string]any{ err := owner.Execute(query, map[string]any{
"input": map[string]any{ "input": map[string]any{
"taskId": taskID, "taskId": taskID,
"assignedToId": profileID.String(), "assignedToId": profileID,
}, },
}, &result) }, &result)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, taskID, result.UpdateTask.Task.ID) assert.Equal(t, taskID, result.UpdateTask.Task.ID)
assert.Equal(t, profileID.String(), result.UpdateTask.Task.AssignedTo.ID) assert.Equal(t, profileID, result.UpdateTask.Task.AssignedTo.ID)
} }
func TestTask_Unassign(t *testing.T) { func TestTask_Unassign(t *testing.T) {
@@ -77,7 +77,7 @@ func TestTask_Unassign(t *testing.T) {
// Create measure, task, people and assign // Create measure, task, people and assign
measureID := factory.NewMeasure(owner).Create() measureID := factory.NewMeasure(owner).Create()
taskID := factory.NewTask(owner, measureID).Create() taskID := factory.NewTask(owner, measureID).Create()
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() profileID := factory.CreateUser(owner)
// First assign the task // First assign the task
assignQuery := ` assignQuery := `
@@ -93,7 +93,7 @@ func TestTask_Unassign(t *testing.T) {
_, err := owner.Do(assignQuery, map[string]any{ _, err := owner.Do(assignQuery, map[string]any{
"input": map[string]any{ "input": map[string]any{
"taskId": taskID, "taskId": taskID,
"assignedToId": profileID.String(), "assignedToId": profileID,
}, },
}) })
require.NoError(t, err) require.NoError(t, err)

View File

@@ -650,7 +650,7 @@ func TestTask_OmittableAssignee(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// Create a profile for assignee // Create a profile for assignee
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() profileID := factory.CreateUser(owner)
measureID := factory.NewMeasure(owner). measureID := factory.NewMeasure(owner).
WithName("Task Assignee Test"). WithName("Task Assignee Test").
Create() Create()
@@ -689,11 +689,11 @@ func TestTask_OmittableAssignee(t *testing.T) {
err := owner.Execute(query, map[string]any{ err := owner.Execute(query, map[string]any{
"input": map[string]any{ "input": map[string]any{
"taskId": taskID, "taskId": taskID,
"assignedToId": profileID.String(), "assignedToId": profileID,
}, },
}, &result) }, &result)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, profileID.String(), result.UpdateTask.Task.AssignedTo.ID) assert.Equal(t, profileID, result.UpdateTask.Task.AssignedTo.ID)
}) })
t.Run("clear assignee", func(t *testing.T) { t.Run("clear assignee", func(t *testing.T) {

View File

@@ -57,7 +57,7 @@ probod:
smtp: smtp:
addr: "localhost:1025" addr: "localhost:1025"
tls-required: false tls-required: false
mailer-interval: 60 mailer-interval: 1
slack: slack:
sender-interval: 60 sender-interval: 60

View File

@@ -15,32 +15,32 @@
package console_test package console_test
import ( import (
"fmt"
"testing" "testing"
"time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.probo.inc/probo/e2e/internal/testutil" "go.probo.inc/probo/e2e/internal/testutil"
) )
func TestMember_UpdateMembership(t *testing.T) { func TestUser_UpdateMembership(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// Create an admin to update // Create an admin to update
_ = testutil.NewClientInOrg(t, testutil.RoleAdmin, owner) _ = testutil.NewClientInOrg(t, testutil.RoleAdmin, owner)
// Get the member ID of the admin // Get the user ID of the admin
query := ` query := `
query($id: ID!) { query($id: ID!) {
node(id: $id) { node(id: $id) {
... on Organization { ... on Organization {
members(first: 10) { profiles(first: 10) {
edges { edges {
node { node {
id membership {
role id
role
}
} }
} }
} }
@@ -51,14 +51,16 @@ func TestMember_UpdateMembership(t *testing.T) {
var result struct { var result struct {
Node struct { Node struct {
Members struct { Profiles struct {
Edges []struct { Edges []struct {
Node struct { Node struct {
ID string `json:"id"` Membership struct {
Role string `json:"role"` ID string `json:"id"`
Role string `json:"role"`
} `json:"membership"`
} `json:"node"` } `json:"node"`
} `json:"edges"` } `json:"edges"`
} `json:"members"` } `json:"profiles"`
} `json:"node"` } `json:"node"`
} }
@@ -67,15 +69,15 @@ func TestMember_UpdateMembership(t *testing.T) {
}, &result) }, &result)
require.NoError(t, err) require.NoError(t, err)
// Find the admin member // Find the admin
var adminMemberID string var adminMembershipID string
for _, edge := range result.Node.Members.Edges { for _, edge := range result.Node.Profiles.Edges {
if edge.Node.Role == "ADMIN" { if edge.Node.Membership.Role == "ADMIN" {
adminMemberID = edge.Node.ID adminMembershipID = edge.Node.Membership.ID
break break
} }
} }
require.NotEmpty(t, adminMemberID, "Should find admin member") require.NotEmpty(t, adminMembershipID, "Should find admin member")
// Update the member role to VIEWER // Update the member role to VIEWER
mutation := ` mutation := `
@@ -101,7 +103,7 @@ func TestMember_UpdateMembership(t *testing.T) {
err = owner.ExecuteConnect(mutation, map[string]any{ err = owner.ExecuteConnect(mutation, map[string]any{
"input": map[string]any{ "input": map[string]any{
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"membershipId": adminMemberID, "membershipId": adminMembershipID,
"role": "VIEWER", "role": "VIEWER",
}, },
}, &mutationResult) }, &mutationResult)
@@ -110,24 +112,26 @@ func TestMember_UpdateMembership(t *testing.T) {
assert.Equal(t, "VIEWER", mutationResult.UpdateMembership.Membership.Role) assert.Equal(t, "VIEWER", mutationResult.UpdateMembership.Membership.Role)
} }
func TestMember_RemoveMember(t *testing.T) { func TestUser_RemoveUser(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// Create a member to remove // Create a user to remove
memberToRemove := testutil.NewClientInOrg(t, testutil.RoleViewer, owner) userToRemove := testutil.NewClientInOrg(t, testutil.RoleViewer, owner)
_ = memberToRemove _ = userToRemove
// Get the member ID // Get the user ID
query := ` query := `
query($id: ID!) { query($id: ID!) {
node(id: $id) { node(id: $id) {
... on Organization { ... on Organization {
members(first: 50) { profiles(first: 50) {
edges { edges {
node { node {
id id
role membership {
role
}
} }
} }
} }
@@ -138,14 +142,16 @@ func TestMember_RemoveMember(t *testing.T) {
var result struct { var result struct {
Node struct { Node struct {
Members struct { Profiles struct {
Edges []struct { Edges []struct {
Node struct { Node struct {
ID string `json:"id"` ID string `json:"id"`
Role string `json:"role"` Membership struct {
Role string `json:"role"`
} `json:"membership"`
} `json:"node"` } `json:"node"`
} `json:"edges"` } `json:"edges"`
} `json:"members"` } `json:"profiles"`
} `json:"node"` } `json:"node"`
} }
@@ -154,113 +160,43 @@ func TestMember_RemoveMember(t *testing.T) {
}, &result) }, &result)
require.NoError(t, err) require.NoError(t, err)
// Find a viewer member to remove // Find a viewer user to remove
var memberID string var userID string
for _, edge := range result.Node.Members.Edges { for _, edge := range result.Node.Profiles.Edges {
if edge.Node.Role == "VIEWER" { if edge.Node.Membership.Role == "VIEWER" {
memberID = edge.Node.ID userID = edge.Node.ID
break break
} }
} }
assert.NotEmpty(t, memberID, "Should find viewer member") assert.NotEmpty(t, userID, "Should find viewer member")
// Remove the member // Remove the member
mutation := ` mutation := `
mutation($input: RemoveMemberInput!) { mutation($input: RemoveUserInput!) {
removeMember(input: $input) { removeUser(input: $input) {
deletedMembershipId deletedProfileId
} }
} }
` `
var mutationResult struct { var mutationResult struct {
RemoveMember struct { RemoveUser struct {
DeletedMembershipID string `json:"deletedMembershipId"` DeletedProfileID string `json:"deletedProfileId"`
} `json:"removeMember"` } `json:"removeUser"`
} }
err = owner.ExecuteConnect(mutation, map[string]any{ err = owner.ExecuteConnect(mutation, map[string]any{
"input": map[string]any{ "input": map[string]any{
"organizationId": owner.GetOrganizationID().String(), "organizationId": owner.GetOrganizationID().String(),
"membershipId": memberID, "profileId": userID,
}, },
}, &mutationResult) }, &mutationResult)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, memberID, mutationResult.RemoveMember.DeletedMembershipID) assert.Equal(t, userID, mutationResult.RemoveUser.DeletedProfileID)
} }
func TestInvitation_Delete(t *testing.T) { func TestUser_List(t *testing.T) {
t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner)
// Create an invitation
inviteMutation := `
mutation($input: InviteMemberInput!) {
inviteMember(input: $input) {
invitationEdge {
node {
id
email
status
}
}
}
}
`
var inviteResult struct {
InviteMember struct {
InvitationEdge struct {
Node struct {
ID string `json:"id"`
Email string `json:"email"`
Status string `json:"status"`
} `json:"node"`
} `json:"invitationEdge"`
} `json:"inviteMember"`
}
err := owner.ExecuteConnect(inviteMutation, map[string]any{
"input": map[string]any{
"organizationId": owner.GetOrganizationID().String(),
"email": fmt.Sprintf("invite.delete.%d@example.com", time.Now().UnixNano()),
"fullName": "Test User",
"role": "VIEWER",
},
}, &inviteResult)
require.NoError(t, err)
invitationID := inviteResult.InviteMember.InvitationEdge.Node.ID
assert.NotEmpty(t, invitationID)
// Delete the invitation
deleteMutation := `
mutation($input: DeleteInvitationInput!) {
deleteInvitation(input: $input) {
deletedInvitationId
}
}
`
var deleteResult struct {
DeleteInvitation struct {
DeletedInvitationID string `json:"deletedInvitationId"`
} `json:"deleteInvitation"`
}
err = owner.ExecuteConnect(deleteMutation, map[string]any{
"input": map[string]any{
"organizationId": owner.GetOrganizationID().String(),
"invitationId": invitationID,
},
}, &deleteResult)
require.NoError(t, err)
assert.Equal(t, invitationID, deleteResult.DeleteInvitation.DeletedInvitationID)
}
func TestMember_List(t *testing.T) {
t.Parallel() t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
@@ -272,11 +208,13 @@ func TestMember_List(t *testing.T) {
query($id: ID!) { query($id: ID!) {
node(id: $id) { node(id: $id) {
... on Organization { ... on Organization {
members(first: 10) { profiles(first: 10) {
edges { edges {
node { node {
id id
role membership {
role
}
} }
} }
totalCount totalCount
@@ -288,15 +226,17 @@ func TestMember_List(t *testing.T) {
var result struct { var result struct {
Node struct { Node struct {
Members struct { Profiles struct {
Edges []struct { Edges []struct {
Node struct { Node struct {
ID string `json:"id"` ID string `json:"id"`
Role string `json:"role"` Membership struct {
Role string `json:"role"`
} `json:"membership"`
} `json:"node"` } `json:"node"`
} `json:"edges"` } `json:"edges"`
TotalCount int `json:"totalCount"` TotalCount int `json:"totalCount"`
} `json:"members"` } `json:"profiles"`
} `json:"node"` } `json:"node"`
} }
@@ -305,5 +245,5 @@ func TestMember_List(t *testing.T) {
}, &result) }, &result)
require.NoError(t, err) require.NoError(t, err)
assert.GreaterOrEqual(t, result.Node.Members.TotalCount, 3, "Should have at least 3 members") assert.GreaterOrEqual(t, result.Node.Profiles.TotalCount, 3, "Should have at least 3 members")
} }

View File

@@ -755,7 +755,7 @@ func TestVendor_OmittableBusinessOwner(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// Create a profile for owner assignment // Create a profile for owner assignment
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() profileID := factory.CreateUser(owner)
vendorID := factory.NewVendor(owner). vendorID := factory.NewVendor(owner).
WithName("BusinessOwner Test Vendor"). WithName("BusinessOwner Test Vendor").
Create() Create()
@@ -790,11 +790,11 @@ func TestVendor_OmittableBusinessOwner(t *testing.T) {
err := owner.Execute(query, map[string]any{ err := owner.Execute(query, map[string]any{
"input": map[string]any{ "input": map[string]any{
"id": vendorID, "id": vendorID,
"businessOwnerId": profileID.String(), "businessOwnerId": profileID,
}, },
}, &result) }, &result)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, profileID.String(), result.UpdateVendor.Vendor.BusinessOwner.ID) assert.Equal(t, profileID, result.UpdateVendor.Vendor.BusinessOwner.ID)
}) })
t.Run("clear business owner with null", func(t *testing.T) { t.Run("clear business owner with null", func(t *testing.T) {
@@ -838,7 +838,7 @@ func TestVendor_OmittableSecurityOwner(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner) owner := testutil.NewClient(t, testutil.RoleOwner)
// Create a profile for owner assignment // Create a profile for owner assignment
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID() profileID := factory.CreateUser(owner)
vendorID := factory.NewVendor(owner).WithName("SecurityOwner Test Vendor").Create() vendorID := factory.NewVendor(owner).WithName("SecurityOwner Test Vendor").Create()
t.Run("set security owner", func(t *testing.T) { t.Run("set security owner", func(t *testing.T) {
@@ -871,11 +871,11 @@ func TestVendor_OmittableSecurityOwner(t *testing.T) {
err := owner.Execute(query, map[string]any{ err := owner.Execute(query, map[string]any{
"input": map[string]any{ "input": map[string]any{
"id": vendorID, "id": vendorID,
"securityOwnerId": profileID.String(), "securityOwnerId": profileID,
}, },
}, &result) }, &result)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, profileID.String(), result.UpdateVendor.Vendor.SecurityOwner.ID) assert.Equal(t, profileID, result.UpdateVendor.Vendor.SecurityOwner.ID)
}) })
t.Run("clear security owner with null", func(t *testing.T) { t.Run("clear security owner with null", func(t *testing.T) {

View File

@@ -22,6 +22,7 @@ import (
"github.com/brianvoe/gofakeit/v7" "github.com/brianvoe/gofakeit/v7"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.probo.inc/probo/e2e/internal/testutil" "go.probo.inc/probo/e2e/internal/testutil"
"go.probo.inc/probo/pkg/coredata"
) )
func SafeName(prefix string) string { func SafeName(prefix string) string {
@@ -92,6 +93,52 @@ func (a Attrs) getBool(key string, defaultVal bool) bool {
return defaultVal return defaultVal
} }
func CreateUser(c *testutil.Client, attrs ...Attrs) string {
c.T.Helper()
var a Attrs
if len(attrs) > 0 {
a = attrs[0]
}
const query = `
mutation($input: CreateUserInput!) {
createUser(input: $input) {
profileEdge {
node { id }
}
}
}
`
input := map[string]any{
"organizationId": c.GetOrganizationID(),
"emailAddress": a.getString("emailAddress", SafeEmail()),
"fullName": a.getString("fullName", SafeName("User")),
"role": a.getString("role", "EMPLOYEE"),
"kind": coredata.MembershipProfileKindEmployee.String(),
"additionalEmailAddresses": []string{},
}
if position := a.getStringPtr("position"); position != nil {
input["position"] = *position
}
var result struct {
CreateUser struct {
ProfileEdge struct {
Node struct {
ID string `json:"id"`
} `json:"node"`
} `json:"profileEdge"`
} `json:"createUser"`
}
err := c.ExecuteConnect(query, map[string]any{"input": input}, &result)
require.NoError(c.T, err, "createUser mutation failed")
return result.CreateUser.ProfileEdge.Node.ID
}
func CreateVendor(c *testutil.Client, attrs ...Attrs) string { func CreateVendor(c *testutil.Client, attrs ...Attrs) string {
c.T.Helper() c.T.Helper()

View File

@@ -20,6 +20,7 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"net/http/cookiejar" "net/http/cookiejar"
"net/url"
"testing" "testing"
"time" "time"
@@ -46,9 +47,9 @@ type Client struct {
T testing.TB T testing.TB
httpClient *http.Client httpClient *http.Client
baseURL string baseURL string
mailpitBaseURL string
role TestRole role TestRole
userID gid.GID userID gid.GID
profileID gid.GID
organizationID gid.GID organizationID gid.GID
} }
@@ -59,9 +60,10 @@ func NewClient(t testing.TB, role TestRole) *Client {
require.NoError(t, err, "cannot create cookie jar") require.NoError(t, err, "cannot create cookie jar")
client := &Client{ client := &Client{
T: t, T: t,
baseURL: GetBaseURL(), baseURL: GetBaseURL(),
role: role, mailpitBaseURL: GetMailpitBaseURL(),
role: role,
httpClient: &http.Client{ httpClient: &http.Client{
Jar: jar, Jar: jar,
Timeout: 30 * time.Second, Timeout: 30 * time.Second,
@@ -82,6 +84,7 @@ func NewClientInOrg(t testing.TB, role TestRole, ownerClient *Client) *Client {
client := &Client{ client := &Client{
T: t, T: t,
baseURL: GetBaseURL(), baseURL: GetBaseURL(),
mailpitBaseURL: GetMailpitBaseURL(),
role: role, role: role,
organizationID: ownerClient.organizationID, organizationID: ownerClient.organizationID,
httpClient: &http.Client{ httpClient: &http.Client{
@@ -106,7 +109,7 @@ func (c *Client) setupTestUser() {
// Create organization (this makes the user an OWNER) // Create organization (this makes the user an OWNER)
orgName := fmt.Sprintf("Test Org %s", uniqueID) orgName := fmt.Sprintf("Test Org %s", uniqueID)
c.organizationID, c.profileID = c.createOrganization(orgName) c.organizationID = c.createOrganization(orgName)
// Assume organization session to use console API // Assume organization session to use console API
c.assumeOrganizationSession() c.assumeOrganizationSession()
@@ -127,10 +130,12 @@ func (c *Client) SetupTestUserInOrg(ownerClient *Client) {
c.userID = c.signUp(email, password, fullName) c.userID = c.signUp(email, password, fullName)
// Owner invites user to organization // Owner invites user to organization
invitationID := ownerClient.inviteMember(email, fullName, coredata.MembershipRole(c.role)) profileID := ownerClient.createUser(email, fullName, coredata.MembershipRole(c.role))
ownerClient.inviteUser(profileID)
// New user accepts invitation token := c.getActivationToken(email)
c.profileID = c.acceptInvitation(invitationID)
c.activateUser(token)
// Assume organization session to use console API // Assume organization session to use console API
c.assumeOrganizationSession() c.assumeOrganizationSession()
@@ -168,16 +173,12 @@ func (c *Client) signUp(email, password, fullName string) gid.GID {
return userID return userID
} }
func (c *Client) createOrganization(name string) (gid.GID, gid.GID) { func (c *Client) createOrganization(name string) gid.GID {
const query = ` const query = `
mutation($input: CreateOrganizationInput!) { mutation($input: CreateOrganizationInput!) {
createOrganization(input: $input) { createOrganization(input: $input) {
organization { id } organization { id }
membershipEdge { profile { id }
node {
profile { id }
}
}
} }
} }
` `
@@ -187,14 +188,6 @@ func (c *Client) createOrganization(name string) (gid.GID, gid.GID) {
Organization struct { Organization struct {
ID string `json:"id"` ID string `json:"id"`
} `json:"organization"` } `json:"organization"`
MembershipEdge struct {
Node struct {
ID string `json:"id"`
Profile struct {
ID string `json:"id"`
} `json:"profile"`
} `json:"node"`
} `json:"membershipEdge"`
} `json:"createOrganization"` } `json:"createOrganization"`
} }
@@ -206,10 +199,7 @@ func (c *Client) createOrganization(name string) (gid.GID, gid.GID) {
orgID, err := gid.ParseGID(result.CreateOrganization.Organization.ID) orgID, err := gid.ParseGID(result.CreateOrganization.Organization.ID)
require.NoError(c.T, err, "cannot parse organization ID") require.NoError(c.T, err, "cannot parse organization ID")
profileID, err := gid.ParseGID(result.CreateOrganization.MembershipEdge.Node.Profile.ID) return orgID
require.NoError(c.T, err, "cannot parse profile ID")
return orgID, profileID
} }
func (c *Client) updateOwnMembershipRole(role coredata.MembershipRole) { func (c *Client) updateOwnMembershipRole(role coredata.MembershipRole) {
@@ -284,10 +274,49 @@ func (c *Client) updateOwnMembershipRole(role coredata.MembershipRole) {
require.NoError(c.T, err, "updateMembership mutation failed") require.NoError(c.T, err, "updateMembership mutation failed")
} }
func (c *Client) inviteMember(email, fullName string, role coredata.MembershipRole) gid.GID { func (c *Client) createUser(email, fullName string, role coredata.MembershipRole) gid.GID {
const query = ` const query = `
mutation($input: InviteMemberInput!) { mutation($input: CreateUserInput!) {
inviteMember(input: $input) { createUser(input: $input) {
profileEdge {
node { id }
}
}
}
`
var result struct {
CreateUser struct {
ProfileEdge struct {
Node struct {
ID string `json:"id"`
} `json:"node"`
} `json:"profileEdge"`
} `json:"createUser"`
}
err := c.ExecuteConnect(query, map[string]any{
"input": map[string]any{
"organizationId": c.organizationID.String(),
"emailAddress": email,
"fullName": fullName,
"role": string(role),
"kind": coredata.MembershipProfileKindEmployee,
"additionalEmailAddresses": []string{},
},
}, &result)
require.NoError(c.T, err, "createUser mutation failed")
profileID, err := gid.ParseGID(result.CreateUser.ProfileEdge.Node.ID)
require.NoError(c.T, err, "cannot parse profile ID")
return profileID
}
func (c *Client) inviteUser(profileID gid.GID) {
const query = `
mutation($input: InviteUserInput!) {
inviteUser(input: $input) {
invitationEdge { invitationEdge {
node { id } node { id }
} }
@@ -296,67 +325,79 @@ func (c *Client) inviteMember(email, fullName string, role coredata.MembershipRo
` `
var result struct { var result struct {
InviteMember struct { InviteUser struct {
InvitationEdge struct { InvitationEdge struct {
Node struct { Node struct {
ID string `json:"id"` ID string `json:"id"`
} `json:"node"` } `json:"node"`
} `json:"invitationEdge"` } `json:"invitationEdge"`
} `json:"inviteMember"` } `json:"inviteUser"`
} }
err := c.ExecuteConnect(query, map[string]any{ err := c.ExecuteConnect(query, map[string]any{
"input": map[string]any{ "input": map[string]any{
"organizationId": c.organizationID.String(), "organizationId": c.organizationID.String(),
"email": email, "profileId": profileID.String(),
"fullName": fullName,
"role": string(role),
}, },
}, &result) }, &result)
require.NoError(c.T, err, "inviteMember mutation failed") require.NoError(c.T, err, "inviteUser mutation failed")
invitationID, err := gid.ParseGID(result.InviteMember.InvitationEdge.Node.ID)
require.NoError(c.T, err, "cannot parse invitation ID")
return invitationID
} }
func (c *Client) acceptInvitation(invitationID gid.GID) gid.GID { func (c *Client) getActivationToken(email string) string {
deadline := time.Now().Add(5 * time.Second)
for time.Now().Before(deadline) {
searchMails, err := c.SearchMails(fmt.Sprintf("to:%s subject:\"Invitation to join\"", email))
require.NoError(c.T, err, "mailpit messages search failed")
for _, msg := range searchMails.Messages {
linksCheck, err := c.CheckMessageLinks(msg.ID)
require.NoError(c.T, err, "mailpit link check failed")
for _, link := range linksCheck.Links {
linkURL, err := url.Parse(link.URL)
require.NoError(c.T, err, "mailpit link invalid URL")
query := linkURL.Query()
if query.Get("token") != "" {
return query.Get("token")
}
}
}
time.Sleep(100 * time.Millisecond)
}
c.T.Logf("activation token not found")
c.T.FailNow()
return ""
}
func (c *Client) activateUser(token string) {
const query = ` const query = `
mutation($input: AcceptInvitationInput!) { mutation($input: ActivateAccountInput!) {
acceptInvitation(input: $input) { activateAccount(input: $input) {
membershipEdge { profile {
node { id
profile { id }
}
} }
} }
} }
` `
var result struct { var result struct {
AcceptInvitation struct { ActivateAccount struct {
MembershipEdge struct { Profile struct {
Node struct { ID string `json:"id"`
Profile struct { } `json:"profile"`
ID string `json:"id"` } `json:"activateAccount"`
} `json:"profile"`
} `json:"node"`
} `json:"membershipEdge"`
} `json:"acceptInvitation"`
} }
err := c.ExecuteConnect(query, map[string]any{ err := c.ExecuteConnect(query, map[string]any{
"input": map[string]any{ "input": map[string]any{
"invitationId": invitationID.String(), "token": token,
}, },
}, &result) }, &result)
require.NoError(c.T, err, "acceptInvitation mutation failed") require.NoError(c.T, err, "activateAccount mutation failed")
profileID, err := gid.ParseGID(result.AcceptInvitation.MembershipEdge.Node.Profile.ID)
require.NoError(c.T, err, "cannot parse profile ID")
return profileID
} }
func (c *Client) assumeOrganizationSession() { func (c *Client) assumeOrganizationSession() {
@@ -385,10 +426,6 @@ func (c *Client) GetUserID() gid.GID {
return c.userID return c.userID
} }
func (c *Client) GetProfileID() gid.GID {
return c.profileID
}
func (c *Client) GetOrganizationID() gid.GID { func (c *Client) GetOrganizationID() gid.GID {
return c.organizationID return c.organizationID
} }

View File

@@ -0,0 +1,101 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package testutil
import (
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
)
type (
MailpitMessage struct {
ID string `json:"id"`
}
MailpitSearchResponse struct {
Messages []MailpitMessage `json:"messages"`
}
MailpitLink struct {
URL string `json:"url"`
}
MailpitLinkCheckResponse struct {
Links []MailpitLink `json:"links"`
}
)
func (c *Client) SearchMails(query string) (*MailpitSearchResponse, error) {
req, err := http.NewRequest("GET", c.mailpitBaseURL+"/api/v1/search?query="+url.QueryEscape(query), nil)
if err != nil {
return nil, fmt.Errorf("cannot create request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
defer func() { _ = resp.Body.Close() }()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("cannot read response: %w", err)
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("unexpected status %d: %s", resp.StatusCode, string(respBody))
}
var searchResp MailpitSearchResponse
if err := json.Unmarshal(respBody, &searchResp); err != nil {
return nil, fmt.Errorf("cannot decode response: %w", err)
}
return &searchResp, nil
}
func (c *Client) CheckMessageLinks(messageID string) (*MailpitLinkCheckResponse, error) {
req, err := http.NewRequest("GET", fmt.Sprintf("%s/api/v1/message/%s/link-check", c.mailpitBaseURL, messageID), nil)
if err != nil {
return nil, fmt.Errorf("cannot create request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
defer func() { _ = resp.Body.Close() }()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("cannot read response: %w", err)
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("unexpected status %d: %s", resp.StatusCode, string(respBody))
}
var linkCheckResp MailpitLinkCheckResponse
if err := json.Unmarshal(respBody, &linkCheckResp); err != nil {
return nil, fmt.Errorf("cannot decode response: %w", err)
}
return &linkCheckResp, nil
}

View File

@@ -34,9 +34,10 @@ var (
) )
type TestEnv struct { type TestEnv struct {
BaseURL string MailpitBaseURL string
cmd *exec.Cmd BaseURL string
done chan error cmd *exec.Cmd
done chan error
} }
func Setup() { func Setup() {
@@ -94,18 +95,24 @@ func Setup() {
}() }()
testEnv.BaseURL = "http://localhost:18080" testEnv.BaseURL = "http://localhost:18080"
testEnv.MailpitBaseURL = "http://localhost:8025"
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel() defer cancel()
if err := waitForServer(ctx, testEnv.BaseURL, 30*time.Second); err != nil { if err := waitForServer(ctx, testEnv.BaseURL+"/api/console/v1/graphql", 30*time.Second); err != nil {
fmt.Fprintf(os.Stderr, "e2etest: server failed to start: %v\n", err) fmt.Fprintf(os.Stderr, "e2etest: API server failed to start: %v\n", err)
_ = testEnv.cmd.Process.Kill()
os.Exit(1)
}
if err := waitForServer(ctx, testEnv.MailpitBaseURL+"/api/v1/messages", 30*time.Second); err != nil {
fmt.Fprintf(os.Stderr, "e2etest: MailPit server failed to start: %v\n", err)
_ = testEnv.cmd.Process.Kill() _ = testEnv.cmd.Process.Kill()
os.Exit(1) os.Exit(1)
} }
}) })
} }
func waitForServer(ctx context.Context, baseURL string, timeout time.Duration) error { func waitForServer(ctx context.Context, url string, timeout time.Duration) error {
deadline := time.Now().Add(timeout) deadline := time.Now().Add(timeout)
client := &http.Client{Timeout: 2 * time.Second} client := &http.Client{Timeout: 2 * time.Second}
@@ -116,7 +123,7 @@ func waitForServer(ctx context.Context, baseURL string, timeout time.Duration) e
default: default:
} }
req, err := http.NewRequestWithContext(ctx, "GET", baseURL+"/api/console/v1/graphql", nil) req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil { if err != nil {
return err return err
} }
@@ -157,3 +164,10 @@ func GetBaseURL() string {
} }
return testEnv.BaseURL return testEnv.BaseURL
} }
func GetMailpitBaseURL() string {
if testEnv == nil {
return "http://localhost:8025"
}
return testEnv.MailpitBaseURL
}

View File

@@ -319,7 +319,6 @@ func (p *Presenter) RenderInvitation(ctx context.Context, invitationURLPath stri
MustParse(vars.BaseURL). MustParse(vars.BaseURL).
AppendPath(invitationURLPath). AppendPath(invitationURLPath).
WithQuery("token", invitationToken). WithQuery("token", invitationToken).
WithQuery("fullName", vars.RecipientFullName).
MustString() MustString()
data := struct { data := struct {

View File

@@ -414,6 +414,8 @@ WITH profiles AS (
mp.id, mp.id,
mp.identity_id, mp.identity_id,
mp.organization_id, mp.organization_id,
mp.source,
mp.state,
mp.full_name, mp.full_name,
mp.kind, mp.kind,
mp.additional_email_addresses, mp.additional_email_addresses,
@@ -438,12 +440,15 @@ SELECT
p.identity_id, p.identity_id,
p.organization_id, p.organization_id,
i.email_address, i.email_address,
p.source,
p.state,
p.full_name, p.full_name,
p.kind, p.kind,
p.additional_email_addresses, p.additional_email_addresses,
p.position, p.position,
p.contract_start_date, p.contract_start_date,
p.contract_end_date, p.contract_end_date,
'' AS organization_name,
p.created_at, p.created_at,
p.updated_at p.updated_at
FROM profiles p FROM profiles p
@@ -516,6 +521,8 @@ WITH profiles AS (
mp.identity_id, mp.identity_id,
mp.organization_id, mp.organization_id,
mp.full_name, mp.full_name,
mp.source,
mp.state,
mp.kind, mp.kind,
mp.additional_email_addresses, mp.additional_email_addresses,
mp.position, mp.position,
@@ -539,12 +546,15 @@ SELECT
p.identity_id, p.identity_id,
p.organization_id, p.organization_id,
i.email_address, i.email_address,
p.source,
p.state,
p.full_name, p.full_name,
p.kind, p.kind,
p.additional_email_addresses, p.additional_email_addresses,
p.position, p.position,
p.contract_start_date, p.contract_start_date,
p.contract_end_date, p.contract_end_date,
'' AS organization_name,
p.created_at, p.created_at,
p.updated_at p.updated_at
FROM profiles p FROM profiles p

View File

@@ -184,6 +184,27 @@ WHERE
pi.organization_id = i.organization_id pi.organization_id = i.organization_id
AND pi.email_address = i.email; AND pi.email_address = i.email;
-- Delete orphan invitations: e.g. expired invitations that were never accepted
WITH orphan_invitations AS (
SELECT
inv.id
FROM
iam_invitations inv
LEFT JOIN identities i ON i.email_address = inv.email
LEFT JOIN iam_membership_profiles p ON p.identity_id = i.id
WHERE
i.id IS NULL OR p.id IS NULL
)
DELETE FROM
iam_invitations
WHERE
id IN (
SELECT
id
FROM
orphan_invitations
);
ALTER TABLE ALTER TABLE
iam_invitations iam_invitations
ALTER COLUMN ALTER COLUMN
@@ -197,4 +218,4 @@ ALTER COLUMN
ALTER COLUMN ALTER COLUMN
role DROP NOT NULL, role DROP NOT NULL,
ALTER COLUMN ALTER COLUMN
full_name DROP NOT NULL; full_name DROP NOT NULL;

View File

@@ -52,11 +52,13 @@ const (
ActionMembershipRoleSetOwner = "iam:membership-role:set-owner" ActionMembershipRoleSetOwner = "iam:membership-role:set-owner"
// Membership Profile actions // Membership Profile actions
ActionMembershipProfileGet = "iam:membership-profile:get" ActionMembershipProfileGet = "iam:membership-profile:get"
ActionMembershipProfileList = "iam:membership-profile:list" ActionMembershipProfileList = "iam:membership-profile:list"
ActionMembershipProfileCreate = "iam:membership-profile:create" ActionMembershipProfileCreate = "iam:membership-profile:create"
ActionMembershipProfileUpdate = "iam:membership-profile:update" ActionMembershipProfileUpdate = "iam:membership-profile:update"
ActionMembershipProfileDelete = "iam:membership-profile:delete" ActionMembershipProfileDelete = "iam:membership-profile:delete"
ActionMembershipProfileActivate = "iam:membership-profile:activate"
ActionMembershipProfileDeactivate = "iam:membership-profile:deactivate"
// Personal API Key actions // Personal API Key actions
ActionPersonalAPIKeyCreate = "iam:personal-api-key:create" ActionPersonalAPIKeyCreate = "iam:personal-api-key:create"

View File

@@ -167,6 +167,8 @@ var IAMOwnerPolicy = policy.NewPolicy(
ActionMembershipProfileCreate, ActionMembershipProfileCreate,
ActionMembershipProfileUpdate, ActionMembershipProfileUpdate,
ActionMembershipProfileDelete, ActionMembershipProfileDelete,
ActionMembershipProfileActivate,
ActionMembershipProfileDeactivate,
). ).
WithSID("full-membership-profile-access"). WithSID("full-membership-profile-access").
When(policy.Equals("principal.organization_id", "resource.organization_id")), When(policy.Equals("principal.organization_id", "resource.organization_id")),
@@ -248,6 +250,8 @@ var IAMAdminPolicy = policy.NewPolicy(
ActionMembershipProfileCreate, ActionMembershipProfileCreate,
ActionMembershipProfileUpdate, ActionMembershipProfileUpdate,
ActionMembershipProfileDelete, ActionMembershipProfileDelete,
ActionMembershipProfileActivate,
ActionMembershipProfileDeactivate,
). ).
WithSID("membership-profile-admin-access"). WithSID("membership-profile-admin-access").
When(policy.Equals("principal.organization_id", "resource.organization_id")), When(policy.Equals("principal.organization_id", "resource.organization_id")),

View File

@@ -427,7 +427,7 @@ func (s *OrganizationService) CreateOrganization(
ctx context.Context, ctx context.Context,
identityID gid.GID, identityID gid.GID,
req *CreateOrganizationRequest, req *CreateOrganizationRequest,
) (*coredata.Organization, *coredata.Membership, error) { ) (*coredata.Organization, *coredata.MembershipProfile, error) {
if err := req.Validate(); err != nil { if err := req.Validate(); err != nil {
return nil, nil, fmt.Errorf("invalid request: %w", err) return nil, nil, fmt.Errorf("invalid request: %w", err)
} }
@@ -639,7 +639,7 @@ func (s *OrganizationService) CreateOrganization(
return nil, nil, fmt.Errorf("cannot insert organization: %w", err) return nil, nil, fmt.Errorf("cannot insert organization: %w", err)
} }
return organization, membership, nil return organization, profile, nil
} }
func (s *OrganizationService) UpdateOrganization(ctx context.Context, organizationID gid.GID, req *UpdateOrganizationRequest) (*coredata.Organization, error) { func (s *OrganizationService) UpdateOrganization(ctx context.Context, organizationID gid.GID, req *UpdateOrganizationRequest) (*coredata.Organization, error) {
@@ -973,6 +973,41 @@ func (s *OrganizationService) UpdateUser(ctx context.Context, req *UpdateUserReq
return profile, nil return profile, nil
} }
func (s *OrganizationService) UpdateUserState(
ctx context.Context,
userID gid.GID,
state coredata.ProfileState,
) (*coredata.MembershipProfile, error) {
var (
scope = coredata.NewScopeFromObjectID(userID)
profile = &coredata.MembershipProfile{}
)
err := s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
if err := profile.LoadByID(ctx, conn, scope, userID); err != nil {
return fmt.Errorf("cannot load profile: %w", err)
}
profile.State = state
profile.UpdatedAt = time.Now()
if err := profile.Update(ctx, conn, scope); err != nil {
return fmt.Errorf("cannot update profile: %w", err)
}
return nil
},
)
if err != nil {
return nil, err
}
return profile, nil
}
func (s *OrganizationService) GetProfile(ctx context.Context, profileID gid.GID) (*coredata.MembershipProfile, error) { func (s *OrganizationService) GetProfile(ctx context.Context, profileID gid.GID) (*coredata.MembershipProfile, error) {
profile := &coredata.MembershipProfile{} profile := &coredata.MembershipProfile{}

View File

@@ -55,7 +55,7 @@ type Mutation {
signOut: SignOutPayload @session(required: PRESENT) signOut: SignOutPayload @session(required: PRESENT)
activateAccount( activateAccount(
input: ActivateAccountInput! input: ActivateAccountInput!
): ActivateAccountPayload @session(required: NONE) ): ActivateAccountPayload @session(required: OPTIONAL)
forgotPassword(input: ForgotPasswordInput!): ForgotPasswordPayload forgotPassword(input: ForgotPasswordInput!): ForgotPasswordPayload
@session(required: NONE) @session(required: NONE)
resetPassword(input: ResetPasswordInput!): ResetPasswordPayload resetPassword(input: ResetPasswordInput!): ResetPasswordPayload
@@ -98,6 +98,7 @@ type Mutation {
@session(required: PRESENT) @session(required: PRESENT)
inviteUser(input: InviteUserInput!): InviteUserPayload inviteUser(input: InviteUserInput!): InviteUserPayload
@session(required: PRESENT) @session(required: PRESENT)
deactivateUser(input: DeactivateUserInput!): DeactivateUserPayload
updateUser(input: UpdateUserInput!): UpdateUserPayload! updateUser(input: UpdateUserInput!): UpdateUserPayload!
updateMembership(input: UpdateMembershipInput!): UpdateMembershipPayload! updateMembership(input: UpdateMembershipInput!): UpdateMembershipPayload!
removeUser(input: RemoveUserInput!): RemoveUserPayload removeUser(input: RemoveUserInput!): RemoveUserPayload
@@ -719,6 +720,16 @@ input InviteUserInput {
profileId: ID! profileId: ID!
} }
input ActivateUserInput {
organizationId: ID!
profileId: ID!
}
input DeactivateUserInput {
organizationId: ID!
profileId: ID!
}
input UpdateUserInput { input UpdateUserInput {
id: ID! id: ID!
fullName: String! fullName: String!
@@ -740,15 +751,6 @@ input RemoveUserInput {
profileId: ID! profileId: ID!
} }
input AcceptInvitationInput {
invitationId: ID!
}
input DeleteInvitationInput {
organizationId: ID!
invitationId: ID!
}
input CreateSAMLConfigurationInput { input CreateSAMLConfigurationInput {
organizationId: ID! organizationId: ID!
emailDomain: String! emailDomain: String!
@@ -861,7 +863,7 @@ type RevokePersonalAPIKeyPayload {
type CreateOrganizationPayload { type CreateOrganizationPayload {
organization: Organization organization: Organization
membership: Membership! profile: Profile!
} }
type UpdateOrganizationPayload { type UpdateOrganizationPayload {
@@ -884,6 +886,10 @@ type InviteUserPayload {
invitationEdge: InvitationEdge! invitationEdge: InvitationEdge!
} }
type DeactivateUserPayload {
success: Boolean!
}
type UpdateUserPayload { type UpdateUserPayload {
profile: Profile! profile: Profile!
} }
@@ -896,15 +902,6 @@ type RemoveUserPayload {
deletedProfileId: ID! deletedProfileId: ID!
} }
type AcceptInvitationPayload {
membership: Membership!
invitation: Invitation!
}
type DeleteInvitationPayload {
deletedInvitationId: ID!
}
type CreateSAMLConfigurationPayload { type CreateSAMLConfigurationPayload {
samlConfigurationEdge: SAMLConfigurationEdge! samlConfigurationEdge: SAMLConfigurationEdge!
} }

View File

@@ -74,11 +74,6 @@ type DirectiveRoot struct {
} }
type ComplexityRoot struct { type ComplexityRoot struct {
AcceptInvitationPayload struct {
Invitation func(childComplexity int) int
Membership func(childComplexity int) int
}
ActivateAccountPayload struct { ActivateAccountPayload struct {
CreatePasswordToken func(childComplexity int) int CreatePasswordToken func(childComplexity int) int
Profile func(childComplexity int) int Profile func(childComplexity int) int
@@ -105,8 +100,8 @@ type ComplexityRoot struct {
} }
CreateOrganizationPayload struct { CreateOrganizationPayload struct {
Membership func(childComplexity int) int
Organization func(childComplexity int) int Organization func(childComplexity int) int
Profile func(childComplexity int) int
} }
CreatePersonalAPIKeyPayload struct { CreatePersonalAPIKeyPayload struct {
@@ -128,8 +123,8 @@ type ComplexityRoot struct {
ProfileEdge func(childComplexity int) int ProfileEdge func(childComplexity int) int
} }
DeleteInvitationPayload struct { DeactivateUserPayload struct {
DeletedInvitationID func(childComplexity int) int Success func(childComplexity int) int
} }
DeleteOrganizationHorizontalLogoPayload struct { DeleteOrganizationHorizontalLogoPayload struct {
@@ -209,6 +204,7 @@ type ComplexityRoot struct {
CreateSAMLConfiguration func(childComplexity int, input types.CreateSAMLConfigurationInput) int CreateSAMLConfiguration func(childComplexity int, input types.CreateSAMLConfigurationInput) int
CreateSCIMConfiguration func(childComplexity int, input types.CreateSCIMConfigurationInput) int CreateSCIMConfiguration func(childComplexity int, input types.CreateSCIMConfigurationInput) int
CreateUser func(childComplexity int, input types.CreateUserInput) int CreateUser func(childComplexity int, input types.CreateUserInput) int
DeactivateUser func(childComplexity int, input types.DeactivateUserInput) int
DeleteOrganization func(childComplexity int, input types.DeleteOrganizationInput) int DeleteOrganization func(childComplexity int, input types.DeleteOrganizationInput) int
DeleteOrganizationHorizontalLogo func(childComplexity int, input types.DeleteOrganizationHorizontalLogoInput) int DeleteOrganizationHorizontalLogo func(childComplexity int, input types.DeleteOrganizationHorizontalLogoInput) int
DeleteSAMLConfiguration func(childComplexity int, input types.DeleteSAMLConfigurationInput) int DeleteSAMLConfiguration func(childComplexity int, input types.DeleteSAMLConfigurationInput) int
@@ -539,6 +535,7 @@ type MutationResolver interface {
DeleteOrganizationHorizontalLogo(ctx context.Context, input types.DeleteOrganizationHorizontalLogoInput) (*types.DeleteOrganizationHorizontalLogoPayload, error) DeleteOrganizationHorizontalLogo(ctx context.Context, input types.DeleteOrganizationHorizontalLogoInput) (*types.DeleteOrganizationHorizontalLogoPayload, error)
CreateUser(ctx context.Context, input types.CreateUserInput) (*types.CreateUserPayload, error) CreateUser(ctx context.Context, input types.CreateUserInput) (*types.CreateUserPayload, error)
InviteUser(ctx context.Context, input types.InviteUserInput) (*types.InviteUserPayload, error) InviteUser(ctx context.Context, input types.InviteUserInput) (*types.InviteUserPayload, error)
DeactivateUser(ctx context.Context, input types.DeactivateUserInput) (*types.DeactivateUserPayload, error)
UpdateUser(ctx context.Context, input types.UpdateUserInput) (*types.UpdateUserPayload, error) UpdateUser(ctx context.Context, input types.UpdateUserInput) (*types.UpdateUserPayload, error)
UpdateMembership(ctx context.Context, input types.UpdateMembershipInput) (*types.UpdateMembershipPayload, error) UpdateMembership(ctx context.Context, input types.UpdateMembershipInput) (*types.UpdateMembershipPayload, error)
RemoveUser(ctx context.Context, input types.RemoveUserInput) (*types.RemoveUserPayload, error) RemoveUser(ctx context.Context, input types.RemoveUserInput) (*types.RemoveUserPayload, error)
@@ -638,19 +635,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
_ = ec _ = ec
switch typeName + "." + field { switch typeName + "." + field {
case "AcceptInvitationPayload.invitation":
if e.complexity.AcceptInvitationPayload.Invitation == nil {
break
}
return e.complexity.AcceptInvitationPayload.Invitation(childComplexity), true
case "AcceptInvitationPayload.membership":
if e.complexity.AcceptInvitationPayload.Membership == nil {
break
}
return e.complexity.AcceptInvitationPayload.Membership(childComplexity), true
case "ActivateAccountPayload.createPasswordToken": case "ActivateAccountPayload.createPasswordToken":
if e.complexity.ActivateAccountPayload.CreatePasswordToken == nil { if e.complexity.ActivateAccountPayload.CreatePasswordToken == nil {
break break
@@ -721,18 +705,18 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.Connector.UpdatedAt(childComplexity), true return e.complexity.Connector.UpdatedAt(childComplexity), true
case "CreateOrganizationPayload.membership":
if e.complexity.CreateOrganizationPayload.Membership == nil {
break
}
return e.complexity.CreateOrganizationPayload.Membership(childComplexity), true
case "CreateOrganizationPayload.organization": case "CreateOrganizationPayload.organization":
if e.complexity.CreateOrganizationPayload.Organization == nil { if e.complexity.CreateOrganizationPayload.Organization == nil {
break break
} }
return e.complexity.CreateOrganizationPayload.Organization(childComplexity), true return e.complexity.CreateOrganizationPayload.Organization(childComplexity), true
case "CreateOrganizationPayload.profile":
if e.complexity.CreateOrganizationPayload.Profile == nil {
break
}
return e.complexity.CreateOrganizationPayload.Profile(childComplexity), true
case "CreatePersonalAPIKeyPayload.personalAPIKeyEdge": case "CreatePersonalAPIKeyPayload.personalAPIKeyEdge":
if e.complexity.CreatePersonalAPIKeyPayload.PersonalAPIKeyEdge == nil { if e.complexity.CreatePersonalAPIKeyPayload.PersonalAPIKeyEdge == nil {
@@ -780,12 +764,12 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.CreateUserPayload.ProfileEdge(childComplexity), true return e.complexity.CreateUserPayload.ProfileEdge(childComplexity), true
case "DeleteInvitationPayload.deletedInvitationId": case "DeactivateUserPayload.success":
if e.complexity.DeleteInvitationPayload.DeletedInvitationID == nil { if e.complexity.DeactivateUserPayload.Success == nil {
break break
} }
return e.complexity.DeleteInvitationPayload.DeletedInvitationID(childComplexity), true return e.complexity.DeactivateUserPayload.Success(childComplexity), true
case "DeleteOrganizationHorizontalLogoPayload.organization": case "DeleteOrganizationHorizontalLogoPayload.organization":
if e.complexity.DeleteOrganizationHorizontalLogoPayload.Organization == nil { if e.complexity.DeleteOrganizationHorizontalLogoPayload.Organization == nil {
@@ -1131,6 +1115,17 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
} }
return e.complexity.Mutation.CreateUser(childComplexity, args["input"].(types.CreateUserInput)), true return e.complexity.Mutation.CreateUser(childComplexity, args["input"].(types.CreateUserInput)), true
case "Mutation.deactivateUser":
if e.complexity.Mutation.DeactivateUser == nil {
break
}
args, err := ec.field_Mutation_deactivateUser_args(ctx, rawArgs)
if err != nil {
return 0, false
}
return e.complexity.Mutation.DeactivateUser(childComplexity, args["input"].(types.DeactivateUserInput)), true
case "Mutation.deleteOrganization": case "Mutation.deleteOrganization":
if e.complexity.Mutation.DeleteOrganization == nil { if e.complexity.Mutation.DeleteOrganization == nil {
break break
@@ -2346,8 +2341,8 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
opCtx := graphql.GetOperationContext(ctx) opCtx := graphql.GetOperationContext(ctx)
ec := executionContext{opCtx, e, 0, 0, make(chan graphql.DeferredResult)} ec := executionContext{opCtx, e, 0, 0, make(chan graphql.DeferredResult)}
inputUnmarshalMap := graphql.BuildUnmarshalerMap( inputUnmarshalMap := graphql.BuildUnmarshalerMap(
ec.unmarshalInputAcceptInvitationInput,
ec.unmarshalInputActivateAccountInput, ec.unmarshalInputActivateAccountInput,
ec.unmarshalInputActivateUserInput,
ec.unmarshalInputAssumeOrganizationSessionInput, ec.unmarshalInputAssumeOrganizationSessionInput,
ec.unmarshalInputChangeEmailInput, ec.unmarshalInputChangeEmailInput,
ec.unmarshalInputChangePasswordInput, ec.unmarshalInputChangePasswordInput,
@@ -2356,7 +2351,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
ec.unmarshalInputCreateSAMLConfigurationInput, ec.unmarshalInputCreateSAMLConfigurationInput,
ec.unmarshalInputCreateSCIMConfigurationInput, ec.unmarshalInputCreateSCIMConfigurationInput,
ec.unmarshalInputCreateUserInput, ec.unmarshalInputCreateUserInput,
ec.unmarshalInputDeleteInvitationInput, ec.unmarshalInputDeactivateUserInput,
ec.unmarshalInputDeleteOrganizationHorizontalLogoInput, ec.unmarshalInputDeleteOrganizationHorizontalLogoInput,
ec.unmarshalInputDeleteOrganizationInput, ec.unmarshalInputDeleteOrganizationInput,
ec.unmarshalInputDeleteSAMLConfigurationInput, ec.unmarshalInputDeleteSAMLConfigurationInput,
@@ -2536,7 +2531,7 @@ type Mutation {
signOut: SignOutPayload @session(required: PRESENT) signOut: SignOutPayload @session(required: PRESENT)
activateAccount( activateAccount(
input: ActivateAccountInput! input: ActivateAccountInput!
): ActivateAccountPayload @session(required: NONE) ): ActivateAccountPayload @session(required: OPTIONAL)
forgotPassword(input: ForgotPasswordInput!): ForgotPasswordPayload forgotPassword(input: ForgotPasswordInput!): ForgotPasswordPayload
@session(required: NONE) @session(required: NONE)
resetPassword(input: ResetPasswordInput!): ResetPasswordPayload resetPassword(input: ResetPasswordInput!): ResetPasswordPayload
@@ -2579,6 +2574,7 @@ type Mutation {
@session(required: PRESENT) @session(required: PRESENT)
inviteUser(input: InviteUserInput!): InviteUserPayload inviteUser(input: InviteUserInput!): InviteUserPayload
@session(required: PRESENT) @session(required: PRESENT)
deactivateUser(input: DeactivateUserInput!): DeactivateUserPayload
updateUser(input: UpdateUserInput!): UpdateUserPayload! updateUser(input: UpdateUserInput!): UpdateUserPayload!
updateMembership(input: UpdateMembershipInput!): UpdateMembershipPayload! updateMembership(input: UpdateMembershipInput!): UpdateMembershipPayload!
removeUser(input: RemoveUserInput!): RemoveUserPayload removeUser(input: RemoveUserInput!): RemoveUserPayload
@@ -3200,6 +3196,16 @@ input InviteUserInput {
profileId: ID! profileId: ID!
} }
input ActivateUserInput {
organizationId: ID!
profileId: ID!
}
input DeactivateUserInput {
organizationId: ID!
profileId: ID!
}
input UpdateUserInput { input UpdateUserInput {
id: ID! id: ID!
fullName: String! fullName: String!
@@ -3221,15 +3227,6 @@ input RemoveUserInput {
profileId: ID! profileId: ID!
} }
input AcceptInvitationInput {
invitationId: ID!
}
input DeleteInvitationInput {
organizationId: ID!
invitationId: ID!
}
input CreateSAMLConfigurationInput { input CreateSAMLConfigurationInput {
organizationId: ID! organizationId: ID!
emailDomain: String! emailDomain: String!
@@ -3342,7 +3339,7 @@ type RevokePersonalAPIKeyPayload {
type CreateOrganizationPayload { type CreateOrganizationPayload {
organization: Organization organization: Organization
membership: Membership! profile: Profile!
} }
type UpdateOrganizationPayload { type UpdateOrganizationPayload {
@@ -3365,6 +3362,10 @@ type InviteUserPayload {
invitationEdge: InvitationEdge! invitationEdge: InvitationEdge!
} }
type DeactivateUserPayload {
success: Boolean!
}
type UpdateUserPayload { type UpdateUserPayload {
profile: Profile! profile: Profile!
} }
@@ -3377,15 +3378,6 @@ type RemoveUserPayload {
deletedProfileId: ID! deletedProfileId: ID!
} }
type AcceptInvitationPayload {
membership: Membership!
invitation: Invitation!
}
type DeleteInvitationPayload {
deletedInvitationId: ID!
}
type CreateSAMLConfigurationPayload { type CreateSAMLConfigurationPayload {
samlConfigurationEdge: SAMLConfigurationEdge! samlConfigurationEdge: SAMLConfigurationEdge!
} }
@@ -3731,6 +3723,17 @@ func (ec *executionContext) field_Mutation_createUser_args(ctx context.Context,
return args, nil return args, nil
} }
func (ec *executionContext) field_Mutation_deactivateUser_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
var err error
args := map[string]any{}
arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNDeactivateUserInput2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐDeactivateUserInput)
if err != nil {
return nil, err
}
args["input"] = arg0
return args, nil
}
func (ec *executionContext) field_Mutation_deleteOrganizationHorizontalLogo_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { func (ec *executionContext) field_Mutation_deleteOrganizationHorizontalLogo_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
var err error var err error
args := map[string]any{} args := map[string]any{}
@@ -4232,94 +4235,6 @@ func (ec *executionContext) field___Type_fields_args(ctx context.Context, rawArg
// region **************************** field.gotpl ***************************** // region **************************** field.gotpl *****************************
func (ec *executionContext) _AcceptInvitationPayload_membership(ctx context.Context, field graphql.CollectedField, obj *types.AcceptInvitationPayload) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
ec.OperationContext,
field,
ec.fieldContext_AcceptInvitationPayload_membership,
func(ctx context.Context) (any, error) {
return obj.Membership, nil
},
nil,
ec.marshalNMembership2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐMembership,
true,
true,
)
}
func (ec *executionContext) fieldContext_AcceptInvitationPayload_membership(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "AcceptInvitationPayload",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "id":
return ec.fieldContext_Membership_id(ctx, field)
case "createdAt":
return ec.fieldContext_Membership_createdAt(ctx, field)
case "role":
return ec.fieldContext_Membership_role(ctx, field)
case "lastSession":
return ec.fieldContext_Membership_lastSession(ctx, field)
case "permission":
return ec.fieldContext_Membership_permission(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type Membership", field.Name)
},
}
return fc, nil
}
func (ec *executionContext) _AcceptInvitationPayload_invitation(ctx context.Context, field graphql.CollectedField, obj *types.AcceptInvitationPayload) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
ec.OperationContext,
field,
ec.fieldContext_AcceptInvitationPayload_invitation,
func(ctx context.Context) (any, error) {
return obj.Invitation, nil
},
nil,
ec.marshalNInvitation2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐInvitation,
true,
true,
)
}
func (ec *executionContext) fieldContext_AcceptInvitationPayload_invitation(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "AcceptInvitationPayload",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "id":
return ec.fieldContext_Invitation_id(ctx, field)
case "expiresAt":
return ec.fieldContext_Invitation_expiresAt(ctx, field)
case "acceptedAt":
return ec.fieldContext_Invitation_acceptedAt(ctx, field)
case "createdAt":
return ec.fieldContext_Invitation_createdAt(ctx, field)
case "status":
return ec.fieldContext_Invitation_status(ctx, field)
case "user":
return ec.fieldContext_Invitation_user(ctx, field)
case "organization":
return ec.fieldContext_Invitation_organization(ctx, field)
case "permission":
return ec.fieldContext_Invitation_permission(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type Invitation", field.Name)
},
}
return fc, nil
}
func (ec *executionContext) _ActivateAccountPayload_createPasswordToken(ctx context.Context, field graphql.CollectedField, obj *types.ActivateAccountPayload) (ret graphql.Marshaler) { func (ec *executionContext) _ActivateAccountPayload_createPasswordToken(ctx context.Context, field graphql.CollectedField, obj *types.ActivateAccountPayload) (ret graphql.Marshaler) {
return graphql.ResolveField( return graphql.ResolveField(
ctx, ctx,
@@ -4737,23 +4652,23 @@ func (ec *executionContext) fieldContext_CreateOrganizationPayload_organization(
return fc, nil return fc, nil
} }
func (ec *executionContext) _CreateOrganizationPayload_membership(ctx context.Context, field graphql.CollectedField, obj *types.CreateOrganizationPayload) (ret graphql.Marshaler) { func (ec *executionContext) _CreateOrganizationPayload_profile(ctx context.Context, field graphql.CollectedField, obj *types.CreateOrganizationPayload) (ret graphql.Marshaler) {
return graphql.ResolveField( return graphql.ResolveField(
ctx, ctx,
ec.OperationContext, ec.OperationContext,
field, field,
ec.fieldContext_CreateOrganizationPayload_membership, ec.fieldContext_CreateOrganizationPayload_profile,
func(ctx context.Context) (any, error) { func(ctx context.Context) (any, error) {
return obj.Membership, nil return obj.Profile, nil
}, },
nil, nil,
ec.marshalNMembership2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐMembership, ec.marshalNProfile2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐProfile,
true, true,
true, true,
) )
} }
func (ec *executionContext) fieldContext_CreateOrganizationPayload_membership(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { func (ec *executionContext) fieldContext_CreateOrganizationPayload_profile(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{ fc = &graphql.FieldContext{
Object: "CreateOrganizationPayload", Object: "CreateOrganizationPayload",
Field: field, Field: field,
@@ -4762,17 +4677,41 @@ func (ec *executionContext) fieldContext_CreateOrganizationPayload_membership(_
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name { switch field.Name {
case "id": case "id":
return ec.fieldContext_Membership_id(ctx, field) return ec.fieldContext_Profile_id(ctx, field)
case "fullName":
return ec.fieldContext_Profile_fullName(ctx, field)
case "emailAddress":
return ec.fieldContext_Profile_emailAddress(ctx, field)
case "source":
return ec.fieldContext_Profile_source(ctx, field)
case "state":
return ec.fieldContext_Profile_state(ctx, field)
case "additionalEmailAddresses":
return ec.fieldContext_Profile_additionalEmailAddresses(ctx, field)
case "kind":
return ec.fieldContext_Profile_kind(ctx, field)
case "position":
return ec.fieldContext_Profile_position(ctx, field)
case "contractStartDate":
return ec.fieldContext_Profile_contractStartDate(ctx, field)
case "contractEndDate":
return ec.fieldContext_Profile_contractEndDate(ctx, field)
case "createdAt": case "createdAt":
return ec.fieldContext_Membership_createdAt(ctx, field) return ec.fieldContext_Profile_createdAt(ctx, field)
case "role": case "updatedAt":
return ec.fieldContext_Membership_role(ctx, field) return ec.fieldContext_Profile_updatedAt(ctx, field)
case "lastSession": case "identity":
return ec.fieldContext_Membership_lastSession(ctx, field) return ec.fieldContext_Profile_identity(ctx, field)
case "organization":
return ec.fieldContext_Profile_organization(ctx, field)
case "membership":
return ec.fieldContext_Profile_membership(ctx, field)
case "pendingInvitations":
return ec.fieldContext_Profile_pendingInvitations(ctx, field)
case "permission": case "permission":
return ec.fieldContext_Membership_permission(ctx, field) return ec.fieldContext_Profile_permission(ctx, field)
} }
return nil, fmt.Errorf("no field named %q was found under type Membership", field.Name) return nil, fmt.Errorf("no field named %q was found under type Profile", field.Name)
}, },
} }
return fc, nil return fc, nil
@@ -5037,30 +4976,30 @@ func (ec *executionContext) fieldContext_CreateUserPayload_profileEdge(_ context
return fc, nil return fc, nil
} }
func (ec *executionContext) _DeleteInvitationPayload_deletedInvitationId(ctx context.Context, field graphql.CollectedField, obj *types.DeleteInvitationPayload) (ret graphql.Marshaler) { func (ec *executionContext) _DeactivateUserPayload_success(ctx context.Context, field graphql.CollectedField, obj *types.DeactivateUserPayload) (ret graphql.Marshaler) {
return graphql.ResolveField( return graphql.ResolveField(
ctx, ctx,
ec.OperationContext, ec.OperationContext,
field, field,
ec.fieldContext_DeleteInvitationPayload_deletedInvitationId, ec.fieldContext_DeactivateUserPayload_success,
func(ctx context.Context) (any, error) { func(ctx context.Context) (any, error) {
return obj.DeletedInvitationID, nil return obj.Success, nil
}, },
nil, nil,
ec.marshalNID2goᚗproboᚗincᚋproboᚋpkgᚋgidᚐGID, ec.marshalNBoolean2bool,
true, true,
true, true,
) )
} }
func (ec *executionContext) fieldContext_DeleteInvitationPayload_deletedInvitationId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { func (ec *executionContext) fieldContext_DeactivateUserPayload_success(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{ fc = &graphql.FieldContext{
Object: "DeleteInvitationPayload", Object: "DeactivateUserPayload",
Field: field, Field: field,
IsMethod: false, IsMethod: false,
IsResolver: false, IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type ID does not have child fields") return nil, errors.New("field of type Boolean does not have child fields")
}, },
} }
return fc, nil return fc, nil
@@ -6600,7 +6539,7 @@ func (ec *executionContext) _Mutation_activateAccount(ctx context.Context, field
directive0 := next directive0 := next
directive1 := func(ctx context.Context) (any, error) { directive1 := func(ctx context.Context) (any, error) {
required, err := ec.unmarshalNSessionRequirement2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋgqlutilsᚋdirectivesᚋsessionᚐSessionRequirement(ctx, "NONE") required, err := ec.unmarshalNSessionRequirement2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋgqlutilsᚋdirectivesᚋsessionᚐSessionRequirement(ctx, "OPTIONAL")
if err != nil { if err != nil {
var zeroVal *types.ActivateAccountPayload var zeroVal *types.ActivateAccountPayload
return zeroVal, err return zeroVal, err
@@ -7316,8 +7255,8 @@ func (ec *executionContext) fieldContext_Mutation_createOrganization(ctx context
switch field.Name { switch field.Name {
case "organization": case "organization":
return ec.fieldContext_CreateOrganizationPayload_organization(ctx, field) return ec.fieldContext_CreateOrganizationPayload_organization(ctx, field)
case "membership": case "profile":
return ec.fieldContext_CreateOrganizationPayload_membership(ctx, field) return ec.fieldContext_CreateOrganizationPayload_profile(ctx, field)
} }
return nil, fmt.Errorf("no field named %q was found under type CreateOrganizationPayload", field.Name) return nil, fmt.Errorf("no field named %q was found under type CreateOrganizationPayload", field.Name)
}, },
@@ -7651,6 +7590,51 @@ func (ec *executionContext) fieldContext_Mutation_inviteUser(ctx context.Context
return fc, nil return fc, nil
} }
func (ec *executionContext) _Mutation_deactivateUser(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
return graphql.ResolveField(
ctx,
ec.OperationContext,
field,
ec.fieldContext_Mutation_deactivateUser,
func(ctx context.Context) (any, error) {
fc := graphql.GetFieldContext(ctx)
return ec.resolvers.Mutation().DeactivateUser(ctx, fc.Args["input"].(types.DeactivateUserInput))
},
nil,
ec.marshalODeactivateUserPayload2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐDeactivateUserPayload,
true,
false,
)
}
func (ec *executionContext) fieldContext_Mutation_deactivateUser(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Mutation",
Field: field,
IsMethod: true,
IsResolver: true,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "success":
return ec.fieldContext_DeactivateUserPayload_success(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type DeactivateUserPayload", field.Name)
},
}
defer func() {
if r := recover(); r != nil {
err = ec.Recover(ctx, r)
ec.Error(ctx, err)
}
}()
ctx = graphql.WithFieldContext(ctx, fc)
if fc.Args, err = ec.field_Mutation_deactivateUser_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
ec.Error(ctx, err)
return fc, err
}
return fc, nil
}
func (ec *executionContext) _Mutation_updateUser(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { func (ec *executionContext) _Mutation_updateUser(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
return graphql.ResolveField( return graphql.ResolveField(
ctx, ctx,
@@ -15145,33 +15129,6 @@ func (ec *executionContext) fieldContext___Type_isOneOf(_ context.Context, field
// region **************************** input.gotpl ***************************** // region **************************** input.gotpl *****************************
func (ec *executionContext) unmarshalInputAcceptInvitationInput(ctx context.Context, obj any) (types.AcceptInvitationInput, error) {
var it types.AcceptInvitationInput
asMap := map[string]any{}
for k, v := range obj.(map[string]any) {
asMap[k] = v
}
fieldsInOrder := [...]string{"invitationId"}
for _, k := range fieldsInOrder {
v, ok := asMap[k]
if !ok {
continue
}
switch k {
case "invitationId":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("invitationId"))
data, err := ec.unmarshalNID2goᚗproboᚗincᚋproboᚋpkgᚋgidᚐGID(ctx, v)
if err != nil {
return it, err
}
it.InvitationID = data
}
}
return it, nil
}
func (ec *executionContext) unmarshalInputActivateAccountInput(ctx context.Context, obj any) (types.ActivateAccountInput, error) { func (ec *executionContext) unmarshalInputActivateAccountInput(ctx context.Context, obj any) (types.ActivateAccountInput, error) {
var it types.ActivateAccountInput var it types.ActivateAccountInput
asMap := map[string]any{} asMap := map[string]any{}
@@ -15199,6 +15156,40 @@ func (ec *executionContext) unmarshalInputActivateAccountInput(ctx context.Conte
return it, nil return it, nil
} }
func (ec *executionContext) unmarshalInputActivateUserInput(ctx context.Context, obj any) (types.ActivateUserInput, error) {
var it types.ActivateUserInput
asMap := map[string]any{}
for k, v := range obj.(map[string]any) {
asMap[k] = v
}
fieldsInOrder := [...]string{"organizationId", "profileId"}
for _, k := range fieldsInOrder {
v, ok := asMap[k]
if !ok {
continue
}
switch k {
case "organizationId":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("organizationId"))
data, err := ec.unmarshalNID2goᚗproboᚗincᚋproboᚋpkgᚋgidᚐGID(ctx, v)
if err != nil {
return it, err
}
it.OrganizationID = data
case "profileId":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("profileId"))
data, err := ec.unmarshalNID2goᚗproboᚗincᚋproboᚋpkgᚋgidᚐGID(ctx, v)
if err != nil {
return it, err
}
it.ProfileID = data
}
}
return it, nil
}
func (ec *executionContext) unmarshalInputAssumeOrganizationSessionInput(ctx context.Context, obj any) (types.AssumeOrganizationSessionInput, error) { func (ec *executionContext) unmarshalInputAssumeOrganizationSessionInput(ctx context.Context, obj any) (types.AssumeOrganizationSessionInput, error) {
var it types.AssumeOrganizationSessionInput var it types.AssumeOrganizationSessionInput
asMap := map[string]any{} asMap := map[string]any{}
@@ -15562,14 +15553,14 @@ func (ec *executionContext) unmarshalInputCreateUserInput(ctx context.Context, o
return it, nil return it, nil
} }
func (ec *executionContext) unmarshalInputDeleteInvitationInput(ctx context.Context, obj any) (types.DeleteInvitationInput, error) { func (ec *executionContext) unmarshalInputDeactivateUserInput(ctx context.Context, obj any) (types.DeactivateUserInput, error) {
var it types.DeleteInvitationInput var it types.DeactivateUserInput
asMap := map[string]any{} asMap := map[string]any{}
for k, v := range obj.(map[string]any) { for k, v := range obj.(map[string]any) {
asMap[k] = v asMap[k] = v
} }
fieldsInOrder := [...]string{"organizationId", "invitationId"} fieldsInOrder := [...]string{"organizationId", "profileId"}
for _, k := range fieldsInOrder { for _, k := range fieldsInOrder {
v, ok := asMap[k] v, ok := asMap[k]
if !ok { if !ok {
@@ -15583,13 +15574,13 @@ func (ec *executionContext) unmarshalInputDeleteInvitationInput(ctx context.Cont
return it, err return it, err
} }
it.OrganizationID = data it.OrganizationID = data
case "invitationId": case "profileId":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("invitationId")) ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("profileId"))
data, err := ec.unmarshalNID2goᚗproboᚗincᚋproboᚋpkgᚋgidᚐGID(ctx, v) data, err := ec.unmarshalNID2goᚗproboᚗincᚋproboᚋpkgᚋgidᚐGID(ctx, v)
if err != nil { if err != nil {
return it, err return it, err
} }
it.InvitationID = data it.ProfileID = data
} }
} }
@@ -16704,50 +16695,6 @@ func (ec *executionContext) _Node(ctx context.Context, sel ast.SelectionSet, obj
// region **************************** object.gotpl **************************** // region **************************** object.gotpl ****************************
var acceptInvitationPayloadImplementors = []string{"AcceptInvitationPayload"}
func (ec *executionContext) _AcceptInvitationPayload(ctx context.Context, sel ast.SelectionSet, obj *types.AcceptInvitationPayload) graphql.Marshaler {
fields := graphql.CollectFields(ec.OperationContext, sel, acceptInvitationPayloadImplementors)
out := graphql.NewFieldSet(fields)
deferred := make(map[string]*graphql.FieldSet)
for i, field := range fields {
switch field.Name {
case "__typename":
out.Values[i] = graphql.MarshalString("AcceptInvitationPayload")
case "membership":
out.Values[i] = ec._AcceptInvitationPayload_membership(ctx, field, obj)
if out.Values[i] == graphql.Null {
out.Invalids++
}
case "invitation":
out.Values[i] = ec._AcceptInvitationPayload_invitation(ctx, field, obj)
if out.Values[i] == graphql.Null {
out.Invalids++
}
default:
panic("unknown field " + strconv.Quote(field.Name))
}
}
out.Dispatch(ctx)
if out.Invalids > 0 {
return graphql.Null
}
atomic.AddInt32(&ec.deferred, int32(len(deferred)))
for label, dfs := range deferred {
ec.processDeferredGroup(graphql.DeferredGroup{
Label: label,
Path: graphql.GetPath(ctx),
FieldSet: dfs,
Context: ctx,
})
}
return out
}
var activateAccountPayloadImplementors = []string{"ActivateAccountPayload"} var activateAccountPayloadImplementors = []string{"ActivateAccountPayload"}
func (ec *executionContext) _ActivateAccountPayload(ctx context.Context, sel ast.SelectionSet, obj *types.ActivateAccountPayload) graphql.Marshaler { func (ec *executionContext) _ActivateAccountPayload(ctx context.Context, sel ast.SelectionSet, obj *types.ActivateAccountPayload) graphql.Marshaler {
@@ -17006,8 +16953,8 @@ func (ec *executionContext) _CreateOrganizationPayload(ctx context.Context, sel
out.Values[i] = graphql.MarshalString("CreateOrganizationPayload") out.Values[i] = graphql.MarshalString("CreateOrganizationPayload")
case "organization": case "organization":
out.Values[i] = ec._CreateOrganizationPayload_organization(ctx, field, obj) out.Values[i] = ec._CreateOrganizationPayload_organization(ctx, field, obj)
case "membership": case "profile":
out.Values[i] = ec._CreateOrganizationPayload_membership(ctx, field, obj) out.Values[i] = ec._CreateOrganizationPayload_profile(ctx, field, obj)
if out.Values[i] == graphql.Null { if out.Values[i] == graphql.Null {
out.Invalids++ out.Invalids++
} }
@@ -17202,19 +17149,19 @@ func (ec *executionContext) _CreateUserPayload(ctx context.Context, sel ast.Sele
return out return out
} }
var deleteInvitationPayloadImplementors = []string{"DeleteInvitationPayload"} var deactivateUserPayloadImplementors = []string{"DeactivateUserPayload"}
func (ec *executionContext) _DeleteInvitationPayload(ctx context.Context, sel ast.SelectionSet, obj *types.DeleteInvitationPayload) graphql.Marshaler { func (ec *executionContext) _DeactivateUserPayload(ctx context.Context, sel ast.SelectionSet, obj *types.DeactivateUserPayload) graphql.Marshaler {
fields := graphql.CollectFields(ec.OperationContext, sel, deleteInvitationPayloadImplementors) fields := graphql.CollectFields(ec.OperationContext, sel, deactivateUserPayloadImplementors)
out := graphql.NewFieldSet(fields) out := graphql.NewFieldSet(fields)
deferred := make(map[string]*graphql.FieldSet) deferred := make(map[string]*graphql.FieldSet)
for i, field := range fields { for i, field := range fields {
switch field.Name { switch field.Name {
case "__typename": case "__typename":
out.Values[i] = graphql.MarshalString("DeleteInvitationPayload") out.Values[i] = graphql.MarshalString("DeactivateUserPayload")
case "deletedInvitationId": case "success":
out.Values[i] = ec._DeleteInvitationPayload_deletedInvitationId(ctx, field, obj) out.Values[i] = ec._DeactivateUserPayload_success(ctx, field, obj)
if out.Values[i] == graphql.Null { if out.Values[i] == graphql.Null {
out.Invalids++ out.Invalids++
} }
@@ -18206,6 +18153,10 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
return ec._Mutation_inviteUser(ctx, field) return ec._Mutation_inviteUser(ctx, field)
}) })
case "deactivateUser":
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
return ec._Mutation_deactivateUser(ctx, field)
})
case "updateUser": case "updateUser":
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
return ec._Mutation_updateUser(ctx, field) return ec._Mutation_updateUser(ctx, field)
@@ -21721,6 +21672,11 @@ func (ec *executionContext) marshalNDatetime2timeᚐTime(ctx context.Context, se
return res return res
} }
func (ec *executionContext) unmarshalNDeactivateUserInput2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐDeactivateUserInput(ctx context.Context, v any) (types.DeactivateUserInput, error) {
res, err := ec.unmarshalInputDeactivateUserInput(ctx, v)
return res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) unmarshalNDeleteOrganizationHorizontalLogoInput2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐDeleteOrganizationHorizontalLogoInput(ctx context.Context, v any) (types.DeleteOrganizationHorizontalLogoInput, error) { func (ec *executionContext) unmarshalNDeleteOrganizationHorizontalLogoInput2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐDeleteOrganizationHorizontalLogoInput(ctx context.Context, v any) (types.DeleteOrganizationHorizontalLogoInput, error) {
res, err := ec.unmarshalInputDeleteOrganizationHorizontalLogoInput(ctx, v) res, err := ec.unmarshalInputDeleteOrganizationHorizontalLogoInput(ctx, v)
return res, graphql.ErrorOnPath(ctx, err) return res, graphql.ErrorOnPath(ctx, err)
@@ -23199,6 +23155,13 @@ func (ec *executionContext) marshalODatetime2ᚖtimeᚐTime(ctx context.Context,
return res return res
} }
func (ec *executionContext) marshalODeactivateUserPayload2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐDeactivateUserPayload(ctx context.Context, sel ast.SelectionSet, v *types.DeactivateUserPayload) graphql.Marshaler {
if v == nil {
return graphql.Null
}
return ec._DeactivateUserPayload(ctx, sel, v)
}
func (ec *executionContext) marshalODeleteOrganizationHorizontalLogoPayload2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐDeleteOrganizationHorizontalLogoPayload(ctx context.Context, sel ast.SelectionSet, v *types.DeleteOrganizationHorizontalLogoPayload) graphql.Marshaler { func (ec *executionContext) marshalODeleteOrganizationHorizontalLogoPayload2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐDeleteOrganizationHorizontalLogoPayload(ctx context.Context, sel ast.SelectionSet, v *types.DeleteOrganizationHorizontalLogoPayload) graphql.Marshaler {
if v == nil { if v == nil {
return graphql.Null return graphql.Null

View File

@@ -25,15 +25,6 @@ type Node interface {
GetID() gid.GID GetID() gid.GID
} }
type AcceptInvitationInput struct {
InvitationID gid.GID `json:"invitationId"`
}
type AcceptInvitationPayload struct {
Membership *Membership `json:"membership"`
Invitation *Invitation `json:"invitation"`
}
type ActivateAccountInput struct { type ActivateAccountInput struct {
Token string `json:"token"` Token string `json:"token"`
} }
@@ -43,6 +34,11 @@ type ActivateAccountPayload struct {
Profile *Profile `json:"profile,omitempty"` Profile *Profile `json:"profile,omitempty"`
} }
type ActivateUserInput struct {
OrganizationID gid.GID `json:"organizationId"`
ProfileID gid.GID `json:"profileId"`
}
type AssumeOrganizationSessionInput struct { type AssumeOrganizationSessionInput struct {
OrganizationID gid.GID `json:"organizationId"` OrganizationID gid.GID `json:"organizationId"`
Continue string `json:"continue"` Continue string `json:"continue"`
@@ -89,7 +85,7 @@ type CreateOrganizationInput struct {
type CreateOrganizationPayload struct { type CreateOrganizationPayload struct {
Organization *Organization `json:"organization,omitempty"` Organization *Organization `json:"organization,omitempty"`
Membership *Membership `json:"membership"` Profile *Profile `json:"profile"`
} }
type CreatePersonalAPIKeyInput struct { type CreatePersonalAPIKeyInput struct {
@@ -143,13 +139,13 @@ type CreateUserPayload struct {
ProfileEdge *ProfileEdge `json:"profileEdge"` ProfileEdge *ProfileEdge `json:"profileEdge"`
} }
type DeleteInvitationInput struct { type DeactivateUserInput struct {
OrganizationID gid.GID `json:"organizationId"` OrganizationID gid.GID `json:"organizationId"`
InvitationID gid.GID `json:"invitationId"` ProfileID gid.GID `json:"profileId"`
} }
type DeleteInvitationPayload struct { type DeactivateUserPayload struct {
DeletedInvitationID gid.GID `json:"deletedInvitationId"` Success bool `json:"success"`
} }
type DeleteOrganizationHorizontalLogoInput struct { type DeleteOrganizationHorizontalLogoInput struct {

View File

@@ -718,7 +718,7 @@ func (r *mutationResolver) CreateOrganization(ctx context.Context, input types.C
Size: input.HorizontalLogoFile.Size, Size: input.HorizontalLogoFile.Size,
} }
} }
organization, membership, err := r.iam.OrganizationService.CreateOrganization( organization, profile, err := r.iam.OrganizationService.CreateOrganization(
ctx, ctx,
identity.ID, identity.ID,
&iam.CreateOrganizationRequest{ &iam.CreateOrganizationRequest{
@@ -734,7 +734,7 @@ func (r *mutationResolver) CreateOrganization(ctx context.Context, input types.C
return &types.CreateOrganizationPayload{ return &types.CreateOrganizationPayload{
Organization: types.NewOrganization(organization), Organization: types.NewOrganization(organization),
Membership: types.NewMembership(membership), Profile: types.NewProfile(profile),
}, nil }, nil
} }
@@ -883,6 +883,28 @@ func (r *mutationResolver) InviteUser(ctx context.Context, input types.InviteUse
}, nil }, nil
} }
// DeactivateUser is the resolver for the deactivateUser field.
func (r *mutationResolver) DeactivateUser(ctx context.Context, input types.DeactivateUserInput) (*types.DeactivateUserPayload, error) {
if err := r.authorize(ctx, input.ProfileID, iam.ActionMembershipProfileDeactivate); err != nil {
return nil, err
}
_, err := r.iam.OrganizationService.UpdateUserState(
ctx,
input.ProfileID,
coredata.ProfileStateInactive,
)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot deactivate profile", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.DeactivateUserPayload{
Success: true,
}, nil
}
// UpdateUser is the resolver for the updateUser field. // UpdateUser is the resolver for the updateUser field.
func (r *mutationResolver) UpdateUser(ctx context.Context, input types.UpdateUserInput) (*types.UpdateUserPayload, error) { func (r *mutationResolver) UpdateUser(ctx context.Context, input types.UpdateUserInput) (*types.UpdateUserPayload, error) {
if err := r.authorize(ctx, input.ID, iam.ActionMembershipProfileUpdate); err != nil { if err := r.authorize(ctx, input.ID, iam.ActionMembershipProfileUpdate); err != nil {