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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -21,6 +21,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.probo.inc/probo/e2e/internal/factory"
"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) {
t.Parallel()
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")
query := `
@@ -142,7 +143,7 @@ func TestNonconformity_Create(t *testing.T) {
"auditId": auditID,
"rootCause": "Insufficient access controls",
"correctiveAction": "Implement MFA",
"ownerId": profileID.String(),
"ownerId": profileID,
"status": "OPEN",
},
}, &result)
@@ -158,7 +159,7 @@ func TestNonconformity_Create(t *testing.T) {
func TestNonconformity_Update(t *testing.T) {
t.Parallel()
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")
// Create a nonconformity to update
@@ -190,7 +191,7 @@ func TestNonconformity_Update(t *testing.T) {
"referenceId": fmt.Sprintf("NC-UPDATE-%d", time.Now().UnixNano()),
"auditId": auditID,
"rootCause": "Original root cause",
"ownerId": profileID.String(),
"ownerId": profileID,
"status": "OPEN",
},
}, &createResult)
@@ -241,7 +242,7 @@ func TestNonconformity_Update(t *testing.T) {
func TestNonconformity_Delete(t *testing.T) {
t.Parallel()
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")
// Create a nonconformity to delete
@@ -273,7 +274,7 @@ func TestNonconformity_Delete(t *testing.T) {
"referenceId": fmt.Sprintf("NC-DELETE-%d", time.Now().UnixNano()),
"auditId": auditID,
"rootCause": "Test root cause",
"ownerId": profileID.String(),
"ownerId": profileID,
"status": "OPEN",
},
}, &createResult)
@@ -306,7 +307,7 @@ func TestNonconformity_Delete(t *testing.T) {
func TestNonconformity_List(t *testing.T) {
t.Parallel()
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")
// Create multiple nonconformities
@@ -339,7 +340,7 @@ func TestNonconformity_List(t *testing.T) {
"referenceId": fmt.Sprintf("NC-LIST-%d-%d", i, time.Now().UnixNano()),
"auditId": auditID,
"rootCause": fmt.Sprintf("Root cause %d", i),
"ownerId": profileID.String(),
"ownerId": profileID,
"status": "OPEN",
},
}, &createResult)
@@ -390,7 +391,7 @@ func TestNonconformity_List(t *testing.T) {
func TestNonconformity_StatusValues(t *testing.T) {
t.Parallel()
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")
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()),
"auditId": auditID,
"rootCause": "Test root cause",
"ownerId": profileID.String(),
"ownerId": profileID,
"status": status,
},
}, &result)

View File

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

View File

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

View File

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

View File

@@ -650,7 +650,7 @@ func TestTask_OmittableAssignee(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner)
// Create a profile for assignee
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID()
profileID := factory.CreateUser(owner)
measureID := factory.NewMeasure(owner).
WithName("Task Assignee Test").
Create()
@@ -689,11 +689,11 @@ func TestTask_OmittableAssignee(t *testing.T) {
err := owner.Execute(query, map[string]any{
"input": map[string]any{
"taskId": taskID,
"assignedToId": profileID.String(),
"assignedToId": profileID,
},
}, &result)
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) {

View File

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

View File

@@ -15,32 +15,32 @@
package console_test
import (
"fmt"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.probo.inc/probo/e2e/internal/testutil"
)
func TestMember_UpdateMembership(t *testing.T) {
func TestUser_UpdateMembership(t *testing.T) {
t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner)
// Create an admin to update
_ = testutil.NewClientInOrg(t, testutil.RoleAdmin, owner)
// Get the member ID of the admin
// Get the user ID of the admin
query := `
query($id: ID!) {
node(id: $id) {
... on Organization {
members(first: 10) {
profiles(first: 10) {
edges {
node {
id
role
membership {
id
role
}
}
}
}
@@ -51,14 +51,16 @@ func TestMember_UpdateMembership(t *testing.T) {
var result struct {
Node struct {
Members struct {
Profiles struct {
Edges []struct {
Node struct {
ID string `json:"id"`
Role string `json:"role"`
Membership struct {
ID string `json:"id"`
Role string `json:"role"`
} `json:"membership"`
} `json:"node"`
} `json:"edges"`
} `json:"members"`
} `json:"profiles"`
} `json:"node"`
}
@@ -67,15 +69,15 @@ func TestMember_UpdateMembership(t *testing.T) {
}, &result)
require.NoError(t, err)
// Find the admin member
var adminMemberID string
for _, edge := range result.Node.Members.Edges {
if edge.Node.Role == "ADMIN" {
adminMemberID = edge.Node.ID
// Find the admin
var adminMembershipID string
for _, edge := range result.Node.Profiles.Edges {
if edge.Node.Membership.Role == "ADMIN" {
adminMembershipID = edge.Node.Membership.ID
break
}
}
require.NotEmpty(t, adminMemberID, "Should find admin member")
require.NotEmpty(t, adminMembershipID, "Should find admin member")
// Update the member role to VIEWER
mutation := `
@@ -101,7 +103,7 @@ func TestMember_UpdateMembership(t *testing.T) {
err = owner.ExecuteConnect(mutation, map[string]any{
"input": map[string]any{
"organizationId": owner.GetOrganizationID().String(),
"membershipId": adminMemberID,
"membershipId": adminMembershipID,
"role": "VIEWER",
},
}, &mutationResult)
@@ -110,24 +112,26 @@ func TestMember_UpdateMembership(t *testing.T) {
assert.Equal(t, "VIEWER", mutationResult.UpdateMembership.Membership.Role)
}
func TestMember_RemoveMember(t *testing.T) {
func TestUser_RemoveUser(t *testing.T) {
t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner)
// Create a member to remove
memberToRemove := testutil.NewClientInOrg(t, testutil.RoleViewer, owner)
_ = memberToRemove
// Create a user to remove
userToRemove := testutil.NewClientInOrg(t, testutil.RoleViewer, owner)
_ = userToRemove
// Get the member ID
// Get the user ID
query := `
query($id: ID!) {
node(id: $id) {
... on Organization {
members(first: 50) {
profiles(first: 50) {
edges {
node {
id
role
membership {
role
}
}
}
}
@@ -138,14 +142,16 @@ func TestMember_RemoveMember(t *testing.T) {
var result struct {
Node struct {
Members struct {
Profiles struct {
Edges []struct {
Node struct {
ID string `json:"id"`
Role string `json:"role"`
ID string `json:"id"`
Membership struct {
Role string `json:"role"`
} `json:"membership"`
} `json:"node"`
} `json:"edges"`
} `json:"members"`
} `json:"profiles"`
} `json:"node"`
}
@@ -154,113 +160,43 @@ func TestMember_RemoveMember(t *testing.T) {
}, &result)
require.NoError(t, err)
// Find a viewer member to remove
var memberID string
for _, edge := range result.Node.Members.Edges {
if edge.Node.Role == "VIEWER" {
memberID = edge.Node.ID
// Find a viewer user to remove
var userID string
for _, edge := range result.Node.Profiles.Edges {
if edge.Node.Membership.Role == "VIEWER" {
userID = edge.Node.ID
break
}
}
assert.NotEmpty(t, memberID, "Should find viewer member")
assert.NotEmpty(t, userID, "Should find viewer member")
// Remove the member
mutation := `
mutation($input: RemoveMemberInput!) {
removeMember(input: $input) {
deletedMembershipId
mutation($input: RemoveUserInput!) {
removeUser(input: $input) {
deletedProfileId
}
}
`
var mutationResult struct {
RemoveMember struct {
DeletedMembershipID string `json:"deletedMembershipId"`
} `json:"removeMember"`
RemoveUser struct {
DeletedProfileID string `json:"deletedProfileId"`
} `json:"removeUser"`
}
err = owner.ExecuteConnect(mutation, map[string]any{
"input": map[string]any{
"organizationId": owner.GetOrganizationID().String(),
"membershipId": memberID,
"profileId": userID,
},
}, &mutationResult)
require.NoError(t, err)
assert.Equal(t, memberID, mutationResult.RemoveMember.DeletedMembershipID)
assert.Equal(t, userID, mutationResult.RemoveUser.DeletedProfileID)
}
func TestInvitation_Delete(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) {
func TestUser_List(t *testing.T) {
t.Parallel()
owner := testutil.NewClient(t, testutil.RoleOwner)
@@ -272,11 +208,13 @@ func TestMember_List(t *testing.T) {
query($id: ID!) {
node(id: $id) {
... on Organization {
members(first: 10) {
profiles(first: 10) {
edges {
node {
id
role
membership {
role
}
}
}
totalCount
@@ -288,15 +226,17 @@ func TestMember_List(t *testing.T) {
var result struct {
Node struct {
Members struct {
Profiles struct {
Edges []struct {
Node struct {
ID string `json:"id"`
Role string `json:"role"`
ID string `json:"id"`
Membership struct {
Role string `json:"role"`
} `json:"membership"`
} `json:"node"`
} `json:"edges"`
TotalCount int `json:"totalCount"`
} `json:"members"`
} `json:"profiles"`
} `json:"node"`
}
@@ -305,5 +245,5 @@ func TestMember_List(t *testing.T) {
}, &result)
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)
// Create a profile for owner assignment
profileID := testutil.NewClientInOrg(t, testutil.RoleViewer, owner).GetProfileID()
profileID := factory.CreateUser(owner)
vendorID := factory.NewVendor(owner).
WithName("BusinessOwner Test Vendor").
Create()
@@ -790,11 +790,11 @@ func TestVendor_OmittableBusinessOwner(t *testing.T) {
err := owner.Execute(query, map[string]any{
"input": map[string]any{
"id": vendorID,
"businessOwnerId": profileID.String(),
"businessOwnerId": profileID,
},
}, &result)
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) {
@@ -838,7 +838,7 @@ func TestVendor_OmittableSecurityOwner(t *testing.T) {
owner := testutil.NewClient(t, testutil.RoleOwner)
// 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()
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{
"input": map[string]any{
"id": vendorID,
"securityOwnerId": profileID.String(),
"securityOwnerId": profileID,
},
}, &result)
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) {

View File

@@ -22,6 +22,7 @@ import (
"github.com/brianvoe/gofakeit/v7"
"github.com/stretchr/testify/require"
"go.probo.inc/probo/e2e/internal/testutil"
"go.probo.inc/probo/pkg/coredata"
)
func SafeName(prefix string) string {
@@ -92,6 +93,52 @@ func (a Attrs) getBool(key string, defaultVal bool) bool {
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 {
c.T.Helper()

View File

@@ -20,6 +20,7 @@ import (
"fmt"
"net/http"
"net/http/cookiejar"
"net/url"
"testing"
"time"
@@ -46,9 +47,9 @@ type Client struct {
T testing.TB
httpClient *http.Client
baseURL string
mailpitBaseURL string
role TestRole
userID gid.GID
profileID 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")
client := &Client{
T: t,
baseURL: GetBaseURL(),
role: role,
T: t,
baseURL: GetBaseURL(),
mailpitBaseURL: GetMailpitBaseURL(),
role: role,
httpClient: &http.Client{
Jar: jar,
Timeout: 30 * time.Second,
@@ -82,6 +84,7 @@ func NewClientInOrg(t testing.TB, role TestRole, ownerClient *Client) *Client {
client := &Client{
T: t,
baseURL: GetBaseURL(),
mailpitBaseURL: GetMailpitBaseURL(),
role: role,
organizationID: ownerClient.organizationID,
httpClient: &http.Client{
@@ -106,7 +109,7 @@ func (c *Client) setupTestUser() {
// Create organization (this makes the user an OWNER)
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
c.assumeOrganizationSession()
@@ -127,10 +130,12 @@ func (c *Client) SetupTestUserInOrg(ownerClient *Client) {
c.userID = c.signUp(email, password, fullName)
// 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
c.profileID = c.acceptInvitation(invitationID)
token := c.getActivationToken(email)
c.activateUser(token)
// Assume organization session to use console API
c.assumeOrganizationSession()
@@ -168,16 +173,12 @@ func (c *Client) signUp(email, password, fullName string) gid.GID {
return userID
}
func (c *Client) createOrganization(name string) (gid.GID, gid.GID) {
func (c *Client) createOrganization(name string) gid.GID {
const query = `
mutation($input: CreateOrganizationInput!) {
createOrganization(input: $input) {
organization { id }
membershipEdge {
node {
profile { id }
}
}
profile { id }
}
}
`
@@ -187,14 +188,6 @@ func (c *Client) createOrganization(name string) (gid.GID, gid.GID) {
Organization struct {
ID string `json:"id"`
} `json:"organization"`
MembershipEdge struct {
Node struct {
ID string `json:"id"`
Profile struct {
ID string `json:"id"`
} `json:"profile"`
} `json:"node"`
} `json:"membershipEdge"`
} `json:"createOrganization"`
}
@@ -206,10 +199,7 @@ func (c *Client) createOrganization(name string) (gid.GID, gid.GID) {
orgID, err := gid.ParseGID(result.CreateOrganization.Organization.ID)
require.NoError(c.T, err, "cannot parse organization ID")
profileID, err := gid.ParseGID(result.CreateOrganization.MembershipEdge.Node.Profile.ID)
require.NoError(c.T, err, "cannot parse profile ID")
return orgID, profileID
return orgID
}
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")
}
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 = `
mutation($input: InviteMemberInput!) {
inviteMember(input: $input) {
mutation($input: CreateUserInput!) {
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 {
node { id }
}
@@ -296,67 +325,79 @@ func (c *Client) inviteMember(email, fullName string, role coredata.MembershipRo
`
var result struct {
InviteMember struct {
InviteUser struct {
InvitationEdge struct {
Node struct {
ID string `json:"id"`
} `json:"node"`
} `json:"invitationEdge"`
} `json:"inviteMember"`
} `json:"inviteUser"`
}
err := c.ExecuteConnect(query, map[string]any{
"input": map[string]any{
"organizationId": c.organizationID.String(),
"email": email,
"fullName": fullName,
"role": string(role),
"profileId": profileID.String(),
},
}, &result)
require.NoError(c.T, err, "inviteMember mutation failed")
invitationID, err := gid.ParseGID(result.InviteMember.InvitationEdge.Node.ID)
require.NoError(c.T, err, "cannot parse invitation ID")
return invitationID
require.NoError(c.T, err, "inviteUser mutation failed")
}
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 = `
mutation($input: AcceptInvitationInput!) {
acceptInvitation(input: $input) {
membershipEdge {
node {
profile { id }
}
mutation($input: ActivateAccountInput!) {
activateAccount(input: $input) {
profile {
id
}
}
}
`
var result struct {
AcceptInvitation struct {
MembershipEdge struct {
Node struct {
Profile struct {
ID string `json:"id"`
} `json:"profile"`
} `json:"node"`
} `json:"membershipEdge"`
} `json:"acceptInvitation"`
ActivateAccount struct {
Profile struct {
ID string `json:"id"`
} `json:"profile"`
} `json:"activateAccount"`
}
err := c.ExecuteConnect(query, map[string]any{
"input": map[string]any{
"invitationId": invitationID.String(),
"token": token,
},
}, &result)
require.NoError(c.T, err, "acceptInvitation mutation failed")
profileID, err := gid.ParseGID(result.AcceptInvitation.MembershipEdge.Node.Profile.ID)
require.NoError(c.T, err, "cannot parse profile ID")
return profileID
require.NoError(c.T, err, "activateAccount mutation failed")
}
func (c *Client) assumeOrganizationSession() {
@@ -385,10 +426,6 @@ func (c *Client) GetUserID() gid.GID {
return c.userID
}
func (c *Client) GetProfileID() gid.GID {
return c.profileID
}
func (c *Client) GetOrganizationID() gid.GID {
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 {
BaseURL string
cmd *exec.Cmd
done chan error
MailpitBaseURL string
BaseURL string
cmd *exec.Cmd
done chan error
}
func Setup() {
@@ -94,18 +95,24 @@ func Setup() {
}()
testEnv.BaseURL = "http://localhost:18080"
testEnv.MailpitBaseURL = "http://localhost:8025"
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := waitForServer(ctx, testEnv.BaseURL, 30*time.Second); err != nil {
fmt.Fprintf(os.Stderr, "e2etest: server failed to start: %v\n", err)
if err := waitForServer(ctx, testEnv.BaseURL+"/api/console/v1/graphql", 30*time.Second); err != nil {
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()
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)
client := &http.Client{Timeout: 2 * time.Second}
@@ -116,7 +123,7 @@ func waitForServer(ctx context.Context, baseURL string, timeout time.Duration) e
default:
}
req, err := http.NewRequestWithContext(ctx, "GET", baseURL+"/api/console/v1/graphql", nil)
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil {
return err
}
@@ -157,3 +164,10 @@ func GetBaseURL() string {
}
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).
AppendPath(invitationURLPath).
WithQuery("token", invitationToken).
WithQuery("fullName", vars.RecipientFullName).
MustString()
data := struct {

View File

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

View File

@@ -184,6 +184,27 @@ WHERE
pi.organization_id = i.organization_id
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
iam_invitations
ALTER COLUMN
@@ -197,4 +218,4 @@ ALTER COLUMN
ALTER COLUMN
role DROP NOT NULL,
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"
// Membership Profile actions
ActionMembershipProfileGet = "iam:membership-profile:get"
ActionMembershipProfileList = "iam:membership-profile:list"
ActionMembershipProfileCreate = "iam:membership-profile:create"
ActionMembershipProfileUpdate = "iam:membership-profile:update"
ActionMembershipProfileDelete = "iam:membership-profile:delete"
ActionMembershipProfileGet = "iam:membership-profile:get"
ActionMembershipProfileList = "iam:membership-profile:list"
ActionMembershipProfileCreate = "iam:membership-profile:create"
ActionMembershipProfileUpdate = "iam:membership-profile:update"
ActionMembershipProfileDelete = "iam:membership-profile:delete"
ActionMembershipProfileActivate = "iam:membership-profile:activate"
ActionMembershipProfileDeactivate = "iam:membership-profile:deactivate"
// Personal API Key actions
ActionPersonalAPIKeyCreate = "iam:personal-api-key:create"

View File

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

View File

@@ -427,7 +427,7 @@ func (s *OrganizationService) CreateOrganization(
ctx context.Context,
identityID gid.GID,
req *CreateOrganizationRequest,
) (*coredata.Organization, *coredata.Membership, error) {
) (*coredata.Organization, *coredata.MembershipProfile, error) {
if err := req.Validate(); err != nil {
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 organization, membership, nil
return organization, profile, nil
}
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
}
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) {
profile := &coredata.MembershipProfile{}

View File

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

View File

@@ -74,11 +74,6 @@ type DirectiveRoot struct {
}
type ComplexityRoot struct {
AcceptInvitationPayload struct {
Invitation func(childComplexity int) int
Membership func(childComplexity int) int
}
ActivateAccountPayload struct {
CreatePasswordToken func(childComplexity int) int
Profile func(childComplexity int) int
@@ -105,8 +100,8 @@ type ComplexityRoot struct {
}
CreateOrganizationPayload struct {
Membership func(childComplexity int) int
Organization func(childComplexity int) int
Profile func(childComplexity int) int
}
CreatePersonalAPIKeyPayload struct {
@@ -128,8 +123,8 @@ type ComplexityRoot struct {
ProfileEdge func(childComplexity int) int
}
DeleteInvitationPayload struct {
DeletedInvitationID func(childComplexity int) int
DeactivateUserPayload struct {
Success func(childComplexity int) int
}
DeleteOrganizationHorizontalLogoPayload struct {
@@ -209,6 +204,7 @@ type ComplexityRoot struct {
CreateSAMLConfiguration func(childComplexity int, input types.CreateSAMLConfigurationInput) int
CreateSCIMConfiguration func(childComplexity int, input types.CreateSCIMConfigurationInput) 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
DeleteOrganizationHorizontalLogo func(childComplexity int, input types.DeleteOrganizationHorizontalLogoInput) 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)
CreateUser(ctx context.Context, input types.CreateUserInput) (*types.CreateUserPayload, 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)
UpdateMembership(ctx context.Context, input types.UpdateMembershipInput) (*types.UpdateMembershipPayload, 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
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":
if e.complexity.ActivateAccountPayload.CreatePasswordToken == nil {
break
@@ -721,18 +705,18 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
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":
if e.complexity.CreateOrganizationPayload.Organization == nil {
break
}
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":
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
case "DeleteInvitationPayload.deletedInvitationId":
if e.complexity.DeleteInvitationPayload.DeletedInvitationID == nil {
case "DeactivateUserPayload.success":
if e.complexity.DeactivateUserPayload.Success == nil {
break
}
return e.complexity.DeleteInvitationPayload.DeletedInvitationID(childComplexity), true
return e.complexity.DeactivateUserPayload.Success(childComplexity), true
case "DeleteOrganizationHorizontalLogoPayload.organization":
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
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":
if e.complexity.Mutation.DeleteOrganization == nil {
break
@@ -2346,8 +2341,8 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
opCtx := graphql.GetOperationContext(ctx)
ec := executionContext{opCtx, e, 0, 0, make(chan graphql.DeferredResult)}
inputUnmarshalMap := graphql.BuildUnmarshalerMap(
ec.unmarshalInputAcceptInvitationInput,
ec.unmarshalInputActivateAccountInput,
ec.unmarshalInputActivateUserInput,
ec.unmarshalInputAssumeOrganizationSessionInput,
ec.unmarshalInputChangeEmailInput,
ec.unmarshalInputChangePasswordInput,
@@ -2356,7 +2351,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
ec.unmarshalInputCreateSAMLConfigurationInput,
ec.unmarshalInputCreateSCIMConfigurationInput,
ec.unmarshalInputCreateUserInput,
ec.unmarshalInputDeleteInvitationInput,
ec.unmarshalInputDeactivateUserInput,
ec.unmarshalInputDeleteOrganizationHorizontalLogoInput,
ec.unmarshalInputDeleteOrganizationInput,
ec.unmarshalInputDeleteSAMLConfigurationInput,
@@ -2536,7 +2531,7 @@ type Mutation {
signOut: SignOutPayload @session(required: PRESENT)
activateAccount(
input: ActivateAccountInput!
): ActivateAccountPayload @session(required: NONE)
): ActivateAccountPayload @session(required: OPTIONAL)
forgotPassword(input: ForgotPasswordInput!): ForgotPasswordPayload
@session(required: NONE)
resetPassword(input: ResetPasswordInput!): ResetPasswordPayload
@@ -2579,6 +2574,7 @@ type Mutation {
@session(required: PRESENT)
inviteUser(input: InviteUserInput!): InviteUserPayload
@session(required: PRESENT)
deactivateUser(input: DeactivateUserInput!): DeactivateUserPayload
updateUser(input: UpdateUserInput!): UpdateUserPayload!
updateMembership(input: UpdateMembershipInput!): UpdateMembershipPayload!
removeUser(input: RemoveUserInput!): RemoveUserPayload
@@ -3200,6 +3196,16 @@ input InviteUserInput {
profileId: ID!
}
input ActivateUserInput {
organizationId: ID!
profileId: ID!
}
input DeactivateUserInput {
organizationId: ID!
profileId: ID!
}
input UpdateUserInput {
id: ID!
fullName: String!
@@ -3221,15 +3227,6 @@ input RemoveUserInput {
profileId: ID!
}
input AcceptInvitationInput {
invitationId: ID!
}
input DeleteInvitationInput {
organizationId: ID!
invitationId: ID!
}
input CreateSAMLConfigurationInput {
organizationId: ID!
emailDomain: String!
@@ -3342,7 +3339,7 @@ type RevokePersonalAPIKeyPayload {
type CreateOrganizationPayload {
organization: Organization
membership: Membership!
profile: Profile!
}
type UpdateOrganizationPayload {
@@ -3365,6 +3362,10 @@ type InviteUserPayload {
invitationEdge: InvitationEdge!
}
type DeactivateUserPayload {
success: Boolean!
}
type UpdateUserPayload {
profile: Profile!
}
@@ -3377,15 +3378,6 @@ type RemoveUserPayload {
deletedProfileId: ID!
}
type AcceptInvitationPayload {
membership: Membership!
invitation: Invitation!
}
type DeleteInvitationPayload {
deletedInvitationId: ID!
}
type CreateSAMLConfigurationPayload {
samlConfigurationEdge: SAMLConfigurationEdge!
}
@@ -3731,6 +3723,17 @@ func (ec *executionContext) field_Mutation_createUser_args(ctx context.Context,
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) {
var err error
args := map[string]any{}
@@ -4232,94 +4235,6 @@ func (ec *executionContext) field___Type_fields_args(ctx context.Context, rawArg
// 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) {
return graphql.ResolveField(
ctx,
@@ -4737,23 +4652,23 @@ func (ec *executionContext) fieldContext_CreateOrganizationPayload_organization(
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(
ctx,
ec.OperationContext,
field,
ec.fieldContext_CreateOrganizationPayload_membership,
ec.fieldContext_CreateOrganizationPayload_profile,
func(ctx context.Context) (any, error) {
return obj.Membership, nil
return obj.Profile, 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,
)
}
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{
Object: "CreateOrganizationPayload",
Field: field,
@@ -4762,17 +4677,41 @@ func (ec *executionContext) fieldContext_CreateOrganizationPayload_membership(_
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
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":
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)
return ec.fieldContext_Profile_createdAt(ctx, field)
case "updatedAt":
return ec.fieldContext_Profile_updatedAt(ctx, field)
case "identity":
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":
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
@@ -5037,30 +4976,30 @@ func (ec *executionContext) fieldContext_CreateUserPayload_profileEdge(_ context
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(
ctx,
ec.OperationContext,
field,
ec.fieldContext_DeleteInvitationPayload_deletedInvitationId,
ec.fieldContext_DeactivateUserPayload_success,
func(ctx context.Context) (any, error) {
return obj.DeletedInvitationID, nil
return obj.Success, nil
},
nil,
ec.marshalNID2goᚗproboᚗincᚋproboᚋpkgᚋgidᚐGID,
ec.marshalNBoolean2bool,
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{
Object: "DeleteInvitationPayload",
Object: "DeactivateUserPayload",
Field: field,
IsMethod: false,
IsResolver: false,
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
@@ -6600,7 +6539,7 @@ func (ec *executionContext) _Mutation_activateAccount(ctx context.Context, field
directive0 := next
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 {
var zeroVal *types.ActivateAccountPayload
return zeroVal, err
@@ -7316,8 +7255,8 @@ func (ec *executionContext) fieldContext_Mutation_createOrganization(ctx context
switch field.Name {
case "organization":
return ec.fieldContext_CreateOrganizationPayload_organization(ctx, field)
case "membership":
return ec.fieldContext_CreateOrganizationPayload_membership(ctx, field)
case "profile":
return ec.fieldContext_CreateOrganizationPayload_profile(ctx, field)
}
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
}
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) {
return graphql.ResolveField(
ctx,
@@ -15145,33 +15129,6 @@ func (ec *executionContext) fieldContext___Type_isOneOf(_ context.Context, field
// 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) {
var it types.ActivateAccountInput
asMap := map[string]any{}
@@ -15199,6 +15156,40 @@ func (ec *executionContext) unmarshalInputActivateAccountInput(ctx context.Conte
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) {
var it types.AssumeOrganizationSessionInput
asMap := map[string]any{}
@@ -15562,14 +15553,14 @@ func (ec *executionContext) unmarshalInputCreateUserInput(ctx context.Context, o
return it, nil
}
func (ec *executionContext) unmarshalInputDeleteInvitationInput(ctx context.Context, obj any) (types.DeleteInvitationInput, error) {
var it types.DeleteInvitationInput
func (ec *executionContext) unmarshalInputDeactivateUserInput(ctx context.Context, obj any) (types.DeactivateUserInput, error) {
var it types.DeactivateUserInput
asMap := map[string]any{}
for k, v := range obj.(map[string]any) {
asMap[k] = v
}
fieldsInOrder := [...]string{"organizationId", "invitationId"}
fieldsInOrder := [...]string{"organizationId", "profileId"}
for _, k := range fieldsInOrder {
v, ok := asMap[k]
if !ok {
@@ -15583,13 +15574,13 @@ func (ec *executionContext) unmarshalInputDeleteInvitationInput(ctx context.Cont
return it, err
}
it.OrganizationID = data
case "invitationId":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("invitationId"))
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.InvitationID = data
it.ProfileID = data
}
}
@@ -16704,50 +16695,6 @@ func (ec *executionContext) _Node(ctx context.Context, sel ast.SelectionSet, obj
// 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"}
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")
case "organization":
out.Values[i] = ec._CreateOrganizationPayload_organization(ctx, field, obj)
case "membership":
out.Values[i] = ec._CreateOrganizationPayload_membership(ctx, field, obj)
case "profile":
out.Values[i] = ec._CreateOrganizationPayload_profile(ctx, field, obj)
if out.Values[i] == graphql.Null {
out.Invalids++
}
@@ -17202,19 +17149,19 @@ func (ec *executionContext) _CreateUserPayload(ctx context.Context, sel ast.Sele
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 {
fields := graphql.CollectFields(ec.OperationContext, sel, deleteInvitationPayloadImplementors)
func (ec *executionContext) _DeactivateUserPayload(ctx context.Context, sel ast.SelectionSet, obj *types.DeactivateUserPayload) graphql.Marshaler {
fields := graphql.CollectFields(ec.OperationContext, sel, deactivateUserPayloadImplementors)
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("DeleteInvitationPayload")
case "deletedInvitationId":
out.Values[i] = ec._DeleteInvitationPayload_deletedInvitationId(ctx, field, obj)
out.Values[i] = graphql.MarshalString("DeactivateUserPayload")
case "success":
out.Values[i] = ec._DeactivateUserPayload_success(ctx, field, obj)
if out.Values[i] == graphql.Null {
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) {
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":
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
return ec._Mutation_updateUser(ctx, field)
@@ -21721,6 +21672,11 @@ func (ec *executionContext) marshalNDatetime2timeᚐTime(ctx context.Context, se
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) {
res, err := ec.unmarshalInputDeleteOrganizationHorizontalLogoInput(ctx, v)
return res, graphql.ErrorOnPath(ctx, err)
@@ -23199,6 +23155,13 @@ func (ec *executionContext) marshalODatetime2ᚖtimeᚐTime(ctx context.Context,
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 {
if v == nil {
return graphql.Null

View File

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

View File

@@ -718,7 +718,7 @@ func (r *mutationResolver) CreateOrganization(ctx context.Context, input types.C
Size: input.HorizontalLogoFile.Size,
}
}
organization, membership, err := r.iam.OrganizationService.CreateOrganization(
organization, profile, err := r.iam.OrganizationService.CreateOrganization(
ctx,
identity.ID,
&iam.CreateOrganizationRequest{
@@ -734,7 +734,7 @@ func (r *mutationResolver) CreateOrganization(ctx context.Context, input types.C
return &types.CreateOrganizationPayload{
Organization: types.NewOrganization(organization),
Membership: types.NewMembership(membership),
Profile: types.NewProfile(profile),
}, nil
}
@@ -883,6 +883,28 @@ func (r *mutationResolver) InviteUser(ctx context.Context, input types.InviteUse
}, 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.
func (r *mutationResolver) UpdateUser(ctx context.Context, input types.UpdateUserInput) (*types.UpdateUserPayload, error) {
if err := r.authorize(ctx, input.ID, iam.ActionMembershipProfileUpdate); err != nil {