diff --git a/pkg/coredata/people.go b/pkg/coredata/people.go index 077c6b62e..1962277b7 100644 --- a/pkg/coredata/people.go +++ b/pkg/coredata/people.go @@ -16,6 +16,7 @@ package coredata import ( "context" + "errors" "fmt" "maps" "time" @@ -40,8 +41,16 @@ type ( } Peoples []*People + + ErrPeopleNotFound struct { + Identifier string + } ) +func (e ErrPeopleNotFound) Error() string { + return fmt.Sprintf("people not found: %s", e.Identifier) +} + func (p People) CursorKey(orderBy PeopleOrderField) page.CursorKey { switch orderBy { case PeopleOrderFieldCreatedAt: @@ -98,6 +107,55 @@ LIMIT 1; return nil } +func (p *People) LoadByEmail( + ctx context.Context, + conn pg.Conn, + scope Scoper, + primaryEmailAddress string, +) error { + q := ` + SELECT + id, + organization_id, + kind, + user_id, + full_name, + primary_email_address, + additional_email_addresses, + created_at, + updated_at + FROM + peoples + WHERE + %s + AND primary_email_address = @primary_email_address + LIMIT 1; + ` + + q = fmt.Sprintf(q, scope.SQLFragment()) + + args := pgx.StrictNamedArgs{"primary_email_address": primaryEmailAddress} + maps.Copy(args, scope.SQLArguments()) + + rows, err := conn.Query(ctx, q, args) + if err != nil { + return fmt.Errorf("cannot query people: %w", err) + } + + people, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[People]) + if err != nil { + if errors.Is(err, pgx.ErrNoRows) { + return &ErrPeopleNotFound{Identifier: primaryEmailAddress} + } + + return fmt.Errorf("cannot collect people: %w", err) + } + + *p = people + + return nil +} + func (p *People) LoadByUserID( ctx context.Context, conn pg.Conn, @@ -135,6 +193,10 @@ LIMIT 1; people, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[People]) if err != nil { + if errors.Is(err, pgx.ErrNoRows) { + return &ErrPeopleNotFound{Identifier: userID.String()} + } + return fmt.Errorf("cannot collect people: %w", err) } diff --git a/pkg/usrmgr/usrmgr.go b/pkg/usrmgr/usrmgr.go index 9d0057975..f4eabc271 100644 --- a/pkg/usrmgr/usrmgr.go +++ b/pkg/usrmgr/usrmgr.go @@ -660,6 +660,34 @@ func (s Service) InviteUser( return fmt.Errorf("cannot insert user organization: %w", err) } + people := &coredata.People{} + scope := coredata.NewScope(organizationID.TenantID()) + if err := people.LoadByEmail(ctx, tx, scope, emailAddress); err != nil { + var errPeopleNotFound *coredata.ErrPeopleNotFound + + if errors.As(err, &errPeopleNotFound) { + people = &coredata.People{ + ID: gid.New(organizationID.TenantID(), coredata.PeopleEntityType), + OrganizationID: organizationID, + UserID: &user.ID, + FullName: fullName, + PrimaryEmailAddress: emailAddress, + Kind: coredata.PeopleKindContractor, + AdditionalEmailAddresses: []string{}, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + } + + if err := people.Insert(ctx, tx, scope); err != nil { + return fmt.Errorf("cannot insert people: %w", err) + } + + return nil + } + + return fmt.Errorf("cannot load people by email: %w", err) + } + return nil }, )