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