From 9f7d142ff4a7fe5a773974a3693d28faa0cc9bc1 Mon Sep 17 00:00:00 2001 From: gibbyb Date: Mon, 7 Oct 2024 13:45:42 -0500 Subject: [PATCH] Finish front end tests --- .env.example | 0 .eslintrc.cjs | 0 .gitignore | 0 drizzle.config.ts | 0 next.config.js | 0 package.json | 0 pnpm-lock.yaml | 0 postcss.config.cjs | 0 prettier.config.js | 0 public/favicon.png | Bin src/app/api/updatePushToken/route.ts | 27 ---- src/app/api/users/changePassword/route.ts | 6 + src/app/api/users/logout/route.ts | 19 +-- src/app/layout.tsx | 0 src/app/page.tsx | 0 src/app/relationships/createRequest/page.tsx | 2 +- .../relationships/deleteRelationship/page.tsx | 61 +++++++++ src/app/relationships/updateRequest/page.tsx | 79 +++++++++++ src/app/users/changePassword/page.tsx | 87 ++++++++++++ src/app/users/createUser/page.tsx | 124 ++++++++++++++++++ src/app/users/getUserByID/page.tsx | 58 ++++++++ src/app/users/getUserByUsername/page.tsx | 58 ++++++++ src/app/users/login/page.tsx | 74 +++++++++++ src/app/users/logout/page.tsx | 60 +++++++++ src/app/users/refreshToken/page.tsx | 60 +++++++++ src/app/users/updatePFP/page.tsx | 73 +++++++++++ src/app/users/updatePushToken/page.tsx | 73 +++++++++++ src/env.js | 37 ++---- src/server/db/index.ts | 0 src/server/db/schema.ts | 0 src/server/functions.ts | 25 +++- src/styles/globals.css | 0 tailwind.config.ts | 0 tsconfig.json | 0 34 files changed, 854 insertions(+), 69 deletions(-) mode change 100644 => 100755 .env.example mode change 100644 => 100755 .eslintrc.cjs mode change 100644 => 100755 .gitignore mode change 100644 => 100755 drizzle.config.ts mode change 100644 => 100755 next.config.js mode change 100644 => 100755 package.json mode change 100644 => 100755 pnpm-lock.yaml mode change 100644 => 100755 postcss.config.cjs mode change 100644 => 100755 prettier.config.js mode change 100644 => 100755 public/favicon.png delete mode 100644 src/app/api/updatePushToken/route.ts mode change 100644 => 100755 src/app/layout.tsx mode change 100644 => 100755 src/app/page.tsx create mode 100644 src/app/relationships/deleteRelationship/page.tsx create mode 100644 src/app/relationships/updateRequest/page.tsx create mode 100644 src/app/users/changePassword/page.tsx create mode 100644 src/app/users/createUser/page.tsx create mode 100644 src/app/users/getUserByID/page.tsx create mode 100644 src/app/users/getUserByUsername/page.tsx create mode 100644 src/app/users/login/page.tsx create mode 100644 src/app/users/logout/page.tsx create mode 100644 src/app/users/refreshToken/page.tsx create mode 100644 src/app/users/updatePFP/page.tsx create mode 100644 src/app/users/updatePushToken/page.tsx mode change 100644 => 100755 src/env.js mode change 100644 => 100755 src/server/db/index.ts mode change 100644 => 100755 src/server/db/schema.ts mode change 100644 => 100755 src/server/functions.ts mode change 100644 => 100755 src/styles/globals.css mode change 100644 => 100755 tailwind.config.ts mode change 100644 => 100755 tsconfig.json diff --git a/.env.example b/.env.example old mode 100644 new mode 100755 diff --git a/.eslintrc.cjs b/.eslintrc.cjs old mode 100644 new mode 100755 diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/drizzle.config.ts b/drizzle.config.ts old mode 100644 new mode 100755 diff --git a/next.config.js b/next.config.js old mode 100644 new mode 100755 diff --git a/package.json b/package.json old mode 100644 new mode 100755 diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml old mode 100644 new mode 100755 diff --git a/postcss.config.cjs b/postcss.config.cjs old mode 100644 new mode 100755 diff --git a/prettier.config.js b/prettier.config.js old mode 100644 new mode 100755 diff --git a/public/favicon.png b/public/favicon.png old mode 100644 new mode 100755 diff --git a/src/app/api/updatePushToken/route.ts b/src/app/api/updatePushToken/route.ts deleted file mode 100644 index 6dd80e8..0000000 --- a/src/app/api/updatePushToken/route.ts +++ /dev/null @@ -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 }); - } -}; diff --git a/src/app/api/users/changePassword/route.ts b/src/app/api/users/changePassword/route.ts index a0c8b8d..861f68c 100644 --- a/src/app/api/users/changePassword/route.ts +++ b/src/app/api/users/changePassword/route.ts @@ -18,6 +18,12 @@ export const POST = async (request: NextRequest) => { 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) { diff --git a/src/app/api/users/logout/route.ts b/src/app/api/users/logout/route.ts index d5c5972..aaa7be4 100644 --- a/src/app/api/users/logout/route.ts +++ b/src/app/api/users/logout/route.ts @@ -3,27 +3,20 @@ import { NextResponse } from "next/server"; import type { NextRequest } from "next/server"; import { logout } from "~/server/functions"; import { middleware } from "~/middleware"; -import jwt from "jsonwebtoken"; export const POST = async (request: NextRequest) => { const middlewareResponse = await middleware(request); if (middlewareResponse) return middlewareResponse; try { - const { token } = await request.json() as { token: string }; - if (!token) - return NextResponse.json({ message: "Token is required" },{ status: 400 }); + const { refreshToken } = await request.json() as { refreshToken: string }; + if (!refreshToken) + return NextResponse.json({ message: "Refresh token is required" }, { status: 400 }); - try { - const decoded = jwt.verify(token, process.env.JWT_SECRET!) as { userId: number }; - 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 }); - } + 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 diff --git a/src/app/layout.tsx b/src/app/layout.tsx old mode 100644 new mode 100755 diff --git a/src/app/page.tsx b/src/app/page.tsx old mode 100644 new mode 100755 diff --git a/src/app/relationships/createRequest/page.tsx b/src/app/relationships/createRequest/page.tsx index cf84f50..c2d4a06 100644 --- a/src/app/relationships/createRequest/page.tsx +++ b/src/app/relationships/createRequest/page.tsx @@ -24,7 +24,7 @@ export default function TestCreateRequestPage() { }), }); const data = await response.json() as {message: string}; - setResult(JSON.stringify(data)); + setResult(JSON.stringify(data, null, 2)); } catch (error) { console.error('Error:', error); setResult('An error occurred'); diff --git a/src/app/relationships/deleteRelationship/page.tsx b/src/app/relationships/deleteRelationship/page.tsx new file mode 100644 index 0000000..0442f42 --- /dev/null +++ b/src/app/relationships/deleteRelationship/page.tsx @@ -0,0 +1,61 @@ +"use client"; + +import React, { useState } from 'react'; + +export default function DeleteRelationshipPage() { + const [relationshipId, setRelationshipId] = useState(""); + const [result, setResult] = useState(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 ( +
+
+

Test Send Message

+
+
+ + setRelationshipId(e.target.value)} + className="border p-2 w-full bg-black" + required + /> +
+ +
+ {result && ( +
+
{result}
+
+ )} +
+
+ ); +}; diff --git a/src/app/relationships/updateRequest/page.tsx b/src/app/relationships/updateRequest/page.tsx new file mode 100644 index 0000000..f171dfa --- /dev/null +++ b/src/app/relationships/updateRequest/page.tsx @@ -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(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 ( +
+
+

Test Send Message

+
+
+ + setRelationshipId(e.target.value)} + className="border p-2 w-full bg-black" + required + /> +
+
+ + +
+ +
+ {result && ( +
+
{result}
+
+ )} +
+
+ ); +}; diff --git a/src/app/users/changePassword/page.tsx b/src/app/users/changePassword/page.tsx new file mode 100644 index 0000000..a6b877c --- /dev/null +++ b/src/app/users/changePassword/page.tsx @@ -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(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 ( +
+
+

Test Change Password

+
+
+ + setUserId(e.target.value)} + className="border p-2 w-full bg-black" + required + /> +
+
+ + setOldPassword(e.target.value)} + className="border p-2 w-full bg-black" + required + /> +
+
+ + setNewPassword(e.target.value)} + className="border p-2 w-full bg-black" + required + /> +
+ +
+ {result && ( +
+
{result}
+
+ )} +
+
+ ); +}; diff --git a/src/app/users/createUser/page.tsx b/src/app/users/createUser/page.tsx new file mode 100644 index 0000000..40beeef --- /dev/null +++ b/src/app/users/createUser/page.tsx @@ -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(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 ( +
+
+

Test Create User

+
+
+ + setUsername(e.target.value)} + className="border p-2 w-full bg-black" + required + /> +
+
+ + setEmail(e.target.value)} + className="border p-2 w-full bg-black" + required + /> +
+
+ + setPasswordHash(e.target.value)} + className="border p-2 w-full bg-black" + required + /> +
+
+ + setName(e.target.value)} + className="border p-2 w-full bg-black" + required + /> +
+
+ + setPfpURL(e.target.value)} + className="border p-2 w-full bg-black" + /> +
+
+ + setPushToken(e.target.value)} + className="border p-2 w-full bg-black" + /> +
+ +
+ {result && ( +
+
{result}
+
+ )} +
+
+ ); +}; diff --git a/src/app/users/getUserByID/page.tsx b/src/app/users/getUserByID/page.tsx new file mode 100644 index 0000000..434ab26 --- /dev/null +++ b/src/app/users/getUserByID/page.tsx @@ -0,0 +1,58 @@ +'use client'; + +import React, { useState } from 'react'; + +export default function GetUserByIDPage() { + const [userId, setUserId] = useState(''); + const [result, setResult] = useState(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 ( +
+
+

Test Get User By ID

+
+
+ + setUserId(e.target.value)} + className="border p-2 w-full bg-black" + required + /> +
+ +
+ {result && ( +
+
{result}
+
+ )} +
+
+ ); +}; diff --git a/src/app/users/getUserByUsername/page.tsx b/src/app/users/getUserByUsername/page.tsx new file mode 100644 index 0000000..2b798e7 --- /dev/null +++ b/src/app/users/getUserByUsername/page.tsx @@ -0,0 +1,58 @@ +'use client'; + +import React, { useState } from 'react'; + +export default function GetUserByUsernamePage() { + const [userName, setUserName] = useState(''); + const [result, setResult] = useState(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 ( +
+
+

Test Get User By Username

+
+
+ + setUserName(e.target.value)} + className="border p-2 w-full bg-black" + required + /> +
+ +
+ {result && ( +
+
{result}
+
+ )} +
+
+ ); +}; diff --git a/src/app/users/login/page.tsx b/src/app/users/login/page.tsx new file mode 100644 index 0000000..6fa159c --- /dev/null +++ b/src/app/users/login/page.tsx @@ -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(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 ( +
+
+

Test Login

+
+
+ + setUsername(e.target.value)} + className="border p-2 w-full bg-black" + required + /> +
+
+ + setPassword(e.target.value)} + className="border p-2 w-full bg-black" + required + /> +
+ +
+ {result && ( +
+
{result}
+
+ )} +
+
+ ); +}; diff --git a/src/app/users/logout/page.tsx b/src/app/users/logout/page.tsx new file mode 100644 index 0000000..eaa03a0 --- /dev/null +++ b/src/app/users/logout/page.tsx @@ -0,0 +1,60 @@ +'use client'; + +import React, { useState } from 'react'; + +export default function TestLogout() { + const [refreshToken, setRefreshToken] = useState(''); + const [result, setResult] = useState(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 ( +
+
+

Test Logout

+
+
+ + setRefreshToken(e.target.value)} + className="border p-2 w-full bg-black" + required + /> +
+ +
+ {result && ( +
+
{result}
+
+ )} +
+
+ ); +}; diff --git a/src/app/users/refreshToken/page.tsx b/src/app/users/refreshToken/page.tsx new file mode 100644 index 0000000..cd14381 --- /dev/null +++ b/src/app/users/refreshToken/page.tsx @@ -0,0 +1,60 @@ +'use client'; + +import React, { useState } from 'react'; + +export default function TestRefreshToken() { + const [refreshToken, setRefreshToken] = useState(''); + const [result, setResult] = useState(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 ( +
+
+

Test Refresh Token

+
+
+ + setRefreshToken(e.target.value)} + className="border p-2 w-full bg-black" + required + /> +
+ +
+ {result && ( +
+
{result}
+
+ )} +
+
+ ); +}; diff --git a/src/app/users/updatePFP/page.tsx b/src/app/users/updatePFP/page.tsx new file mode 100644 index 0000000..448d57c --- /dev/null +++ b/src/app/users/updatePFP/page.tsx @@ -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(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 ( +
+
+

Test Update PFP

+
+
+ + setUserId(e.target.value)} + className="border p-2 w-full bg-black" + required + /> +
+
+ + setPfpURL(e.target.value)} + className="border p-2 w-full bg-black" + required + /> +
+ +
+ {result && ( +
+
{result}
+
+ )} +
+
+ ); +} diff --git a/src/app/users/updatePushToken/page.tsx b/src/app/users/updatePushToken/page.tsx new file mode 100644 index 0000000..5cd7408 --- /dev/null +++ b/src/app/users/updatePushToken/page.tsx @@ -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(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 ( +
+
+

Test Update Push Token

+
+
+ + setUserId(e.target.value)} + className="border p-2 w-full bg-black" + required + /> +
+
+ + setPushToken(e.target.value)} + className="border p-2 w-full bg-black" + required + /> +
+ +
+ {result && ( +
+
{result}
+
+ )} +
+
+ ); +}; diff --git a/src/env.js b/src/env.js old mode 100644 new mode 100755 index b0b9671..6b80db4 --- a/src/env.js +++ b/src/env.js @@ -2,45 +2,32 @@ import { createEnv } from "@t3-oss/env-nextjs"; import { z } from "zod"; 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: { DATABASE_URL: z.string().url(), API_KEY: z.string(), NODE_ENV: z .enum(["development", "test", "production"]) .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: { - // 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: { DATABASE_URL: process.env.DATABASE_URL, API_KEY: process.env.API_KEY, 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 - * useful for Docker builds. - */ - 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, + + skipValidation: !!process.env.SKIP_ENV_VALIDATION, + emptyStringAsUndefined: true, }); diff --git a/src/server/db/index.ts b/src/server/db/index.ts old mode 100644 new mode 100755 diff --git a/src/server/db/schema.ts b/src/server/db/schema.ts old mode 100644 new mode 100755 diff --git a/src/server/functions.ts b/src/server/functions.ts old mode 100644 new mode 100755 index c541998..9165bf9 --- a/src/server/functions.ts +++ b/src/server/functions.ts @@ -214,6 +214,8 @@ export const changePassword = async ( 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); @@ -286,6 +288,10 @@ export const login = async (username: string, passwordHash: string) => { .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) { @@ -322,11 +328,21 @@ export const refreshToken = async (refreshToken: string) => { } }; -export const logout = async (userId: number) => { +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({ lastLogin: null }) - .where(eq(schema.users.id, userId)); + .set({ refreshToken: null }) + .where(eq(schema.users.id, user[0].id)); + return { success: true }; } catch (error) { if (error instanceof Error) { @@ -417,6 +433,9 @@ export const updateRelationshipRequest = async (relationshipId: number, status: export const deleteRelationship = async (relationshipId: number) => { try { await db.transaction(async (trx) => { + await trx.delete(schema.countdowns) + .where(eq(schema.countdowns.relationshipId, relationshipId)); + await trx.delete(schema.userRelationships) .where(eq(schema.userRelationships.relationshipId, relationshipId)); diff --git a/src/styles/globals.css b/src/styles/globals.css old mode 100644 new mode 100755 diff --git a/tailwind.config.ts b/tailwind.config.ts old mode 100644 new mode 100755 diff --git a/tsconfig.json b/tsconfig.json old mode 100644 new mode 100755