Skip to content

Commit 901c84a

Browse files
committed
Update user actions
1 parent aceb7ea commit 901c84a

15 files changed

+443
-77
lines changed

app/actions/user.ts

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
'use server';
2+
3+
import { db } from '@/drizzle/db';
4+
import { verifySession } from '@/app/auth/02-stateless-session';
5+
import { deleteDbSession } from '@/app/auth/02-database-session';
6+
import { users } from '@/drizzle/schema';
7+
import { eq } from 'drizzle-orm';
8+
import { getUser } from '../auth/03-dal';
9+
10+
interface User {
11+
id: number;
12+
name: string;
13+
email: string;
14+
}
15+
16+
export async function fetchUsers(): Promise<User[]> {
17+
try {
18+
const dbUsers = await db.select().from(users);
19+
return dbUsers;
20+
} catch (error) {
21+
console.error('Error fetching users:', error);
22+
throw new Error('Failed to fetch users');
23+
}
24+
}
25+
26+
export const deleteUser = async () => {
27+
console.log('deleteUser function called');
28+
29+
// Verify session
30+
const session = await verifySession();
31+
if (!session) {
32+
console.log('Session verification failed');
33+
return { success: false };
34+
}
35+
console.log('Session verified:', session);
36+
37+
// Get user
38+
const user = await getUser();
39+
if (!user) {
40+
console.log('User not found');
41+
return { success: false };
42+
}
43+
console.log('User found:', user);
44+
45+
try {
46+
// Attempt to delete session
47+
console.log('Attempting to delete session for user id:', session.userId);
48+
const sessionDeleteResponse = await deleteDbSession(session.userId);
49+
50+
// Ensure the session deletion was successful
51+
if (!sessionDeleteResponse) {
52+
console.log('Failed to delete session');
53+
return { success: false };
54+
}
55+
56+
console.log('Session deleted successfully');
57+
58+
// Attempt to delete user
59+
console.log('Attempting to delete user with id:', session.userId);
60+
const userDeleteResponse = await db
61+
.delete(users)
62+
.where(eq(users.id, session.userId));
63+
64+
// Check the result of the delete operation
65+
console.log('Delete user response:', userDeleteResponse);
66+
67+
if (!userDeleteResponse) {
68+
console.log('Failed to delete user');
69+
return { success: false };
70+
}
71+
72+
console.log('User deleted successfully');
73+
return { success: true };
74+
} catch (error) {
75+
console.error('Error deleting user:', error);
76+
throw new Error('Failed to delete user');
77+
}
78+
};

app/api/users/route.ts

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { NextRequest, NextResponse } from 'next/server';
2+
import { cookies } from 'next/headers';
3+
4+
import { decrypt } from '../../auth/02-database-session';
5+
import { fetchUsers } from '../../actions/user';
6+
7+
interface User {
8+
id: number;
9+
name: string;
10+
email: string;
11+
}
12+
13+
export async function GET(req: NextRequest, res: NextResponse<User | null>) {
14+
try {
15+
const cookie = cookies().get('session')?.value;
16+
17+
if (!cookie) {
18+
return new NextResponse(null, { status: 401 });
19+
}
20+
const session = await decrypt(cookie);
21+
22+
if (!session?.userId) {
23+
return new NextResponse(null, { status: 401 });
24+
}
25+
26+
const users = await fetchUsers();
27+
28+
return new NextResponse(JSON.stringify(users), { status: 200 });
29+
} catch (error) {
30+
// Handle errors appropriately
31+
console.error('Error fetching user:', error);
32+
return new NextResponse(null, { status: 500 });
33+
}
34+
}

app/auth/01-auth.ts

+35-23
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,33 @@ import {
77
LoginFormSchema,
88
SignupFormSchema,
99
} from '@/app/auth/definitions';
10-
import { createSession, deleteSession } from '@/app/auth/02-stateless-session';
10+
import {
11+
createDbSession,
12+
deleteDbSession,
13+
} from '@/app/auth/02-database-session'; // Ensure correct import
1114
import bcrypt from 'bcrypt';
1215
import { eq } from 'drizzle-orm';
16+
import { redirect } from 'next/navigation';
17+
import { getUser } from './03-dal';
1318

1419
export async function signup(
1520
state: FormState,
1621
formData: FormData,
1722
): Promise<FormState> {
18-
// 1. Validate form fields
1923
const validatedFields = SignupFormSchema.safeParse({
2024
name: formData.get('name'),
2125
email: formData.get('email'),
2226
password: formData.get('password'),
2327
});
2428

25-
// If any form fields are invalid, return early
2629
if (!validatedFields.success) {
2730
return {
2831
errors: validatedFields.error.flatten().fieldErrors,
2932
};
3033
}
3134

32-
// 2. Prepare data for insertion into database
3335
const { name, email, password } = validatedFields.data;
3436

35-
// 3. Check if the user's email already exists
3637
const existingUser = await db.query.users.findFirst({
3738
where: eq(users.email, email),
3839
});
@@ -43,10 +44,8 @@ export async function signup(
4344
};
4445
}
4546

46-
// Hash the user's password
4747
const hashedPassword = await bcrypt.hash(password, 10);
4848

49-
// 3. Insert the user into the database or call an Auth Provider's API
5049
const data = await db
5150
.insert(users)
5251
.values({
@@ -64,58 +63,71 @@ export async function signup(
6463
};
6564
}
6665

67-
// 4. Create a session for the user
68-
const userId = user.id.toString();
69-
await createSession(userId);
66+
const userId = user.id;
67+
await createDbSession(userId);
68+
69+
redirect('/dashboard');
7070
}
7171

7272
export async function login(
7373
state: FormState,
7474
formData: FormData,
7575
): Promise<FormState> {
76-
// 1. Validate form fields
7776
const validatedFields = LoginFormSchema.safeParse({
7877
email: formData.get('email'),
7978
password: formData.get('password'),
8079
});
8180
const errorMessage = { message: 'Invalid login credentials.' };
8281

83-
// If any form fields are invalid, return early
8482
if (!validatedFields.success) {
8583
return {
8684
errors: validatedFields.error.flatten().fieldErrors,
8785
};
8886
}
8987

90-
// 2. Query the database for the user with the given email
9188
const user = await db.query.users.findFirst({
9289
where: eq(users.email, validatedFields.data.email),
9390
});
9491

95-
// If user is not found, return early
9692
if (!user) {
9793
return errorMessage;
9894
}
99-
// 3. Compare the user's password with the hashed password in the database
95+
10096
const passwordMatch = await bcrypt.compare(
10197
validatedFields.data.password,
10298
user.password,
10399
);
104100

105-
// If the password does not match, return early
106101
if (!passwordMatch) {
107102
return errorMessage;
108103
}
109104

110-
// 4. If login successful, create a session for the user and redirect
111-
const userId = user.id.toString();
112-
await createSession(userId);
105+
const userId = user.id;
106+
await createDbSession(userId);
113107

114-
return {
115-
message: 'Login successful.',
116-
};
108+
redirect('/dashboard');
117109
}
118110

119111
export async function logout() {
120-
deleteSession();
112+
try {
113+
const user = await getUser(); // get the current logged-in user
114+
if (!user) {
115+
console.log('No user logged in');
116+
return {
117+
message: 'No user logged in',
118+
};
119+
}
120+
121+
const userId = user.id;
122+
console.log('Logging out user with ID:', userId);
123+
124+
const result = await deleteDbSession(userId);
125+
if (result.success) {
126+
console.log('Successfully logged out');
127+
} else {
128+
console.log('Failed to log out');
129+
}
130+
} catch (error) {
131+
console.error('Error during logout:', error);
132+
}
121133
}

app/auth/02-database-session.ts

+53-16
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { cookies } from 'next/headers';
55
import type { SessionPayload } from '@/app/auth/definitions';
66
import { sessions } from '@/drizzle/schema';
77
import { db } from '@/drizzle/db';
8+
import { eq } from 'drizzle-orm';
9+
import { createLocalSession } from './02-stateless-session';
810

911
const secretKey = process.env.SECRET;
1012
if (!secretKey) {
@@ -32,40 +34,75 @@ export async function decrypt(session: string | undefined = '') {
3234
}
3335
}
3436

35-
export async function createSession(id: number) {
37+
export async function createDbSession(userId: number) {
3638
const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000);
3739

3840
try {
39-
// 1. Create a session in the database
4041
const data = await db
4142
.insert(sessions)
4243
.values({
43-
userId: id,
44-
expiresAt,
44+
userId: userId,
45+
expiresAt: expiresAt,
4546
})
46-
// Return the session ID
4747
.returning({ id: sessions.id });
4848

4949
if (data.length === 0) {
5050
throw new Error('Failed to create session in the database');
5151
}
5252

5353
const sessionId = data[0].id;
54+
const session = await encrypt({ userId: userId, expiresAt: expiresAt });
5455

55-
// 2. Encrypt the session ID
56-
const session = await encrypt({ userId: id, expiresAt });
57-
58-
// 3. Store the session in cookies for optimistic auth checks
59-
cookies().set('session', session, {
60-
httpOnly: true,
61-
secure: true,
62-
expires: expiresAt,
63-
sameSite: 'lax',
64-
path: '/',
65-
});
56+
createLocalSession(session, expiresAt);
6657

6758
console.log(`Session created successfully: ${sessionId}`);
6859
} catch (error) {
6960
console.error('Error creating session:', error);
7061
}
7162
}
63+
64+
export async function deleteDbSession(userId: number) {
65+
try {
66+
// Get session from cookies
67+
const sessionCookie = cookies().get('session')?.value;
68+
if (!sessionCookie) {
69+
console.log('No session cookie found');
70+
return { success: false };
71+
}
72+
console.log('Session cookie:', sessionCookie);
73+
74+
// Decrypt session
75+
const session = await decrypt(sessionCookie);
76+
if (!session) {
77+
console.log('Failed to decrypt session');
78+
return { success: false };
79+
}
80+
console.log('Decrypted session:', session);
81+
82+
// Verify session user ID
83+
if (session.userId !== userId) {
84+
console.log('Session userId mismatch:', session.userId, '!==', userId);
85+
return { success: false };
86+
}
87+
88+
// Delete session from the database
89+
const response = await db
90+
.delete(sessions)
91+
.where(eq(sessions.userId, userId));
92+
93+
if (!response) {
94+
console.log('Failed to delete session from the database');
95+
return { success: false };
96+
}
97+
console.log('Session deleted from database');
98+
99+
// Delete session from cookies
100+
cookies().delete('session');
101+
console.log('Session cookie deleted');
102+
103+
return { success: true };
104+
} catch (error) {
105+
console.error('Error deleting session:', error);
106+
return { success: false };
107+
}
108+
}

0 commit comments

Comments
 (0)