update backend for appleauth
This commit is contained in:
parent
cbdca78f18
commit
171de4104d
@ -1,33 +0,0 @@
|
||||
"use server";
|
||||
import { NextResponse } from "next/server";
|
||||
import type { NextRequest } from "next/server";
|
||||
import { changePassword } from "~/server/functions";
|
||||
import { middleware } from "~/middleware";
|
||||
|
||||
type Data = {
|
||||
userId: number;
|
||||
oldPassword: string;
|
||||
newPassword: string;
|
||||
};
|
||||
|
||||
export const POST = async (request: NextRequest) => {
|
||||
const middlewareResponse = await middleware(request);
|
||||
if (middlewareResponse) return middlewareResponse;
|
||||
try {
|
||||
const { userId, oldPassword, newPassword } = await request.json() as Data;
|
||||
console.log("Received request:", { userId, oldPassword, newPassword });
|
||||
|
||||
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);
|
||||
return NextResponse.json({ message: "Password changed successfully" });
|
||||
} catch (error) {
|
||||
console.error("Error in changePassword:", error);
|
||||
return NextResponse.json({ message: "Error changing password" }, { status: 500 });
|
||||
}
|
||||
};
|
@ -5,12 +5,11 @@ import { createUser } from "~/server/functions";
|
||||
import { middleware } from "~/middleware";
|
||||
|
||||
type CreateUserRequest = {
|
||||
username: string;
|
||||
email: string;
|
||||
passwordHash: string;
|
||||
name: string;
|
||||
appleId: string;
|
||||
appleEmail: string;
|
||||
fullName: string;
|
||||
pushToken: string;
|
||||
pfpURL?: string;
|
||||
pushToken?: string;
|
||||
};
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
@ -18,16 +17,15 @@ export async function POST(request: NextRequest) {
|
||||
if (middlewareResponse) return middlewareResponse;
|
||||
try {
|
||||
const {
|
||||
username,
|
||||
email,
|
||||
passwordHash,
|
||||
name,
|
||||
appleId,
|
||||
appleEmail,
|
||||
fullName,
|
||||
pushToken,
|
||||
pfpURL = "",
|
||||
pushToken = ""
|
||||
} = await request.json() as CreateUserRequest;
|
||||
|
||||
// Validate required fields
|
||||
if (!username || !email || !passwordHash || !name) {
|
||||
if (!appleId || !appleEmail || !fullName || !pushToken) {
|
||||
return NextResponse.json(
|
||||
{ message: "Missing required fields" },
|
||||
{ status: 400 }
|
||||
@ -35,12 +33,11 @@ export async function POST(request: NextRequest) {
|
||||
}
|
||||
|
||||
const user = await createUser(
|
||||
username,
|
||||
email,
|
||||
passwordHash,
|
||||
name,
|
||||
pfpURL,
|
||||
pushToken
|
||||
appleId,
|
||||
appleEmail,
|
||||
fullName,
|
||||
pushToken,
|
||||
pfpURL
|
||||
);
|
||||
|
||||
return NextResponse.json(user, { status: 201 });
|
||||
|
@ -1,7 +1,7 @@
|
||||
"use server";
|
||||
import { NextResponse } from "next/server";
|
||||
import type { NextRequest } from "next/server";
|
||||
import { getUserByUsername } from "~/server/functions";
|
||||
import { getUserByAppleEmail } from "~/server/functions";
|
||||
import { middleware } from "~/middleware";
|
||||
|
||||
export const GET = async (request: NextRequest) => {
|
||||
@ -9,8 +9,8 @@ export const GET = async (request: NextRequest) => {
|
||||
if (middlewareResponse) return middlewareResponse;
|
||||
try {
|
||||
const url = new URL(request.url);
|
||||
const username = url.searchParams.get("username") ?? "2";
|
||||
const user = await getUserByUsername(username);
|
||||
const appleEmail = url.searchParams.get("appleEmail") ?? "";
|
||||
const user = await getUserByAppleEmail(appleEmail);
|
||||
return NextResponse.json(user);
|
||||
} catch (error) {
|
||||
console.error(error);
|
@ -1,39 +0,0 @@
|
||||
"use server";
|
||||
import { NextResponse } from "next/server";
|
||||
import type { NextRequest } from "next/server";
|
||||
import { login } from "~/server/functions";
|
||||
import { middleware } from "~/middleware";
|
||||
|
||||
type LoginRequest = {
|
||||
username: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
const middlewareResponse = await middleware(request);
|
||||
if (middlewareResponse) return middlewareResponse;
|
||||
try {
|
||||
const { username, password } = await request.json() as LoginRequest;
|
||||
console.log("Received request:", { username, password });
|
||||
|
||||
if (!username || !password) {
|
||||
return NextResponse.json({ message: "Missing required fields" }, { status: 400 });
|
||||
}
|
||||
|
||||
console.log("Logging in user:", username);
|
||||
const result = await login(username, password);
|
||||
|
||||
if (result) {
|
||||
console.log("User logged in successfully");
|
||||
return NextResponse.json({ result }, { status: 200 });
|
||||
} else {
|
||||
throw new Error("Failed to log in user");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error in login:", error);
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json({ message: error.message }, { status: 400 });
|
||||
}
|
||||
return NextResponse.json({ message: "Error logging in user" }, { status: 500 });
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
"use server";
|
||||
import { NextResponse } from "next/server";
|
||||
import type { NextRequest } from "next/server";
|
||||
import { logout } from "~/server/functions";
|
||||
import { middleware } from "~/middleware";
|
||||
|
||||
export const POST = async (request: NextRequest) => {
|
||||
const middlewareResponse = await middleware(request);
|
||||
if (middlewareResponse) return middlewareResponse;
|
||||
|
||||
try {
|
||||
const { refreshToken } = await request.json() as { refreshToken: string };
|
||||
if (!refreshToken)
|
||||
return NextResponse.json({ message: "Refresh token is required" }, { status: 400 });
|
||||
|
||||
await logout(refreshToken);
|
||||
return NextResponse.json({ message: "Logged out successfully" });
|
||||
} catch (error) {
|
||||
console.error('Logout error:', error);
|
||||
if (error instanceof Error)
|
||||
return NextResponse.json({ message: error.message }, { status: 400 });
|
||||
else
|
||||
return NextResponse.json({ message: "Unknown error occurred" }, { status: 500 });
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
"use server";
|
||||
import { NextResponse } from "next/server";
|
||||
import type { NextRequest } from "next/server";
|
||||
import { refreshToken } from "~/server/functions";
|
||||
import { middleware } from "~/middleware";
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
const middlewareResponse = await middleware(request);
|
||||
if (middlewareResponse) return middlewareResponse;
|
||||
try {
|
||||
const { refreshToken: token } = await request.json() as { refreshToken: string };
|
||||
if (!token)
|
||||
return NextResponse.json({ message: "Refresh token is required" },{ status: 400 });
|
||||
const tokens = await refreshToken(token);
|
||||
return NextResponse.json(tokens);
|
||||
} catch (error) {
|
||||
if (error instanceof Error)
|
||||
return NextResponse.json({ message: error.message }, { status: 400 });
|
||||
else
|
||||
return NextResponse.json({ message: "Unknown error occurred" }, { status: 500 });
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ import type { NextRequest } from "next/server";
|
||||
import { updateUserPFP } from "~/server/functions";
|
||||
import { middleware } from "~/middleware";
|
||||
|
||||
interface UpdatePfpRequest {
|
||||
type UpdatePfpRequest = {
|
||||
userId: number;
|
||||
pfpURL: string;
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import type { NextRequest } from "next/server";
|
||||
import { updateUserPushToken } from "~/server/functions";
|
||||
import { middleware } from "~/middleware";
|
||||
|
||||
interface UpdatePushTokenRequest {
|
||||
type UpdatePushTokenRequest = {
|
||||
userId: number;
|
||||
pushToken: string;
|
||||
}
|
||||
|
@ -1,87 +0,0 @@
|
||||
"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>
|
||||
);
|
||||
};
|
@ -3,12 +3,11 @@
|
||||
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 [appleId, setAppleId] = useState("");
|
||||
const [appleEmail, setAppleEmail] = useState("");
|
||||
const [fullName, setFullName] = useState("");
|
||||
const [pushToken, setPushToken] = useState("");
|
||||
const [pfpURL, setPfpURL] = useState("");
|
||||
const [result, setResult] = useState<string | null>(null);
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
@ -23,10 +22,9 @@ export default function CreateUserPage() {
|
||||
'x-api-key': process.env.NEXT_PUBLIC_API_KEY ?? '',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
username,
|
||||
email,
|
||||
passwordHash,
|
||||
name,
|
||||
appleId,
|
||||
appleEmail,
|
||||
fullName,
|
||||
pfpURL,
|
||||
pushToken
|
||||
})
|
||||
@ -46,45 +44,34 @@ export default function CreateUserPage() {
|
||||
<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>
|
||||
<label htmlFor="appleId" className="block">Username:</label>
|
||||
<input
|
||||
type="text"
|
||||
id="username"
|
||||
value={username}
|
||||
onChange={(e) => setUsername(e.target.value)}
|
||||
id="appleId"
|
||||
value={appleId}
|
||||
onChange={(e) => setAppleId(e.target.value)}
|
||||
className="border p-2 w-full bg-black"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="email" className="block">Email:</label>
|
||||
<label htmlFor="appleEmail" className="block">Email:</label>
|
||||
<input
|
||||
type="text"
|
||||
id="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
id="appleEmail"
|
||||
value={appleEmail}
|
||||
onChange={(e) => setAppleEmail(e.target.value)}
|
||||
className="border p-2 w-full bg-black"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="passwordHash" className="block">Password:</label>
|
||||
<label htmlFor="fullName" className="block">Name:</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)}
|
||||
id="fullName"
|
||||
value={fullName}
|
||||
onChange={(e) => setFullName(e.target.value)}
|
||||
className="border p-2 w-full bg-black"
|
||||
required
|
||||
/>
|
||||
|
@ -3,7 +3,7 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
export default function GetUserByUsernamePage() {
|
||||
const [userName, setUserName] = useState('');
|
||||
const [appleEmail, setAppleEmail] = useState('');
|
||||
const [result, setResult] = useState<string | null>(null);
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
@ -11,7 +11,7 @@ export default function GetUserByUsernamePage() {
|
||||
setResult(null);
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/users/getUserByUsername?username=${userName}`, {
|
||||
const response = await fetch(`/api/users/getUserByAppleEmail?appleEmail=${appleEmail}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@ -37,8 +37,8 @@ export default function GetUserByUsernamePage() {
|
||||
<input
|
||||
type="text"
|
||||
id="userId"
|
||||
value={userName}
|
||||
onChange={(e) => setUserName(e.target.value)}
|
||||
value={appleEmail}
|
||||
onChange={(e) => setAppleEmail(e.target.value)}
|
||||
className="border p-2 w-full bg-black"
|
||||
required
|
||||
/>
|
@ -1,74 +0,0 @@
|
||||
'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>
|
||||
);
|
||||
};
|
@ -1,60 +0,0 @@
|
||||
'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>
|
||||
);
|
||||
};
|
@ -1,60 +0,0 @@
|
||||
'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>
|
||||
);
|
||||
};
|
@ -19,14 +19,11 @@ export const users = createTable(
|
||||
"user",
|
||||
{
|
||||
id: serial("id").primaryKey(),
|
||||
username: varchar("username", { length: 50 }).unique().notNull(),
|
||||
email: varchar("email", { length: 255 }).unique().notNull(),
|
||||
passwordHash: varchar("password_hash", {length: 255}).notNull(),
|
||||
name: varchar("name", { length: 100 }),
|
||||
appleId: varchar("apple_id", { length: 255 }).unique(),
|
||||
appleEmail: varchar("apple_email", { length: 255 }).unique().notNull(),
|
||||
fullName: varchar("full_name", { length: 100 }),
|
||||
pfpURL: varchar("pfp_url", { length: 255 }),
|
||||
pushToken: varchar("pushToken", { length: 255 }),
|
||||
refreshToken: varchar("refreshToken", { length: 255 }),
|
||||
lastLogin: timestamp("last_login", { withTimezone: true }),
|
||||
createdAt: timestamp("created_at", { withTimezone: true })
|
||||
.default(sql`CURRENT_TIMESTAMP`)
|
||||
.notNull(),
|
||||
|
@ -2,9 +2,9 @@ import 'server-only';
|
||||
import { db } from '~/server/db';
|
||||
import * as schema from '~/server/db/schema';
|
||||
import { eq, and, or, sql } from 'drizzle-orm';
|
||||
import { pgEnum } from 'drizzle-orm/pg-core';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { inArray } from 'drizzle-orm/sql';
|
||||
//import { pgEnum } from 'drizzle-orm/pg-core';
|
||||
//import { inArray } from 'drizzle-orm/sql';
|
||||
|
||||
// --- Helper Functions --- //
|
||||
|
||||
@ -63,48 +63,7 @@ export const ensureRelationshipExistsByRelationshipId = async (relationshipId: n
|
||||
* Handles both directions of a relationship (userId => partnerId or partnerId => userId).
|
||||
* Optionally checks relationship status.
|
||||
*/
|
||||
export const ensureRelationshipExistsOld = async (userId: number, partnerId: number, status?: 'pending' | 'accepted') => {
|
||||
try {
|
||||
// Ensure bidirectional relationship (user1 <-> user2 or user2 <-> user1)
|
||||
const relationship = await db.select({
|
||||
relationshipId: schema.userRelationships.relationshipId,
|
||||
status: schema.relationships.status,
|
||||
})
|
||||
.from(schema.userRelationships)
|
||||
.leftJoin(
|
||||
schema.relationships,
|
||||
eq(schema.userRelationships.relationshipId, schema.relationships.id)
|
||||
)
|
||||
.where(or(
|
||||
and(
|
||||
eq(schema.userRelationships.userId, userId),
|
||||
eq(schema.userRelationships.userId, partnerId) // Check if userId -> partnerId
|
||||
),
|
||||
and(
|
||||
eq(schema.userRelationships.userId, partnerId),
|
||||
eq(schema.userRelationships.userId, userId) // Check if partnerId -> userId (reverse relationship)
|
||||
)
|
||||
));
|
||||
|
||||
if (!relationship.length) {
|
||||
throw new Error('Relationship does not exist');
|
||||
}
|
||||
|
||||
if (status && relationship[0]?.status !== status) {
|
||||
throw new Error(`Relationship is not in ${status} status`);
|
||||
}
|
||||
|
||||
return relationship[0];
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
throw new Error(`Error checking relationship: ${error.message}`);
|
||||
} else {
|
||||
throw new Error("Unknown error occurred while checking relationship");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const ensureRelationshipExists = async (userId: number, partnerId: number) => {
|
||||
export const ensureRelationshipExistsByUserIds = async (userId: number, partnerId: number) => {
|
||||
try {
|
||||
// Ensure bidirectional relationship (user1 <-> user2 or user2 <-> user1)
|
||||
const relationship = await db.select({
|
||||
@ -160,10 +119,10 @@ export const getUserById = async (userId: number) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const getUserByUsername = async (username: string) => {
|
||||
export const getUserByAppleEmail = async (appleEmail: string) => {
|
||||
try {
|
||||
const user = await db.select().from(schema.users)
|
||||
.where(eq(schema.users.username, username));
|
||||
.where(eq(schema.users.appleEmail, appleEmail));
|
||||
|
||||
if (user.length === 0) throw new Error('User not found');
|
||||
return user[0];
|
||||
@ -177,25 +136,24 @@ export const getUserByUsername = async (username: string) => {
|
||||
};
|
||||
|
||||
export const createUser = async (
|
||||
username: string, email: string, passwordHash: string,
|
||||
name: string, pfpURL = "", pushToken = ""
|
||||
appleId: string, appleEmail: string,
|
||||
fullName: string, pfpURL = "", pushToken = ""
|
||||
) => {
|
||||
try {
|
||||
if (!username || !email || !passwordHash || !name) {
|
||||
if (!appleId || !appleEmail || !fullName || !pushToken) {
|
||||
throw new Error("Error: All required fields must be filled");
|
||||
}
|
||||
|
||||
// Check if username or email is already taken
|
||||
const existingUser = await db.select().from(schema.users)
|
||||
.where(or(eq(schema.users.username, username), eq(schema.users.email, email)));
|
||||
.where(or(eq(schema.users.appleId, appleId), eq(schema.users.appleEmail, appleEmail)));
|
||||
|
||||
if (existingUser.length > 0) {
|
||||
throw new Error("Username or email is already in use");
|
||||
}
|
||||
|
||||
const newUser = await db.insert(schema.users).values({
|
||||
username, email, passwordHash, name, pfpURL, pushToken,
|
||||
lastLogin: new Date(),
|
||||
appleId, appleEmail, fullName, pfpURL, pushToken
|
||||
}).returning();
|
||||
|
||||
return newUser;
|
||||
@ -208,37 +166,6 @@ export const createUser = async (
|
||||
}
|
||||
};
|
||||
|
||||
export const changePassword = async (
|
||||
userId: number, oldPasswordHash: string, newPasswordHash: string
|
||||
) => {
|
||||
try {
|
||||
// Ensure all arguments are provided
|
||||
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);
|
||||
|
||||
// Validate old password
|
||||
if (user?.passwordHash !== oldPasswordHash) {
|
||||
throw new Error("Old password does not match");
|
||||
}
|
||||
|
||||
// Update with the new password hash
|
||||
await db.update(schema.users)
|
||||
.set({ passwordHash: newPasswordHash })
|
||||
.where(eq(schema.users.id, userId));
|
||||
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
throw new Error(`Failed to change password: ${error.message}`);
|
||||
} else {
|
||||
throw new Error("Unknown error occurred while changing password");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const updateUserPFP = async (userId: number, pfpURL: string) => {
|
||||
try {
|
||||
await db.update(schema.users)
|
||||
@ -271,88 +198,6 @@ export const updateUserPushToken = async (userId: number, pushToken: string) =>
|
||||
}
|
||||
};
|
||||
|
||||
export const login = async (username: string, passwordHash: string) => {
|
||||
try {
|
||||
const user = await getUserByUsername(username);
|
||||
if (user?.passwordHash !== passwordHash) {
|
||||
throw new Error("Invalid password");
|
||||
}
|
||||
|
||||
const accessToken = jwt.sign({ userId: user.id }, process.env.JWT_SECRET!,
|
||||
{expiresIn: '15m' });
|
||||
const refreshToken = jwt.sign({ userId: user.id }, process.env.JWT_REFRESH_SECRET!,
|
||||
{expiresIn: '7d' });
|
||||
|
||||
// Update last login timestamp
|
||||
await db.update(schema.users)
|
||||
.set({ lastLogin: new Date() })
|
||||
.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 };
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
throw new Error(`Failed to Log in: ${error.message}`);
|
||||
} else {
|
||||
throw new Error("Unknown error occurred while logging in");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const refreshToken = async (refreshToken: string) => {
|
||||
try {
|
||||
const decoded = jwt.verify(refreshToken, process.env.JWT_REFRESH_SECRET!) as { userId: number };
|
||||
if (!decoded.userId)
|
||||
throw new Error("Invalid refresh token");
|
||||
const user = await getUserById(decoded.userId);
|
||||
if (!user || user.refreshToken !== refreshToken)
|
||||
throw new Error("Invalid refresh token");
|
||||
const newAccessToken = jwt.sign({ userId: user.id }, process.env.JWT_SECRET!,
|
||||
{expiresIn: '15m' });
|
||||
const newRefreshToken = jwt.sign({ userId: user.id }, process.env.JWT_REFRESH_SECRET!,
|
||||
{expiresIn: '7d' });
|
||||
await db.update(schema.users)
|
||||
.set({ refreshToken: newRefreshToken })
|
||||
.where(eq(schema.users.id, user.id));
|
||||
|
||||
return { accessToken: newAccessToken, refreshToken: newRefreshToken };
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
throw new Error(`Failed to refresh token: ${error.message}`);
|
||||
} else {
|
||||
throw new Error("Unknown error occurred while refreshing token");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const logout = async (refreshToken: string) => {
|
||||
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)
|
||||
.set({ refreshToken: null })
|
||||
.where(eq(schema.users.id, user[0].id));
|
||||
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
throw new Error(`Failed to logout: ${error.message}`);
|
||||
} else {
|
||||
throw new Error("Unknown error occurred while logging out");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// --- Relationship Management Functions --- //
|
||||
|
||||
export const createRelationshipRequest = async (requestorId: number, requestedId: number) => {
|
||||
@ -463,7 +308,7 @@ export const sendMessage = async (
|
||||
await ensureUserExists(senderId);
|
||||
await ensureUserExists(receiverId);
|
||||
|
||||
await ensureRelationshipExists(senderId, receiverId);
|
||||
await ensureRelationshipExistsByUserIds(senderId, receiverId);
|
||||
|
||||
// Insert the new message
|
||||
const message = await db.insert(schema.messages).values({
|
||||
@ -481,7 +326,6 @@ export const sendMessage = async (
|
||||
type: mediaType,
|
||||
});
|
||||
}
|
||||
|
||||
return message;
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
@ -495,7 +339,7 @@ export const sendMessage = async (
|
||||
export const fetchMessages = async (userId: number, partnerId: number) => {
|
||||
try {
|
||||
await ensureUserExists(userId);
|
||||
await ensureRelationshipExists(userId, partnerId);
|
||||
await ensureRelationshipExistsByUserIds(userId, partnerId);
|
||||
|
||||
const messages = await db.select().from(schema.messages)
|
||||
.where(or(
|
||||
|
Loading…
Reference in New Issue
Block a user