@@ -77,6 +77,7 @@ export function CreatePeopleDialog({ children, connectionId }: Props) {
|
||||
input: {
|
||||
...data,
|
||||
organizationId,
|
||||
additionalEmailAddresses: data.additionalEmailAddresses ?? [],
|
||||
},
|
||||
connections: [connectionId],
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<22054346a606e1ce4a26b02218f87af9>>
|
||||
* @generated SignedSource<<9acf6a96c0398ea5ae6fec887e8d01b1>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -11,7 +11,7 @@
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
export type PeopleKind = "CONTRACTOR" | "EMPLOYEE" | "SERVICE_ACCOUNT";
|
||||
export type CreatePeopleInput = {
|
||||
additionalEmailAddresses?: ReadonlyArray<any> | null | undefined;
|
||||
additionalEmailAddresses: ReadonlyArray<any>;
|
||||
contractEndDate?: any | null | undefined;
|
||||
contractStartDate?: any | null | undefined;
|
||||
fullName: string;
|
||||
|
||||
@@ -58,11 +58,12 @@ func TestPeople_Create(t *testing.T) {
|
||||
|
||||
err := owner.Execute(query, map[string]any{
|
||||
"input": map[string]any{
|
||||
"organizationId": owner.GetOrganizationID().String(),
|
||||
"fullName": "John Doe",
|
||||
"primaryEmailAddress": "john.doe@example.com",
|
||||
"kind": "EMPLOYEE",
|
||||
"position": "Software Engineer",
|
||||
"organizationId": owner.GetOrganizationID().String(),
|
||||
"fullName": "John Doe",
|
||||
"primaryEmailAddress": "john.doe@example.com",
|
||||
"additionalEmailAddresses": []string{},
|
||||
"kind": "EMPLOYEE",
|
||||
"position": "Software Engineer",
|
||||
},
|
||||
}, &result)
|
||||
require.NoError(t, err)
|
||||
@@ -253,9 +254,10 @@ func TestPeople_RequiredFields(t *testing.T) {
|
||||
{
|
||||
name: "missing organizationId",
|
||||
input: map[string]any{
|
||||
"fullName": "Test Person",
|
||||
"primaryEmailAddress": "test@example.com",
|
||||
"kind": "EMPLOYEE",
|
||||
"fullName": "Test Person",
|
||||
"primaryEmailAddress": "test@example.com",
|
||||
"additionalEmailAddresses": []string{},
|
||||
"kind": "EMPLOYEE",
|
||||
},
|
||||
skipOrganization: true,
|
||||
wantErrorContains: "organizationId",
|
||||
@@ -263,42 +265,47 @@ func TestPeople_RequiredFields(t *testing.T) {
|
||||
{
|
||||
name: "missing fullName",
|
||||
input: map[string]any{
|
||||
"primaryEmailAddress": "test@example.com",
|
||||
"kind": "EMPLOYEE",
|
||||
"primaryEmailAddress": "test@example.com",
|
||||
"additionalEmailAddresses": []string{},
|
||||
"kind": "EMPLOYEE",
|
||||
},
|
||||
wantErrorContains: "fullName",
|
||||
},
|
||||
{
|
||||
name: "missing primaryEmailAddress",
|
||||
input: map[string]any{
|
||||
"fullName": "Test Person",
|
||||
"kind": "EMPLOYEE",
|
||||
"fullName": "Test Person",
|
||||
"additionalEmailAddresses": []string{},
|
||||
"kind": "EMPLOYEE",
|
||||
},
|
||||
wantErrorContains: "primaryEmailAddress",
|
||||
},
|
||||
{
|
||||
name: "missing kind",
|
||||
input: map[string]any{
|
||||
"fullName": "Test Person",
|
||||
"primaryEmailAddress": "test@example.com",
|
||||
"fullName": "Test Person",
|
||||
"primaryEmailAddress": "test@example.com",
|
||||
"additionalEmailAddresses": []string{},
|
||||
},
|
||||
wantErrorContains: "kind",
|
||||
},
|
||||
{
|
||||
name: "empty fullName",
|
||||
input: map[string]any{
|
||||
"fullName": "",
|
||||
"primaryEmailAddress": "test@example.com",
|
||||
"kind": "EMPLOYEE",
|
||||
"fullName": "",
|
||||
"primaryEmailAddress": "test@example.com",
|
||||
"additionalEmailAddresses": []string{},
|
||||
"kind": "EMPLOYEE",
|
||||
},
|
||||
wantErrorContains: "full_name",
|
||||
},
|
||||
{
|
||||
name: "invalid kind enum",
|
||||
input: map[string]any{
|
||||
"fullName": "Test Person",
|
||||
"primaryEmailAddress": "test@example.com",
|
||||
"kind": "INVALID_KIND",
|
||||
"fullName": "Test Person",
|
||||
"primaryEmailAddress": "test@example.com",
|
||||
"additionalEmailAddresses": []string{},
|
||||
"kind": "INVALID_KIND",
|
||||
},
|
||||
wantErrorContains: "kind",
|
||||
},
|
||||
|
||||
@@ -908,7 +908,7 @@ func TestRBAC(t *testing.T) {
|
||||
client: owner,
|
||||
query: createPeopleMutation,
|
||||
variables: func() map[string]any {
|
||||
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "fullName": factory.SafeName("Person"), "primaryEmailAddress": factory.SafeEmail(), "kind": "EMPLOYEE"}}
|
||||
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "fullName": factory.SafeName("Person"), "primaryEmailAddress": factory.SafeEmail(), "additionalEmailAddresses": []string{}, "kind": "EMPLOYEE"}}
|
||||
},
|
||||
shouldAllow: true,
|
||||
},
|
||||
@@ -918,7 +918,7 @@ func TestRBAC(t *testing.T) {
|
||||
client: admin,
|
||||
query: createPeopleMutation,
|
||||
variables: func() map[string]any {
|
||||
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "fullName": factory.SafeName("Person"), "primaryEmailAddress": factory.SafeEmail(), "kind": "EMPLOYEE"}}
|
||||
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "fullName": factory.SafeName("Person"), "primaryEmailAddress": factory.SafeEmail(), "additionalEmailAddresses": []string{}, "kind": "EMPLOYEE"}}
|
||||
},
|
||||
shouldAllow: true,
|
||||
},
|
||||
@@ -928,7 +928,7 @@ func TestRBAC(t *testing.T) {
|
||||
client: viewer,
|
||||
query: createPeopleMutation,
|
||||
variables: func() map[string]any {
|
||||
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "fullName": factory.SafeName("Person"), "primaryEmailAddress": factory.SafeEmail(), "kind": "EMPLOYEE"}}
|
||||
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "fullName": factory.SafeName("Person"), "primaryEmailAddress": factory.SafeEmail(), "additionalEmailAddresses": []string{}, "kind": "EMPLOYEE"}}
|
||||
},
|
||||
shouldAllow: false,
|
||||
},
|
||||
@@ -1259,4 +1259,3 @@ func TestRBAC(t *testing.T) {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -92,6 +92,18 @@ func (a Attrs) getBool(key string, defaultVal bool) bool {
|
||||
return defaultVal
|
||||
}
|
||||
|
||||
func (a Attrs) getSlice(key string, defaultVal []string) []string {
|
||||
if a == nil {
|
||||
return defaultVal
|
||||
}
|
||||
if v, ok := a[key]; ok {
|
||||
if slice, ok := v.([]string); ok {
|
||||
return slice
|
||||
}
|
||||
}
|
||||
return defaultVal
|
||||
}
|
||||
|
||||
func CreateVendor(c *testutil.Client, attrs ...Attrs) string {
|
||||
c.T.Helper()
|
||||
|
||||
@@ -375,10 +387,11 @@ func CreatePeople(c *testutil.Client, attrs ...Attrs) string {
|
||||
`
|
||||
|
||||
input := map[string]any{
|
||||
"organizationId": c.GetOrganizationID().String(),
|
||||
"fullName": a.getString("fullName", SafeName("Person")),
|
||||
"primaryEmailAddress": a.getString("primaryEmailAddress", SafeEmail()),
|
||||
"kind": a.getString("kind", "EMPLOYEE"),
|
||||
"organizationId": c.GetOrganizationID().String(),
|
||||
"fullName": a.getString("fullName", SafeName("Person")),
|
||||
"primaryEmailAddress": a.getString("primaryEmailAddress", SafeEmail()),
|
||||
"additionalEmailAddresses": a.getSlice("additionalEmailAddresses", []string{}),
|
||||
"kind": a.getString("kind", "EMPLOYEE"),
|
||||
}
|
||||
|
||||
var result struct {
|
||||
|
||||
@@ -159,6 +159,8 @@ export async function execute(
|
||||
};
|
||||
if (additionalFields.additionalEmailAddresses) {
|
||||
input.additionalEmailAddresses = additionalFields.additionalEmailAddresses.split(',').map((e) => e.trim()).filter(Boolean);
|
||||
} else {
|
||||
input.additionalEmailAddresses = [];
|
||||
}
|
||||
if (additionalFields.position) input.position = additionalFields.position;
|
||||
if (additionalFields.contractStartDate) input.contractStartDate = new Date(additionalFields.contractStartDate).toISOString();
|
||||
|
||||
5
pkg/coredata/migrations/20260102T093953Z.sql
Normal file
5
pkg/coredata/migrations/20260102T093953Z.sql
Normal file
@@ -0,0 +1,5 @@
|
||||
UPDATE peoples
|
||||
SET additional_email_addresses = ARRAY[]::TEXT[]
|
||||
WHERE additional_email_addresses IS NULL;
|
||||
|
||||
ALTER TABLE peoples ALTER COLUMN additional_email_addresses SET NOT NULL;
|
||||
@@ -3523,7 +3523,7 @@ input CreatePeopleInput {
|
||||
organizationId: ID!
|
||||
fullName: String!
|
||||
primaryEmailAddress: EmailAddr!
|
||||
additionalEmailAddresses: [EmailAddr!]
|
||||
additionalEmailAddresses: [EmailAddr!]!
|
||||
kind: PeopleKind!
|
||||
position: String
|
||||
contractStartDate: Datetime
|
||||
|
||||
@@ -13522,7 +13522,7 @@ input CreatePeopleInput {
|
||||
organizationId: ID!
|
||||
fullName: String!
|
||||
primaryEmailAddress: EmailAddr!
|
||||
additionalEmailAddresses: [EmailAddr!]
|
||||
additionalEmailAddresses: [EmailAddr!]!
|
||||
kind: PeopleKind!
|
||||
position: String
|
||||
contractStartDate: Datetime
|
||||
@@ -60752,7 +60752,7 @@ func (ec *executionContext) unmarshalInputCreatePeopleInput(ctx context.Context,
|
||||
it.PrimaryEmailAddress = data
|
||||
case "additionalEmailAddresses":
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("additionalEmailAddresses"))
|
||||
data, err := ec.unmarshalOEmailAddr2ᚕgoᚗproboᚗincᚋproboᚋpkgᚋmailᚐAddrᚄ(ctx, v)
|
||||
data, err := ec.unmarshalNEmailAddr2ᚕgoᚗproboᚗincᚋproboᚋpkgᚋmailᚐAddrᚄ(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
|
||||
@@ -425,7 +425,7 @@ type CreatePeopleInput struct {
|
||||
OrganizationID gid.GID `json:"organizationId"`
|
||||
FullName string `json:"fullName"`
|
||||
PrimaryEmailAddress mail.Addr `json:"primaryEmailAddress"`
|
||||
AdditionalEmailAddresses []mail.Addr `json:"additionalEmailAddresses,omitempty"`
|
||||
AdditionalEmailAddresses []mail.Addr `json:"additionalEmailAddresses"`
|
||||
Kind coredata.PeopleKind `json:"kind"`
|
||||
Position *string `json:"position,omitempty"`
|
||||
ContractStartDate *time.Time `json:"contractStartDate,omitempty"`
|
||||
|
||||
@@ -2073,7 +2073,7 @@ func (r *mutationResolver) CreatePeople(ctx context.Context, input types.CreateP
|
||||
OrganizationID: input.OrganizationID,
|
||||
FullName: input.FullName,
|
||||
PrimaryEmailAddress: input.PrimaryEmailAddress,
|
||||
AdditionalEmailAddresses: []mail.Addr{},
|
||||
AdditionalEmailAddresses: input.AdditionalEmailAddresses,
|
||||
Kind: input.Kind,
|
||||
Position: input.Position,
|
||||
ContractStartDate: input.ContractStartDate,
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
"go.probo.inc/probo/pkg/authz"
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/mail"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
"go.probo.inc/probo/pkg/probo"
|
||||
"go.probo.inc/probo/pkg/server/api/mcp/v1/types"
|
||||
@@ -171,13 +172,18 @@ func (r *Resolver) AddPeopleTool(ctx context.Context, req *mcp.CallToolRequest,
|
||||
|
||||
svc := r.ProboService(ctx, input.OrganizationID)
|
||||
|
||||
additionalEmails := []mail.Addr{}
|
||||
if input.AdditionalEmailAddresses != nil {
|
||||
additionalEmails = input.AdditionalEmailAddresses
|
||||
}
|
||||
|
||||
people, err := svc.Peoples.Create(
|
||||
ctx,
|
||||
probo.CreatePeopleRequest{
|
||||
OrganizationID: input.OrganizationID,
|
||||
FullName: input.FullName,
|
||||
PrimaryEmailAddress: input.PrimaryEmailAddress,
|
||||
AdditionalEmailAddresses: input.AdditionalEmailAddresses,
|
||||
AdditionalEmailAddresses: additionalEmails,
|
||||
Kind: input.Kind,
|
||||
Position: input.Position,
|
||||
ContractStartDate: input.ContractStartDate,
|
||||
|
||||
Reference in New Issue
Block a user