@@ -8,8 +8,13 @@ import {
88import { FederatedGraphRepository } from '../../repositories/FederatedGraphRepository.js' ;
99import { OnboardingRepository } from '../../repositories/OnboardingRepository.js' ;
1010import { OrganizationRepository } from '../../repositories/OrganizationRepository.js' ;
11+ import { UserInviteService } from '../../services/UserInviteService.js' ;
12+ import { AuditLogRepository } from '../../repositories/AuditLogRepository.js' ;
1113import type { RouterOptions } from '../../routes.js' ;
1214import { enrichLogger , getLogger , handleError } from '../../util.js' ;
15+ import { UnauthorizedError } from '../../errors/errors.js' ;
16+ import { OrganizationGroupRepository } from '../../repositories/OrganizationGroupRepository.js' ;
17+ import { organizationNameSchema } from '../../constants.js' ;
1318
1419export function createOnboarding (
1520 opts : RouterOptions ,
@@ -22,8 +27,9 @@ export function createOnboarding(
2227 const authContext = await opts . authenticator . authenticate ( ctx . requestHeader ) ;
2328 logger = enrichLogger ( ctx , logger , authContext ) ;
2429
30+ const organizationId = authContext . organizationId ;
2531 const orgRepo = new OrganizationRepository ( logger , opts . db , opts . billingDefaultPlanId ) ;
26- const org = await orgRepo . byId ( authContext . organizationId ) ;
32+ const org = await orgRepo . byId ( organizationId ) ;
2733
2834 if ( ! org || org . creatorUserId !== authContext . userId ) {
2935 return {
@@ -35,10 +41,69 @@ export function createOnboarding(
3541 } ;
3642 }
3743
38- // TODO: handle invitation flow + organization renaming
44+ const auditLogRepo = new AuditLogRepository ( opts . db ) ;
45+ if ( authContext . organizationDeactivated || ! authContext . rbac . isOrganizationAdmin ) {
46+ throw new UnauthorizedError ( ) ;
47+ }
48+
49+ const validatedName = organizationNameSchema . safeParse ( req . organizationName ) ;
50+ if ( ! validatedName . success ) {
51+ return {
52+ response : {
53+ code : EnumStatusCode . ERR_BAD_REQUEST ,
54+ details : validatedName . error . errors [ 0 ] ?. message || 'Invalid organization name' ,
55+ } ,
56+ federatedGraphsCount : 0 ,
57+ } ;
58+ }
59+
60+ const onboardingRepo = new OnboardingRepository ( opts . db , organizationId ) ;
61+ const fedGraphRepo = new FederatedGraphRepository ( logger , opts . db , organizationId ) ;
62+ const organizationGroupRepo = new OrganizationGroupRepository ( opts . db ) ;
63+ const orgGroup = await organizationGroupRepo . byName ( {
64+ organizationId,
65+ name : 'organization-developer' ,
66+ } ) ;
3967
40- const onboardingRepo = new OnboardingRepository ( opts . db , authContext . organizationId ) ;
41- const fedGraphRepo = new FederatedGraphRepository ( logger , opts . db , authContext . organizationId ) ;
68+ const service = new UserInviteService ( {
69+ db : opts . db ,
70+ logger,
71+ keycloakRealm : opts . keycloakRealm ,
72+ keycloak : opts . keycloakClient ,
73+ mailer : opts . mailerClient ,
74+ } ) ;
75+
76+ async function createInvitationPromise ( {
77+ email,
78+ organizationId,
79+ userId,
80+ groupId,
81+ } : {
82+ email : string ;
83+ organizationId : string ;
84+ userId : string ;
85+ groupId : string ;
86+ } ) {
87+ await service . inviteUser ( {
88+ organizationId,
89+ inviterUserId : userId ,
90+ email,
91+ groups : [ groupId ] ,
92+ } ) ;
93+
94+ await auditLogRepo . addAuditLog ( {
95+ organizationId,
96+ organizationSlug : authContext . organizationSlug ,
97+ auditAction : 'organization_invitation.created' ,
98+ action : 'created' ,
99+ actorId : authContext . userId ,
100+ auditableDisplayName : email ,
101+ auditableType : 'user' ,
102+ actorDisplayName : authContext . userDisplayName ,
103+ apiKeyName : authContext . apiKeyName ,
104+ actorType : authContext . auth === 'api_key' ? 'api_key' : 'user' ,
105+ } ) ;
106+ }
42107
43108 const [ onboarding , federatedGraphsCount ] = await Promise . all ( [
44109 onboardingRepo . createOrUpdate ( {
@@ -47,6 +112,24 @@ export function createOnboarding(
47112 email : req . email ,
48113 } ) ,
49114 fedGraphRepo . count ( ) ,
115+ ...( validatedName . data === org . name
116+ ? [ ]
117+ : [
118+ orgRepo . updateOrganizationName ( {
119+ id : org . id ,
120+ name : validatedName . data ,
121+ } ) ,
122+ ] ) ,
123+ ...( req . invititationEmails . length > 0 && orgGroup
124+ ? req . invititationEmails . map ( ( email ) =>
125+ createInvitationPromise ( {
126+ email,
127+ organizationId,
128+ userId : authContext . userId ,
129+ groupId : orgGroup ! . groupId ,
130+ } ) ,
131+ )
132+ : [ ] ) ,
50133 ] ) ;
51134
52135 return {
0 commit comments