Finish front end tests
This commit is contained in:
parent
a2bb8023c9
commit
9f7d142ff4
0
.env.example
Normal file → Executable file
0
.env.example
Normal file → Executable file
0
.eslintrc.cjs
Normal file → Executable file
0
.eslintrc.cjs
Normal file → Executable file
0
.gitignore
vendored
Normal file → Executable file
0
.gitignore
vendored
Normal file → Executable file
0
drizzle.config.ts
Normal file → Executable file
0
drizzle.config.ts
Normal file → Executable file
0
next.config.js
Normal file → Executable file
0
next.config.js
Normal file → Executable file
0
package.json
Normal file → Executable file
0
package.json
Normal file → Executable file
0
pnpm-lock.yaml
generated
Normal file → Executable file
0
pnpm-lock.yaml
generated
Normal file → Executable file
0
postcss.config.cjs
Normal file → Executable file
0
postcss.config.cjs
Normal file → Executable file
0
prettier.config.js
Normal file → Executable file
0
prettier.config.js
Normal file → Executable file
0
public/favicon.png
Normal file → Executable file
0
public/favicon.png
Normal file → Executable file
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
@ -1,27 +0,0 @@
|
|||||||
import { NextResponse } from 'next/server';
|
|
||||||
import type { NextRequest } from 'next/server';
|
|
||||||
import { updateUserPushToken } from '~/server/functions';
|
|
||||||
import { middleware } from "~/middleware";
|
|
||||||
|
|
||||||
type Data = {
|
|
||||||
userId: string;
|
|
||||||
pushToken: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const POST = async (request: NextRequest) => {
|
|
||||||
const middlewareResponse = await middleware(request);
|
|
||||||
if (middlewareResponse) return middlewareResponse;
|
|
||||||
try {
|
|
||||||
const { userId, pushToken } = await request.json() as Data;
|
|
||||||
console.log('Received request:', { userId, pushToken });
|
|
||||||
|
|
||||||
console.log('Updating push token for user:', userId);
|
|
||||||
await updateUserPushToken(parseInt(userId), pushToken);
|
|
||||||
|
|
||||||
console.log('Push token updated successfully');
|
|
||||||
return NextResponse.json({ message: "Push token updated successfully" });
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error in updatePushToken:', error);
|
|
||||||
return NextResponse.json({ message: "Error updating push token" }, { status: 500 });
|
|
||||||
}
|
|
||||||
};
|
|
@ -18,6 +18,12 @@ export const POST = async (request: NextRequest) => {
|
|||||||
console.log("Received request:", { userId, oldPassword, newPassword });
|
console.log("Received request:", { userId, oldPassword, newPassword });
|
||||||
|
|
||||||
console.log("Changing password for user:", userId);
|
console.log("Changing password for user:", userId);
|
||||||
|
if (oldPassword === newPassword) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ message: "New password cannot be the same as the old password" },
|
||||||
|
{ status: 400 }
|
||||||
|
);
|
||||||
|
}
|
||||||
await changePassword(userId, oldPassword, newPassword);
|
await changePassword(userId, oldPassword, newPassword);
|
||||||
return NextResponse.json({ message: "Password changed successfully" });
|
return NextResponse.json({ message: "Password changed successfully" });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -3,27 +3,20 @@ import { NextResponse } from "next/server";
|
|||||||
import type { NextRequest } from "next/server";
|
import type { NextRequest } from "next/server";
|
||||||
import { logout } from "~/server/functions";
|
import { logout } from "~/server/functions";
|
||||||
import { middleware } from "~/middleware";
|
import { middleware } from "~/middleware";
|
||||||
import jwt from "jsonwebtoken";
|
|
||||||
|
|
||||||
export const POST = async (request: NextRequest) => {
|
export const POST = async (request: NextRequest) => {
|
||||||
const middlewareResponse = await middleware(request);
|
const middlewareResponse = await middleware(request);
|
||||||
if (middlewareResponse) return middlewareResponse;
|
if (middlewareResponse) return middlewareResponse;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { token } = await request.json() as { token: string };
|
const { refreshToken } = await request.json() as { refreshToken: string };
|
||||||
if (!token)
|
if (!refreshToken)
|
||||||
return NextResponse.json({ message: "Token is required" },{ status: 400 });
|
return NextResponse.json({ message: "Refresh token is required" }, { status: 400 });
|
||||||
|
|
||||||
try {
|
await logout(refreshToken);
|
||||||
const decoded = jwt.verify(token, process.env.JWT_SECRET!) as { userId: number };
|
return NextResponse.json({ message: "Logged out successfully" });
|
||||||
if (!decoded.userId)
|
|
||||||
throw new Error("Invalid token");
|
|
||||||
await logout(decoded.userId);
|
|
||||||
return NextResponse.json({ message: "Logged out successfully" });
|
|
||||||
} catch (jwtError) {
|
|
||||||
return NextResponse.json({ message: "Invalid token", error: jwtError }, { status: 400 });
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.error('Logout error:', error);
|
||||||
if (error instanceof Error)
|
if (error instanceof Error)
|
||||||
return NextResponse.json({ message: error.message }, { status: 400 });
|
return NextResponse.json({ message: error.message }, { status: 400 });
|
||||||
else
|
else
|
||||||
|
0
src/app/layout.tsx
Normal file → Executable file
0
src/app/layout.tsx
Normal file → Executable file
0
src/app/page.tsx
Normal file → Executable file
0
src/app/page.tsx
Normal file → Executable file
@ -24,7 +24,7 @@ export default function TestCreateRequestPage() {
|
|||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
const data = await response.json() as {message: string};
|
const data = await response.json() as {message: string};
|
||||||
setResult(JSON.stringify(data));
|
setResult(JSON.stringify(data, null, 2));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error:', error);
|
console.error('Error:', error);
|
||||||
setResult('An error occurred');
|
setResult('An error occurred');
|
||||||
|
61
src/app/relationships/deleteRelationship/page.tsx
Normal file
61
src/app/relationships/deleteRelationship/page.tsx
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
|
export default function DeleteRelationshipPage() {
|
||||||
|
const [relationshipId, setRelationshipId] = useState("");
|
||||||
|
const [result, setResult] = useState<string | null>(null);
|
||||||
|
|
||||||
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setResult(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/relationships/deleteRelationship', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'x-api-key': process.env.NEXT_PUBLIC_API_KEY ?? '',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
relationshipId
|
||||||
|
})
|
||||||
|
});
|
||||||
|
const data = await response.json() as {message: string}
|
||||||
|
setResult(JSON.stringify(data, null, 2));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error:', error);
|
||||||
|
setResult('An error occurred');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className="flex min-h-screen flex-col items-center justify-center
|
||||||
|
bg-gradient-to-b from-pink-500 to-orange-400 text-white cursor-pointer">
|
||||||
|
<div className="p-4">
|
||||||
|
<h1 className="text-2xl mb-4">Test Send Message</h1>
|
||||||
|
<form onSubmit={handleSubmit} className="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label htmlFor="relationshipId" className="block">Relationship ID:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="relationshipId"
|
||||||
|
value={relationshipId}
|
||||||
|
onChange={(e) => setRelationshipId(e.target.value)}
|
||||||
|
className="border p-2 w-full bg-black"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button type='submit' className='bg-blue-500 p-2 rounded'>
|
||||||
|
Delete Relationship
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
{result && (
|
||||||
|
<div className='mt-4 p-2 rounded bg-black'>
|
||||||
|
<pre>{result}</pre>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
};
|
79
src/app/relationships/updateRequest/page.tsx
Normal file
79
src/app/relationships/updateRequest/page.tsx
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
|
type status = 'pending' | 'accepted' | 'rejected';
|
||||||
|
|
||||||
|
export default function UpdateRequestPage() {
|
||||||
|
const [relationshipId, setRelationshipId] = useState("");
|
||||||
|
const [status, setStatus] = useState("");
|
||||||
|
const [result, setResult] = useState<string | null>(null);
|
||||||
|
|
||||||
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setResult(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/relationships/updateRequest', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'x-api-key': process.env.NEXT_PUBLIC_API_KEY ?? '',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
relationshipId,
|
||||||
|
status
|
||||||
|
})
|
||||||
|
});
|
||||||
|
const data = await response.json() as {message: string}
|
||||||
|
setResult(JSON.stringify(data, null, 2));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error:', error);
|
||||||
|
setResult('An error occurred');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className="flex min-h-screen flex-col items-center justify-center
|
||||||
|
bg-gradient-to-b from-pink-500 to-orange-400 text-white cursor-pointer">
|
||||||
|
<div className="p-4">
|
||||||
|
<h1 className="text-2xl mb-4">Test Send Message</h1>
|
||||||
|
<form onSubmit={handleSubmit} className="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label htmlFor="relationshipId" className="block">Relationship ID:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="relationshipId"
|
||||||
|
value={relationshipId}
|
||||||
|
onChange={(e) => setRelationshipId(e.target.value)}
|
||||||
|
className="border p-2 w-full bg-black"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label htmlFor="status" className="block">Status:</label>
|
||||||
|
<select
|
||||||
|
id="status"
|
||||||
|
value={status}
|
||||||
|
onChange={(e) => setStatus(e.target.value as status)}
|
||||||
|
className="border p-2 w-full bg-black"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<option value="pending">Pending</option>
|
||||||
|
<option value="accepted">Accepted</option>
|
||||||
|
<option value="rejected">Rejected</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<button type='submit' className='bg-blue-500 p-2 rounded'>
|
||||||
|
Update Request
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
{result && (
|
||||||
|
<div className='mt-4 p-2 rounded bg-black'>
|
||||||
|
<pre>{result}</pre>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
};
|
87
src/app/users/changePassword/page.tsx
Normal file
87
src/app/users/changePassword/page.tsx
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
|
export default function ChangePasswordPage() {
|
||||||
|
const [userId, setUserId] = useState("");
|
||||||
|
const [oldPassword, setOldPassword] = useState("");
|
||||||
|
const [newPassword, setNewPassword] = useState("");
|
||||||
|
const [result, setResult] = useState<string | null>(null);
|
||||||
|
|
||||||
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setResult(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/users/changePassword', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'x-api-key': process.env.NEXT_PUBLIC_API_KEY ?? '',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
userId,
|
||||||
|
oldPassword,
|
||||||
|
newPassword
|
||||||
|
})
|
||||||
|
});
|
||||||
|
const data = await response.json() as {message: string}
|
||||||
|
setResult(JSON.stringify(data, null, 2));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error:', error);
|
||||||
|
setResult('An error occurred');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className="flex min-h-screen flex-col items-center justify-center
|
||||||
|
bg-gradient-to-b from-pink-500 to-orange-400 text-white cursor-pointer">
|
||||||
|
<div className="p-4">
|
||||||
|
<h1 className="text-2xl mb-4">Test Change Password</h1>
|
||||||
|
<form onSubmit={handleSubmit} className="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label htmlFor="userId" className="block">User ID:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="userId"
|
||||||
|
value={userId}
|
||||||
|
onChange={(e) => setUserId(e.target.value)}
|
||||||
|
className="border p-2 w-full bg-black"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label htmlFor="oldPassword" className="block">Old Password:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="oldPassword"
|
||||||
|
value={oldPassword}
|
||||||
|
onChange={(e) => setOldPassword(e.target.value)}
|
||||||
|
className="border p-2 w-full bg-black"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label htmlFor="newPassword" className="block">New Password:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="newPassword"
|
||||||
|
value={newPassword}
|
||||||
|
onChange={(e) => setNewPassword(e.target.value)}
|
||||||
|
className="border p-2 w-full bg-black"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button type='submit' className='bg-blue-500 p-2 rounded'>
|
||||||
|
Change Password
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
{result && (
|
||||||
|
<div className='mt-4 p-2 rounded bg-black'>
|
||||||
|
<pre>{result}</pre>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
};
|
124
src/app/users/createUser/page.tsx
Normal file
124
src/app/users/createUser/page.tsx
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
|
export default function CreateUserPage() {
|
||||||
|
const [username, setUsername] = useState("");
|
||||||
|
const [email, setEmail] = useState("");
|
||||||
|
const [passwordHash, setPasswordHash] = useState("");
|
||||||
|
const [name, setName] = useState("");
|
||||||
|
const [pfpURL, setPfpURL] = useState("");
|
||||||
|
const [pushToken, setPushToken] = useState("");
|
||||||
|
const [result, setResult] = useState<string | null>(null);
|
||||||
|
|
||||||
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setResult(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/users/createUser', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'x-api-key': process.env.NEXT_PUBLIC_API_KEY ?? '',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
username,
|
||||||
|
email,
|
||||||
|
passwordHash,
|
||||||
|
name,
|
||||||
|
pfpURL,
|
||||||
|
pushToken
|
||||||
|
})
|
||||||
|
});
|
||||||
|
const data = await response.json() as {message: string}
|
||||||
|
setResult(JSON.stringify(data, null, 2));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error:', error);
|
||||||
|
setResult('An error occurred');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className="flex min-h-screen flex-col items-center justify-center
|
||||||
|
bg-gradient-to-b from-pink-500 to-orange-400 text-white cursor-pointer">
|
||||||
|
<div className="p-4">
|
||||||
|
<h1 className="text-2xl mb-4">Test Create User</h1>
|
||||||
|
<form onSubmit={handleSubmit} className="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label htmlFor="username" className="block">Username:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="username"
|
||||||
|
value={username}
|
||||||
|
onChange={(e) => setUsername(e.target.value)}
|
||||||
|
className="border p-2 w-full bg-black"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label htmlFor="email" className="block">Email:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="email"
|
||||||
|
value={email}
|
||||||
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
|
className="border p-2 w-full bg-black"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label htmlFor="passwordHash" className="block">Password:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="passwordHash"
|
||||||
|
value={passwordHash}
|
||||||
|
onChange={(e) => setPasswordHash(e.target.value)}
|
||||||
|
className="border p-2 w-full bg-black"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label htmlFor="name" className="block">Name:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="name"
|
||||||
|
value={name}
|
||||||
|
onChange={(e) => setName(e.target.value)}
|
||||||
|
className="border p-2 w-full bg-black"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label htmlFor="pfpURL" className="block">Pfp URL:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="pfpURL"
|
||||||
|
value={pfpURL}
|
||||||
|
onChange={(e) => setPfpURL(e.target.value)}
|
||||||
|
className="border p-2 w-full bg-black"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label htmlFor="pushToken" className="block">Push Token:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="pushToken"
|
||||||
|
value={pushToken}
|
||||||
|
onChange={(e) => setPushToken(e.target.value)}
|
||||||
|
className="border p-2 w-full bg-black"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button type='submit' className='bg-blue-500 p-2 rounded'>
|
||||||
|
Create User
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
{result && (
|
||||||
|
<div className='mt-4 p-2 rounded bg-black'>
|
||||||
|
<pre>{result}</pre>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
};
|
58
src/app/users/getUserByID/page.tsx
Normal file
58
src/app/users/getUserByID/page.tsx
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
|
export default function GetUserByIDPage() {
|
||||||
|
const [userId, setUserId] = useState('');
|
||||||
|
const [result, setResult] = useState<string | null>(null);
|
||||||
|
|
||||||
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setResult(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/api/users/getUserByID?userId=${userId}`, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'x-api-key': process.env.NEXT_PUBLIC_API_KEY ?? '',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const data = await response.json() as {message: string}
|
||||||
|
setResult(JSON.stringify(data, null, 2));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error:', error);
|
||||||
|
setResult('An error occurred');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className="flex min-h-screen flex-col items-center justify-center
|
||||||
|
bg-gradient-to-b from-pink-500 to-orange-400 text-white cursor-pointer">
|
||||||
|
<div className="p-4">
|
||||||
|
<h1 className="text-2xl mb-4">Test Get User By ID</h1>
|
||||||
|
<form onSubmit={handleSubmit} className="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label htmlFor="userId" className="block">User ID:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="userId"
|
||||||
|
value={userId}
|
||||||
|
onChange={(e) => setUserId(e.target.value)}
|
||||||
|
className="border p-2 w-full bg-black"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button type='submit' className='bg-blue-500 p-2 rounded'>
|
||||||
|
Get User By ID
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
{result && (
|
||||||
|
<div className='mt-4 p-2 rounded bg-black'>
|
||||||
|
<pre>{result}</pre>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
};
|
58
src/app/users/getUserByUsername/page.tsx
Normal file
58
src/app/users/getUserByUsername/page.tsx
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
|
export default function GetUserByUsernamePage() {
|
||||||
|
const [userName, setUserName] = useState('');
|
||||||
|
const [result, setResult] = useState<string | null>(null);
|
||||||
|
|
||||||
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setResult(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/api/users/getUserByUsername?username=${userName}`, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'x-api-key': process.env.NEXT_PUBLIC_API_KEY ?? '',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const data = await response.json() as {message: string}
|
||||||
|
setResult(JSON.stringify(data, null, 2));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error:', error);
|
||||||
|
setResult('An error occurred');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className="flex min-h-screen flex-col items-center justify-center
|
||||||
|
bg-gradient-to-b from-pink-500 to-orange-400 text-white cursor-pointer">
|
||||||
|
<div className="p-4">
|
||||||
|
<h1 className="text-2xl mb-4">Test Get User By Username</h1>
|
||||||
|
<form onSubmit={handleSubmit} className="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label htmlFor="userId" className="block">User ID:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="userId"
|
||||||
|
value={userName}
|
||||||
|
onChange={(e) => setUserName(e.target.value)}
|
||||||
|
className="border p-2 w-full bg-black"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button type='submit' className='bg-blue-500 p-2 rounded'>
|
||||||
|
Get User By ID
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
{result && (
|
||||||
|
<div className='mt-4 p-2 rounded bg-black'>
|
||||||
|
<pre>{result}</pre>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
};
|
74
src/app/users/login/page.tsx
Normal file
74
src/app/users/login/page.tsx
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
|
export default function LoginTestPage() {
|
||||||
|
const [username, setUsername] = useState('');
|
||||||
|
const [password, setPassword] = useState('');
|
||||||
|
const [result, setResult] = useState<string | null>(null);
|
||||||
|
|
||||||
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setResult(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/users/login', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'x-api-key': process.env.NEXT_PUBLIC_API_KEY ?? '',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
username,
|
||||||
|
password
|
||||||
|
})
|
||||||
|
});
|
||||||
|
const data = await response.json() as {message: string}
|
||||||
|
setResult(JSON.stringify(data, null, 2));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error:', error);
|
||||||
|
setResult('An error occurred');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className="flex min-h-screen flex-col items-center justify-center
|
||||||
|
bg-gradient-to-b from-pink-500 to-orange-400 text-white cursor-pointer">
|
||||||
|
<div className="p-4">
|
||||||
|
<h1 className="text-2xl mb-4">Test Login</h1>
|
||||||
|
<form onSubmit={handleSubmit} className="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label htmlFor="username" className="block">Username:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="username"
|
||||||
|
value={username}
|
||||||
|
onChange={(e) => setUsername(e.target.value)}
|
||||||
|
className="border p-2 w-full bg-black"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label htmlFor="password" className="block">Password:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="password"
|
||||||
|
value={password}
|
||||||
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
|
className="border p-2 w-full bg-black"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button type='submit' className='bg-blue-500 p-2 rounded'>
|
||||||
|
Login
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
{result && (
|
||||||
|
<div className='mt-4 p-2 rounded bg-black'>
|
||||||
|
<pre>{result}</pre>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
};
|
60
src/app/users/logout/page.tsx
Normal file
60
src/app/users/logout/page.tsx
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
|
export default function TestLogout() {
|
||||||
|
const [refreshToken, setRefreshToken] = useState('');
|
||||||
|
const [result, setResult] = useState<string | null>(null);
|
||||||
|
|
||||||
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setResult(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/users/logout', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'x-api-key': process.env.NEXT_PUBLIC_API_KEY ?? '',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
refreshToken
|
||||||
|
})
|
||||||
|
});
|
||||||
|
const data = await response.json() as {message: string}
|
||||||
|
setResult(JSON.stringify(data, null, 2));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error:', error);
|
||||||
|
setResult('An error occurred');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<main className="flex min-h-screen flex-col items-center justify-center
|
||||||
|
bg-gradient-to-b from-pink-500 to-orange-400 text-white cursor-pointer">
|
||||||
|
<div className="p-4">
|
||||||
|
<h1 className="text-2xl mb-4">Test Logout</h1>
|
||||||
|
<form onSubmit={handleSubmit} className="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label htmlFor="refreshToken" className="block">Token:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="refreshToken"
|
||||||
|
value={refreshToken}
|
||||||
|
onChange={(e) => setRefreshToken(e.target.value)}
|
||||||
|
className="border p-2 w-full bg-black"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button type='submit' className='bg-blue-500 p-2 rounded'>
|
||||||
|
Logout
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
{result && (
|
||||||
|
<div className='mt-4 p-2 rounded bg-black'>
|
||||||
|
<pre>{result}</pre>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
};
|
60
src/app/users/refreshToken/page.tsx
Normal file
60
src/app/users/refreshToken/page.tsx
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
|
export default function TestRefreshToken() {
|
||||||
|
const [refreshToken, setRefreshToken] = useState('');
|
||||||
|
const [result, setResult] = useState<string | null>(null);
|
||||||
|
|
||||||
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setResult(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/users/refreshToken', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'x-api-key': process.env.NEXT_PUBLIC_API_KEY ?? '',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
refreshToken
|
||||||
|
})
|
||||||
|
});
|
||||||
|
const data = await response.json() as {message: string}
|
||||||
|
setResult(JSON.stringify(data, null, 2));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error:', error);
|
||||||
|
setResult('An error occurred');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<main className="flex min-h-screen flex-col items-center justify-center
|
||||||
|
bg-gradient-to-b from-pink-500 to-orange-400 text-white cursor-pointer">
|
||||||
|
<div className="p-4">
|
||||||
|
<h1 className="text-2xl mb-4">Test Refresh Token</h1>
|
||||||
|
<form onSubmit={handleSubmit} className="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label htmlFor="refreshToken" className="block">Token:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="refreshToken"
|
||||||
|
value={refreshToken}
|
||||||
|
onChange={(e) => setRefreshToken(e.target.value)}
|
||||||
|
className="border p-2 w-full bg-black"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button type='submit' className='bg-blue-500 p-2 rounded'>
|
||||||
|
Refresh Token
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
{result && (
|
||||||
|
<div className='mt-4 p-2 rounded bg-black'>
|
||||||
|
<pre>{result}</pre>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
};
|
73
src/app/users/updatePFP/page.tsx
Normal file
73
src/app/users/updatePFP/page.tsx
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
|
export default function TestUpdatePFP() {
|
||||||
|
const [userId, setUserId] = useState('');
|
||||||
|
const [pfpURL, setPfpURL] = useState('');
|
||||||
|
const [result, setResult] = useState<string | null>(null);
|
||||||
|
|
||||||
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setResult(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/users/updatePFP', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'x-api-key': process.env.NEXT_PUBLIC_API_KEY ?? '',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
userId,
|
||||||
|
pfpURL
|
||||||
|
})
|
||||||
|
});
|
||||||
|
const data = await response.json() as {message: string}
|
||||||
|
setResult(JSON.stringify(data, null, 2));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error:', error);
|
||||||
|
setResult('An error occurred');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<main className="flex min-h-screen flex-col items-center justify-center
|
||||||
|
bg-gradient-to-b from-pink-500 to-orange-400 text-white cursor-pointer">
|
||||||
|
<div className="p-4">
|
||||||
|
<h1 className="text-2xl mb-4">Test Update PFP</h1>
|
||||||
|
<form onSubmit={handleSubmit} className="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label htmlFor="userId" className="block">User ID:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="userId"
|
||||||
|
value={userId}
|
||||||
|
onChange={(e) => setUserId(e.target.value)}
|
||||||
|
className="border p-2 w-full bg-black"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label htmlFor="pfpURL" className="block">PFP URL:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="pfpURL"
|
||||||
|
value={pfpURL}
|
||||||
|
onChange={(e) => setPfpURL(e.target.value)}
|
||||||
|
className="border p-2 w-full bg-black"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button type='submit' className='bg-blue-500 p-2 rounded'>
|
||||||
|
Update PFP
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
{result && (
|
||||||
|
<div className='mt-4 p-2 rounded bg-black'>
|
||||||
|
<pre>{result}</pre>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
73
src/app/users/updatePushToken/page.tsx
Normal file
73
src/app/users/updatePushToken/page.tsx
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
|
export default function TestUpdatePushToken() {
|
||||||
|
const [userId, setUserId] = useState('');
|
||||||
|
const [pushToken, setPushToken] = useState('');
|
||||||
|
const [result, setResult] = useState<string | null>(null);
|
||||||
|
|
||||||
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setResult(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/users/updatePushToken', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'x-api-key': process.env.NEXT_PUBLIC_API_KEY ?? '',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
userId,
|
||||||
|
pushToken
|
||||||
|
})
|
||||||
|
});
|
||||||
|
const data = await response.json() as {message: string}
|
||||||
|
setResult(JSON.stringify(data, null, 2));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error:', error);
|
||||||
|
setResult('An error occurred');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<main className="flex min-h-screen flex-col items-center justify-center
|
||||||
|
bg-gradient-to-b from-pink-500 to-orange-400 text-white cursor-pointer">
|
||||||
|
<div className="p-4">
|
||||||
|
<h1 className="text-2xl mb-4">Test Update Push Token</h1>
|
||||||
|
<form onSubmit={handleSubmit} className="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label htmlFor="userId" className="block">User ID:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="userId"
|
||||||
|
value={userId}
|
||||||
|
onChange={(e) => setUserId(e.target.value)}
|
||||||
|
className="border p-2 w-full bg-black"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label htmlFor="pushToken" className="block">Push Token:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="pushToken"
|
||||||
|
value={pushToken}
|
||||||
|
onChange={(e) => setPushToken(e.target.value)}
|
||||||
|
className="border p-2 w-full bg-black"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button type='submit' className='bg-blue-500 p-2 rounded'>
|
||||||
|
Update Push Token
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
{result && (
|
||||||
|
<div className='mt-4 p-2 rounded bg-black'>
|
||||||
|
<pre>{result}</pre>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
};
|
37
src/env.js
Normal file → Executable file
37
src/env.js
Normal file → Executable file
@ -2,45 +2,32 @@ import { createEnv } from "@t3-oss/env-nextjs";
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const env = createEnv({
|
export const env = createEnv({
|
||||||
/**
|
|
||||||
* Specify your server-side environment variables schema here. This way you can ensure the app
|
|
||||||
* isn't built with invalid env vars.
|
|
||||||
*/
|
|
||||||
server: {
|
server: {
|
||||||
DATABASE_URL: z.string().url(),
|
DATABASE_URL: z.string().url(),
|
||||||
API_KEY: z.string(),
|
API_KEY: z.string(),
|
||||||
NODE_ENV: z
|
NODE_ENV: z
|
||||||
.enum(["development", "test", "production"])
|
.enum(["development", "test", "production"])
|
||||||
.default("development"),
|
.default("development"),
|
||||||
|
JWT_SECRET: z.string(),
|
||||||
|
JWT_REFRESH_SECRET: z.string(),
|
||||||
|
SKIP_ENV_VALIDATION: z.boolean().optional(),
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify your client-side environment variables schema here. This way you can ensure the app
|
|
||||||
* isn't built with invalid env vars. To expose them to the client, prefix them with
|
|
||||||
* `NEXT_PUBLIC_`.
|
|
||||||
*/
|
|
||||||
client: {
|
client: {
|
||||||
// NEXT_PUBLIC_CLIENTVAR: z.string(),
|
NEXT_PUBLIC_API_KEY: z.string(),
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* You can't destruct `process.env` as a regular object in the Next.js edge runtimes (e.g.
|
|
||||||
* middlewares) or client-side so we need to destruct manually.
|
|
||||||
*/
|
|
||||||
runtimeEnv: {
|
runtimeEnv: {
|
||||||
DATABASE_URL: process.env.DATABASE_URL,
|
DATABASE_URL: process.env.DATABASE_URL,
|
||||||
API_KEY: process.env.API_KEY,
|
API_KEY: process.env.API_KEY,
|
||||||
NODE_ENV: process.env.NODE_ENV,
|
NODE_ENV: process.env.NODE_ENV,
|
||||||
// NEXT_PUBLIC_CLIENTVAR: process.env.NEXT_PUBLIC_CLIENTVAR,
|
JWT_SECRET: process.env.JWT_SECRET,
|
||||||
|
JWT_REFRESH_SECRET: process.env.JWT_REFRESH_SECRET,
|
||||||
|
NEXT_PUBLIC_API_KEY: process.env.NEXT_PUBLIC_API_KEY,
|
||||||
|
SKIP_ENV_VALIDATION: process.env.SKIP_ENV_VALIDATION,
|
||||||
},
|
},
|
||||||
/**
|
|
||||||
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially
|
skipValidation: !!process.env.SKIP_ENV_VALIDATION,
|
||||||
* useful for Docker builds.
|
emptyStringAsUndefined: true,
|
||||||
*/
|
|
||||||
skipValidation: !!process.env.SKIP_ENV_VALIDATION,
|
|
||||||
/**
|
|
||||||
* Makes it so that empty strings are treated as undefined. `SOME_VAR: z.string()` and
|
|
||||||
* `SOME_VAR=''` will throw an error.
|
|
||||||
*/
|
|
||||||
emptyStringAsUndefined: true,
|
|
||||||
});
|
});
|
||||||
|
0
src/server/db/index.ts
Normal file → Executable file
0
src/server/db/index.ts
Normal file → Executable file
0
src/server/db/schema.ts
Normal file → Executable file
0
src/server/db/schema.ts
Normal file → Executable file
25
src/server/functions.ts
Normal file → Executable file
25
src/server/functions.ts
Normal file → Executable file
@ -214,6 +214,8 @@ export const changePassword = async (
|
|||||||
try {
|
try {
|
||||||
// Ensure all arguments are provided
|
// Ensure all arguments are provided
|
||||||
if (!oldPasswordHash || !newPasswordHash) throw new Error("Password fields are required");
|
if (!oldPasswordHash || !newPasswordHash) throw new Error("Password fields are required");
|
||||||
|
if (oldPasswordHash === newPasswordHash)
|
||||||
|
throw new Error("New password cannot be the same as the old password");
|
||||||
|
|
||||||
const user = await ensureUserExists(userId);
|
const user = await ensureUserExists(userId);
|
||||||
|
|
||||||
@ -286,6 +288,10 @@ export const login = async (username: string, passwordHash: string) => {
|
|||||||
.set({ lastLogin: new Date() })
|
.set({ lastLogin: new Date() })
|
||||||
.where(eq(schema.users.id, user.id));
|
.where(eq(schema.users.id, user.id));
|
||||||
|
|
||||||
|
await db.update(schema.users)
|
||||||
|
.set({ refreshToken: refreshToken })
|
||||||
|
.where(eq(schema.users.id, user.id));
|
||||||
|
|
||||||
return { user, accessToken, refreshToken };
|
return { user, accessToken, refreshToken };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
@ -322,11 +328,21 @@ export const refreshToken = async (refreshToken: string) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const logout = async (userId: number) => {
|
export const logout = async (refreshToken: string) => {
|
||||||
try {
|
try {
|
||||||
|
const user = await db.select()
|
||||||
|
.from(schema.users)
|
||||||
|
.where(eq(schema.users.refreshToken, refreshToken))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (user.length === 0 || !user[0]?.id) {
|
||||||
|
throw new Error('No user found with this refresh token');
|
||||||
|
}
|
||||||
|
|
||||||
await db.update(schema.users)
|
await db.update(schema.users)
|
||||||
.set({ lastLogin: null })
|
.set({ refreshToken: null })
|
||||||
.where(eq(schema.users.id, userId));
|
.where(eq(schema.users.id, user[0].id));
|
||||||
|
|
||||||
return { success: true };
|
return { success: true };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
@ -417,6 +433,9 @@ export const updateRelationshipRequest = async (relationshipId: number, status:
|
|||||||
export const deleteRelationship = async (relationshipId: number) => {
|
export const deleteRelationship = async (relationshipId: number) => {
|
||||||
try {
|
try {
|
||||||
await db.transaction(async (trx) => {
|
await db.transaction(async (trx) => {
|
||||||
|
await trx.delete(schema.countdowns)
|
||||||
|
.where(eq(schema.countdowns.relationshipId, relationshipId));
|
||||||
|
|
||||||
await trx.delete(schema.userRelationships)
|
await trx.delete(schema.userRelationships)
|
||||||
.where(eq(schema.userRelationships.relationshipId, relationshipId));
|
.where(eq(schema.userRelationships.relationshipId, relationshipId));
|
||||||
|
|
||||||
|
0
src/styles/globals.css
Normal file → Executable file
0
src/styles/globals.css
Normal file → Executable file
0
tailwind.config.ts
Normal file → Executable file
0
tailwind.config.ts
Normal file → Executable file
0
tsconfig.json
Normal file → Executable file
0
tsconfig.json
Normal file → Executable file
Loading…
Reference in New Issue
Block a user