Skip to content
This repository was archived by the owner on Jun 13, 2025. It is now read-only.

Commit 91db4dd

Browse files
fix: once invites are accepted the page is stuck
1 parent 15d8e34 commit 91db4dd

File tree

13 files changed

+29
-185
lines changed

13 files changed

+29
-185
lines changed

.env.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
VERSION=0.3.0-alpha
1+
VERSION=0.3.1-alpha
22
NODE_ENV=development
33

44

apps/server/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "server",
3-
"version": "0.3.0",
3+
"version": "0.3.1",
44
"description": "Tegon server",
55
"author": "Tegon",
66
"private": true,
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import Passwordless from 'supertokens-node/recipe/passwordless';
2+
3+
export async function createMagicLink(email: string) {
4+
const magicLink = await Passwordless.createMagicLink({
5+
email,
6+
tenantId: 'public',
7+
});
8+
9+
return magicLink;
10+
}

apps/server/src/modules/auth/supertokens/supertokens.service.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { Injectable } from '@nestjs/common';
22
import { MailerService } from '@nestjs-modules/mailer';
33
import supertokens, { deleteUser } from 'supertokens-node';
4-
import EmailPassword from 'supertokens-node/recipe/emailpassword';
54

65
import { UsersService } from 'modules/users/users.service';
76

@@ -28,10 +27,6 @@ export class SupertokensService {
2827
});
2928
}
3029

31-
getEmailPasswordRecipe() {
32-
return EmailPassword;
33-
}
34-
3530
async deleteUserForId(userId: string) {
3631
await deleteUser(userId);
3732
}

apps/server/src/modules/users/users.controller.ts

Lines changed: 1 addition & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import { SessionContainer } from 'supertokens-node/recipe/session';
1919

2020
import { AuthGuard } from 'modules/auth/auth.guard';
2121
import { Session as SessionDecorator } from 'modules/auth/session.decorator';
22-
import { SupertokensService } from 'modules/auth/supertokens/supertokens.service';
2322

2423
import {
2524
UpdateUserBody,
@@ -33,10 +32,7 @@ import { UsersService } from './users.service';
3332
path: 'users',
3433
})
3534
export class UsersController {
36-
constructor(
37-
private usersService: UsersService,
38-
private supertokensService: SupertokensService,
39-
) {}
35+
constructor(private usersService: UsersService) {}
4036

4137
@Get()
4238
@UseGuards(AuthGuard)
@@ -62,41 +58,6 @@ export class UsersController {
6258
return user;
6359
}
6460

65-
@Post('change_password')
66-
@UseGuards(AuthGuard)
67-
async changePassword(
68-
@SessionDecorator() session: SessionContainer,
69-
@Body() passwordBody: Record<string, string>,
70-
) {
71-
const userId = session.getUserId();
72-
return await this.usersService.changePassword(
73-
this.supertokensService,
74-
userId,
75-
session,
76-
passwordBody,
77-
);
78-
}
79-
80-
@Post('forgot_password')
81-
async sendPasswordResetEmail(@Body() forgotBody: Record<string, string>) {
82-
return await this.usersService.sendPasswordResetEmail(
83-
this.supertokensService,
84-
forgotBody.email,
85-
);
86-
}
87-
88-
@Post('forgot_password/:token')
89-
async resetPassword(
90-
@Param('token') token: string,
91-
@Body('newPassword') newPassword: string,
92-
) {
93-
return this.usersService.resetPassword(
94-
this.supertokensService,
95-
token,
96-
newPassword,
97-
);
98-
}
99-
10061
@Post('pat')
10162
@UseGuards(AuthGuard)
10263
async createPersonalAccessToken(

apps/server/src/modules/users/users.service.ts

Lines changed: 2 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
1-
import { BadRequestException, Injectable, Logger } from '@nestjs/common';
2-
import { MailerService } from '@nestjs-modules/mailer';
1+
import { Injectable } from '@nestjs/common';
32
import { Prisma } from '@prisma/client';
43
import { GetUsersDto, PublicUser, User } from '@tegonhq/types';
54
import { PrismaService } from 'nestjs-prisma';
6-
import supertokens from 'supertokens-node';
7-
import { SessionContainer } from 'supertokens-node/recipe/session';
85

96
import {
107
generateKeyForUserId,
118
generatePersonalAccessToken,
129
} from 'common/authentication';
1310

14-
import { SupertokensService } from 'modules/auth/supertokens/supertokens.service';
15-
1611
import {
1712
UpdateUserBody,
1813
userSerializer,
@@ -21,11 +16,7 @@ import {
2116

2217
@Injectable()
2318
export class UsersService {
24-
private readonly logger: Logger = new Logger('UserService');
25-
constructor(
26-
private prisma: PrismaService,
27-
private mailerService: MailerService,
28-
) {}
19+
constructor(private prisma: PrismaService) {}
2920

3021
async upsertUser(
3122
id: string,
@@ -127,125 +118,6 @@ export class UsersService {
127118
return userSerializer(user);
128119
}
129120

130-
async changePassword(
131-
supertokensService: SupertokensService,
132-
userId: string,
133-
session: SessionContainer,
134-
passwordBody: Record<string, string>,
135-
) {
136-
const oldPassword = passwordBody.oldPassword;
137-
const newPassword = passwordBody.newPassword;
138-
139-
const userInfo = await supertokens.getUser(userId);
140-
141-
if (userInfo === undefined) {
142-
throw new BadRequestException('User not found');
143-
}
144-
145-
const loginMethod = userInfo.loginMethods.find(
146-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
147-
(lM: any) =>
148-
lM.recipeUserId.getAsString() ===
149-
session.getRecipeUserId().getAsString() &&
150-
lM.recipeId === 'emailpassword',
151-
);
152-
153-
if (loginMethod === undefined) {
154-
throw new BadRequestException(`You've signed up with different method`);
155-
}
156-
const email = loginMethod.email;
157-
158-
const EmailPassword = supertokensService.getEmailPasswordRecipe();
159-
160-
const isPasswordValid = await EmailPassword.signIn(
161-
session!.getTenantId(),
162-
email,
163-
oldPassword,
164-
);
165-
166-
if (isPasswordValid.status !== 'OK') {
167-
throw new BadRequestException(`Your current password didn't match`);
168-
}
169-
170-
// update the user's password using updateEmailOrPassword
171-
const response = await EmailPassword.updateEmailOrPassword({
172-
recipeUserId: session.getRecipeUserId(),
173-
password: newPassword,
174-
tenantIdForPasswordPolicy: session.getTenantId(),
175-
});
176-
177-
if (response.status === 'PASSWORD_POLICY_VIOLATED_ERROR') {
178-
// TODO: handle incorrect password error
179-
throw new BadRequestException(
180-
`Your new password didn't match with the policy`,
181-
);
182-
}
183-
184-
return { message: 'Successful' };
185-
}
186-
187-
async sendPasswordResetEmail(
188-
supertokensService: SupertokensService,
189-
email: string,
190-
) {
191-
const EmailPassword = supertokensService.getEmailPasswordRecipe();
192-
193-
const user = await this.prisma.user.findUnique({
194-
where: { email },
195-
});
196-
197-
if (!user) {
198-
throw new BadRequestException('User not found');
199-
}
200-
201-
const response = await EmailPassword.createResetPasswordLink(
202-
undefined,
203-
user.id,
204-
email,
205-
);
206-
207-
if (response.status === 'OK') {
208-
await this.mailerService.sendMail({
209-
to: user.email,
210-
subject: 'Password Reset',
211-
template: 'resetPassword',
212-
context: {
213-
username: user.fullname,
214-
resetUrl: response.link,
215-
},
216-
});
217-
this.logger.log('Reset Email sent to user');
218-
}
219-
220-
return response;
221-
}
222-
223-
async resetPassword(
224-
supertokensService: SupertokensService,
225-
token: string,
226-
newPassword: string,
227-
) {
228-
const EmailPassword = supertokensService.getEmailPasswordRecipe();
229-
230-
const response = await EmailPassword.resetPasswordUsingToken(
231-
undefined,
232-
token,
233-
newPassword,
234-
);
235-
236-
if (response.status === 'PASSWORD_POLICY_VIOLATED_ERROR') {
237-
throw new BadRequestException(
238-
`Your new password didn't match with the policy`,
239-
);
240-
} else if (response.status === 'RESET_PASSWORD_INVALID_TOKEN_ERROR') {
241-
throw new BadRequestException(`Invalid reset password token`);
242-
} else if (response.status === 'OK') {
243-
return { message: 'Successful' };
244-
}
245-
246-
throw new BadRequestException(response.status);
247-
}
248-
249121
async getInvitesForUser(email: string) {
250122
const invites = await this.prisma.invite.findMany({
251123
where: { emailId: email, deleted: null },

apps/server/src/modules/workspaces/workspaces.service.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import {
1111
import { PrismaService } from 'nestjs-prisma';
1212
import { SessionContainer } from 'supertokens-node/recipe/session';
1313

14+
import { createMagicLink } from 'common/utils/login';
15+
1416
import { workflowSeedData } from 'modules/teams/teams.interface';
1517
import { UsersService } from 'modules/users/users.service';
1618

@@ -229,14 +231,16 @@ export default class WorkspacesService {
229231
},
230232
});
231233

234+
const magicLink = await createMagicLink(email);
235+
232236
await this.mailerService.sendMail({
233237
to: email,
234238
subject: `Invite to ${workspace.name}`,
235239
template: 'inviteUser',
236240
context: {
237241
workspaceName: workspace.name,
238242
inviterName: iniviter.fullname,
239-
invitationUrl: `${process.env.FRONTEND_HOST}/auth`,
243+
invitationUrl: magicLink,
240244
},
241245
});
242246
this.logger.log('Invite Email sent to user');

apps/webapp/.prod.env

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
NEXT_PUBLIC_VERSION=0.3.0-alpha
1+
NEXT_PUBLIC_VERSION=0.3.1-alpha
22
NEXT_PUBLIC_BASE_HOST=PROD_NEXT_PUBLIC_BASE_HOST
33
NEXT_PUBLIC_BACKEND_HOST=PROD_NEXT_PUBLIC_BACKEND_HOST
44
NEXT_PUBLIC_SENTRY_DSN=PROD_NEXT_PUBLIC_SENTRY_DSN

apps/webapp/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "webapp",
3-
"version": "0.3.0",
3+
"version": "0.3.1",
44
"private": true,
55
"scripts": {
66
"dev": "next dev",

apps/webapp/src/modules/invites/invites.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,16 @@ export function Invites() {
1717
const context = React.useContext(UserContext);
1818
const { toast } = useToast();
1919
const router = useRouter();
20+
2021
const { mutate: inviteAction, isLoading } = useInviteActionMutation({
2122
onSuccess: (data: Invite) => {
2223
if (data.status === 'ACCEPTED') {
23-
router.replace('/');
2424
toast({
2525
title: 'Invitation accepted',
2626
description: 'Current invitation for the workspace has been accepted',
2727
});
28+
29+
window.location.reload();
2830
}
2931
},
3032
});

0 commit comments

Comments
 (0)