Fix people in mcp

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2026-01-02 10:20:13 +01:00
parent 6ab5ace353
commit aba51629c0
12 changed files with 69 additions and 36 deletions

View File

@@ -77,6 +77,7 @@ export function CreatePeopleDialog({ children, connectionId }: Props) {
input: {
...data,
organizationId,
additionalEmailAddresses: data.additionalEmailAddresses ?? [],
},
connections: [connectionId],
},

View File

@@ -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;

View File

@@ -61,6 +61,7 @@ func TestPeople_Create(t *testing.T) {
"organizationId": owner.GetOrganizationID().String(),
"fullName": "John Doe",
"primaryEmailAddress": "john.doe@example.com",
"additionalEmailAddresses": []string{},
"kind": "EMPLOYEE",
"position": "Software Engineer",
},
@@ -255,6 +256,7 @@ func TestPeople_RequiredFields(t *testing.T) {
input: map[string]any{
"fullName": "Test Person",
"primaryEmailAddress": "test@example.com",
"additionalEmailAddresses": []string{},
"kind": "EMPLOYEE",
},
skipOrganization: true,
@@ -264,6 +266,7 @@ func TestPeople_RequiredFields(t *testing.T) {
name: "missing fullName",
input: map[string]any{
"primaryEmailAddress": "test@example.com",
"additionalEmailAddresses": []string{},
"kind": "EMPLOYEE",
},
wantErrorContains: "fullName",
@@ -272,6 +275,7 @@ func TestPeople_RequiredFields(t *testing.T) {
name: "missing primaryEmailAddress",
input: map[string]any{
"fullName": "Test Person",
"additionalEmailAddresses": []string{},
"kind": "EMPLOYEE",
},
wantErrorContains: "primaryEmailAddress",
@@ -281,6 +285,7 @@ func TestPeople_RequiredFields(t *testing.T) {
input: map[string]any{
"fullName": "Test Person",
"primaryEmailAddress": "test@example.com",
"additionalEmailAddresses": []string{},
},
wantErrorContains: "kind",
},
@@ -289,6 +294,7 @@ func TestPeople_RequiredFields(t *testing.T) {
input: map[string]any{
"fullName": "",
"primaryEmailAddress": "test@example.com",
"additionalEmailAddresses": []string{},
"kind": "EMPLOYEE",
},
wantErrorContains: "full_name",
@@ -298,6 +304,7 @@ func TestPeople_RequiredFields(t *testing.T) {
input: map[string]any{
"fullName": "Test Person",
"primaryEmailAddress": "test@example.com",
"additionalEmailAddresses": []string{},
"kind": "INVALID_KIND",
},
wantErrorContains: "kind",

View File

@@ -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) {
)
}
}

View File

@@ -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()
@@ -378,6 +390,7 @@ func CreatePeople(c *testutil.Client, attrs ...Attrs) string {
"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"),
}

View File

@@ -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();

View 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;

View File

@@ -3523,7 +3523,7 @@ input CreatePeopleInput {
organizationId: ID!
fullName: String!
primaryEmailAddress: EmailAddr!
additionalEmailAddresses: [EmailAddr!]
additionalEmailAddresses: [EmailAddr!]!
kind: PeopleKind!
position: String
contractStartDate: Datetime

View File

@@ -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
}

View File

@@ -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"`

View File

@@ -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,

View File

@@ -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,