Skip to content

Commit 0b1857a

Browse files
authored
Extract user creation code into create-user module (#1602)
Part of OPS-3003.
1 parent d01515f commit 0b1857a

8 files changed

Lines changed: 398 additions & 165 deletions

File tree

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Project, ProjectMemberRole, User } from '@openops/shared';
1+
import { User } from '@openops/shared';
22

33
export enum Provider {
44
EMAIL = 'EMAIL',
@@ -8,16 +8,14 @@ export enum Provider {
88
export type AuthenticationServiceHooks = {
99
preSignIn(p: PreParams): Promise<void>;
1010
preSignUp(p: PreSignUpParams): Promise<void>;
11-
postSignUp(p: PostParams): Promise<PostResult>;
12-
postSignIn(p: PostParams): Promise<PostResult>;
11+
postSignUp(p: PostParams): Promise<void>;
12+
postSignIn(p: PostParams): Promise<void>;
1313
};
1414

1515
type PreSignUpParams = {
1616
name: string;
1717
email: string;
1818
password: string;
19-
organizationId: string | null;
20-
provider: Provider;
2119
};
2220

2321
type PreParams = {
@@ -28,15 +26,4 @@ type PreParams = {
2826

2927
type PostParams = {
3028
user: User;
31-
tablesAccessToken: string;
32-
tablesRefreshToken: string;
33-
referringUserId?: string;
34-
};
35-
36-
type PostResult = {
37-
user: User;
38-
project: Project;
39-
token: string;
40-
tablesRefreshToken: string;
41-
projectRole: ProjectMemberRole | null;
4229
};

packages/server/api/src/app/authentication/authentication-service/hooks/community-authentication-hooks.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export const communityAuthenticationServiceHooks: AuthenticationServiceHooks = {
3737
});
3838
}
3939
},
40-
async postSignUp({ user, tablesRefreshToken }) {
40+
async postSignUp({ user }) {
4141
let organization = await organizationService.getOldestOrganization();
4242

4343
const adminUser = await userService.getUserByEmailOrFail({
@@ -66,16 +66,14 @@ export const communityAuthenticationServiceHooks: AuthenticationServiceHooks = {
6666
email: user.email,
6767
workspaceId: organization.tablesWorkspaceId,
6868
});
69-
70-
return getProjectAndToken(user, tablesRefreshToken);
7169
},
7270

73-
async postSignIn({ user, tablesRefreshToken }) {
74-
return getProjectAndToken(user, tablesRefreshToken);
71+
async postSignIn() {
72+
// Empty
7573
},
7674
};
7775

78-
async function getProjectAndToken(
76+
export async function getProjectAndToken(
7977
user: User,
8078
tablesRefreshToken: string,
8179
): Promise<{

packages/server/api/src/app/authentication/authentication-service/index.ts

Lines changed: 18 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,32 @@
11
import { authenticateUserInOpenOpsTables } from '@openops/common';
2-
import { logger, SharedSystemProp, system } from '@openops/server-shared';
32
import {
43
ApplicationError,
54
AuthenticationResponse,
6-
EnvironmentType,
75
ErrorCode,
86
isNil,
9-
OrganizationRole,
107
User,
118
UserId,
129
UserStatus,
1310
} from '@openops/shared';
14-
import { QueryFailedError } from 'typeorm';
15-
import { flagService } from '../../flags/flag.service';
16-
import { openopsTables } from '../../openops-tables';
1711
import { userService } from '../../user/user-service';
1812
import { passwordHasher } from '../basic/password-hasher';
13+
import { createUser } from '../new-user/create-user';
1914
import { authenticationServiceHooks as hooks } from './hooks';
2015
import { Provider } from './hooks/authentication-service-hooks';
16+
import { getProjectAndToken } from './hooks/community-authentication-hooks';
2117

2218
export const authenticationService = {
2319
async signUp(params: SignUpParams): Promise<AuthenticationResponse> {
24-
const name = `${params.firstName} ${params.lastName}`.trim();
25-
await hooks.get().preSignUp({
26-
...params,
27-
name,
28-
});
29-
30-
const { token, refresh_token } = await openopsTables.createUser({
31-
name,
32-
email: params.email,
33-
password: params.password,
34-
authenticate: true,
35-
});
20+
const { user, tablesRefreshToken } = await createUser(params);
3621

37-
const user = await createUser(params);
38-
39-
return this.signUpResponse({
22+
await hooks.get().postSignUp({
4023
user,
41-
tablesAccessToken: token,
42-
tablesRefreshToken: refresh_token,
43-
referringUserId: params.referringUserId,
4424
});
25+
26+
return this.authResponse(user, tablesRefreshToken);
4527
},
4628

4729
async signIn(request: SignInParams): Promise<AuthenticationResponse> {
48-
await hooks.get().preSignIn(request);
49-
5030
const user = await userService.getByOrganizationAndEmail({
5131
organizationId: request.organizationId,
5232
email: request.email,
@@ -59,98 +39,30 @@ export const authenticationService = {
5939
userPassword: user.password,
6040
});
6141

62-
const { token, refresh_token } = await authenticateUserInOpenOpsTables(
42+
const { refresh_token } = await authenticateUserInOpenOpsTables(
6343
request.email,
6444
request.password,
6545
);
6646

67-
return this.signInResponse({
68-
user,
69-
tablesAccessToken: token,
70-
tablesRefreshToken: refresh_token,
71-
});
47+
return this.authResponse(user, refresh_token);
7248
},
7349

74-
async signUpResponse({
75-
user,
76-
tablesAccessToken,
77-
tablesRefreshToken,
78-
referringUserId,
79-
}: SignUpResponseParams): Promise<AuthenticationResponse> {
80-
const authnResponse = await hooks.get().postSignUp({
81-
user,
82-
tablesAccessToken,
83-
tablesRefreshToken,
84-
referringUserId,
85-
});
86-
87-
const userWithoutPassword = removePasswordPropFromUser(authnResponse.user);
50+
async authResponse(
51+
user: User,
52+
tablesRefreshToken: string,
53+
): Promise<AuthenticationResponse> {
54+
const projectContext = await getProjectAndToken(user, tablesRefreshToken);
8855

89-
await saveNewsLetterSubscriber(user);
56+
const userWithoutPassword = removePasswordPropFromUser(projectContext.user);
9057

9158
return {
9259
...userWithoutPassword,
93-
token: authnResponse.token,
94-
projectId: authnResponse.project.id,
95-
projectRole: authnResponse.projectRole,
96-
tablesRefreshToken: authnResponse.tablesRefreshToken,
60+
token: projectContext.token,
61+
projectId: projectContext.project.id,
62+
projectRole: projectContext.projectRole,
63+
tablesRefreshToken: projectContext.tablesRefreshToken,
9764
};
9865
},
99-
100-
async signInResponse({
101-
user,
102-
tablesAccessToken,
103-
tablesRefreshToken,
104-
}: SignInResponseParams): Promise<AuthenticationResponse> {
105-
const authnResponse = await hooks.get().postSignIn({
106-
user,
107-
tablesAccessToken,
108-
tablesRefreshToken,
109-
});
110-
111-
const userWithoutPassword = removePasswordPropFromUser(authnResponse.user);
112-
113-
return {
114-
...userWithoutPassword,
115-
token: authnResponse.token,
116-
projectId: authnResponse.project.id,
117-
projectRole: authnResponse.projectRole,
118-
tablesRefreshToken: authnResponse.tablesRefreshToken,
119-
};
120-
},
121-
};
122-
123-
const createUser = async (params: SignUpParams): Promise<User> => {
124-
try {
125-
const newUser: NewUser = {
126-
email: params.email,
127-
organizationRole: OrganizationRole.MEMBER,
128-
verified: params.verified,
129-
status: UserStatus.ACTIVE,
130-
firstName: params.firstName,
131-
lastName: params.lastName,
132-
trackEvents: params.trackEvents,
133-
newsLetter: params.newsLetter,
134-
password: params.password,
135-
organizationId: params.organizationId,
136-
};
137-
138-
const user = await userService.create(newUser);
139-
140-
return user;
141-
} catch (e: unknown) {
142-
if (e instanceof QueryFailedError) {
143-
throw new ApplicationError({
144-
code: ErrorCode.EXISTING_USER,
145-
params: {
146-
email: params.email,
147-
organizationId: params.organizationId,
148-
},
149-
});
150-
}
151-
152-
throw e;
153-
}
15466
};
15567

15668
const assertUserIsAllowedToSignIn: (
@@ -202,34 +114,6 @@ const removePasswordPropFromUser = (user: User): Omit<User, 'password'> => {
202114
return filteredUser;
203115
};
204116

205-
async function saveNewsLetterSubscriber(user: User): Promise<void> {
206-
const isOrganizationUserOrNotSubscribed =
207-
(!isNil(user.organizationId) &&
208-
!flagService.isCloudOrganization(user.organizationId)) ||
209-
!user.newsLetter;
210-
const environment = system.get(SharedSystemProp.ENVIRONMENT);
211-
if (
212-
isOrganizationUserOrNotSubscribed ||
213-
environment !== EnvironmentType.PRODUCTION
214-
) {
215-
return;
216-
}
217-
try {
218-
const response = await fetch('/addContact', {
219-
method: 'POST',
220-
headers: {
221-
'Content-Type': 'application/json',
222-
},
223-
body: JSON.stringify({ email: user.email }),
224-
});
225-
return await response.json();
226-
} catch (error) {
227-
logger.warn(error);
228-
}
229-
}
230-
231-
type NewUser = Omit<User, 'id' | 'created' | 'updated'>;
232-
233117
type SignUpParams = {
234118
email: string;
235119
password: string;
@@ -239,7 +123,6 @@ type SignUpParams = {
239123
newsLetter: boolean;
240124
verified: boolean;
241125
organizationId: string | null;
242-
referringUserId?: string;
243126
provider: Provider;
244127
};
245128

0 commit comments

Comments
 (0)