Moved functions from login/route.ts to another file
Signup route created
This commit is contained in:
parent
fe5c231e89
commit
c64b953a08
98
src/app/api/functions/csvReadWrite.ts
Normal file
98
src/app/api/functions/csvReadWrite.ts
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import path from "path";
|
||||||
|
import fs from "fs";
|
||||||
|
import csv from "csv-parser";
|
||||||
|
|
||||||
|
export type User = {
|
||||||
|
name: string;
|
||||||
|
email: string;
|
||||||
|
password: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {array} - Array of Objects containing user data
|
||||||
|
*/
|
||||||
|
export async function readUserCsv(): Promise<User[]> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
// Dynamic CSV location generation
|
||||||
|
let csvPath = path.dirname(__dirname); // /login
|
||||||
|
csvPath = path.dirname(csvPath); // /api
|
||||||
|
csvPath = path.dirname(csvPath); // /app
|
||||||
|
csvPath = path.dirname(csvPath); // /src
|
||||||
|
csvPath = path.dirname(csvPath); // /[project]
|
||||||
|
csvPath = path.dirname(csvPath); // /termor-tracker
|
||||||
|
csvPath = path.join(csvPath, "src", "databases", "Users.csv");
|
||||||
|
|
||||||
|
// Forms array for user data
|
||||||
|
let results: User[] = [];
|
||||||
|
// Reads data and adds it to results
|
||||||
|
fs.createReadStream(csvPath)
|
||||||
|
.pipe(csv())
|
||||||
|
.on("data", (data) => results.push(data))
|
||||||
|
.on("end", () => {
|
||||||
|
resolve(results);
|
||||||
|
})
|
||||||
|
.on("error", (error) => {
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findUserByEmail(users: User[], email: string): User | undefined {
|
||||||
|
return users.find((user) => user.email === email);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function passwordStrengthCheck(password: string): Promise<string> {
|
||||||
|
if (password.length < 8) {
|
||||||
|
return "short";
|
||||||
|
} else if (password.length > 16) {
|
||||||
|
return "long";
|
||||||
|
}
|
||||||
|
const lowercaseRegex = /[a-z]/;
|
||||||
|
const uppercaseRegex = /[A-Z]/;
|
||||||
|
const digitRegex = /\d/;
|
||||||
|
const specialCharRegex = /[!@#$%^&*]/;
|
||||||
|
if (!lowercaseRegex.test(password)) {
|
||||||
|
return "no lower";
|
||||||
|
} else if (!uppercaseRegex.test(password)) {
|
||||||
|
return "no upper";
|
||||||
|
} else if (!digitRegex.test(password)) {
|
||||||
|
return "no digit";
|
||||||
|
} else if (!specialCharRegex.test(password)) {
|
||||||
|
return "no special";
|
||||||
|
} else {
|
||||||
|
return "secure";
|
||||||
|
}
|
||||||
|
return "end of function";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes User objects to the Users.csv file
|
||||||
|
* @param users {User[]} Array of User objects to write to the CSV file
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
export async function writeUserCsv(users: User[]): Promise<void> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
// Dynamic CSV location generation
|
||||||
|
let csvPath = path.dirname(__dirname); // /login
|
||||||
|
csvPath = path.dirname(csvPath); // /api
|
||||||
|
csvPath = path.dirname(csvPath); // /app
|
||||||
|
csvPath = path.dirname(csvPath); // /src
|
||||||
|
csvPath = path.dirname(csvPath); // /[project]
|
||||||
|
csvPath = path.dirname(csvPath); // /termor-tracker
|
||||||
|
csvPath = path.join(csvPath, "src", "databases", "Users.csv");
|
||||||
|
|
||||||
|
// Prepare CSV data as a string
|
||||||
|
const headers = "name,email,password"; // CSV headers
|
||||||
|
const rows = users.map((user) => `${user.name},${user.email},${user.password}`);
|
||||||
|
const csvData = `${headers}\n${rows.join("\n")}`;
|
||||||
|
|
||||||
|
// Write data to the file
|
||||||
|
fs.writeFile(csvPath, csvData, (error) => {
|
||||||
|
if (error) {
|
||||||
|
reject(error); // Reject promise on error
|
||||||
|
} else {
|
||||||
|
resolve(); // Resolve the promise if successful
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -1,47 +1,5 @@
|
|||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import path from "path";
|
import {User, readUserCsv, findUserByEmail} from "../functions/csvReadWrite"
|
||||||
import fs from "fs";
|
|
||||||
import csv from "csv-parser";
|
|
||||||
|
|
||||||
type User = {
|
|
||||||
name: string;
|
|
||||||
email: string;
|
|
||||||
password: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {array} - Array of Objects containing user data
|
|
||||||
*/
|
|
||||||
async function readUserCsv(): Promise<User[]>{
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
// Dynamic csv location generation
|
|
||||||
let csvPath = path.dirname(__dirname); // /login
|
|
||||||
csvPath = path.dirname(csvPath); // /api
|
|
||||||
csvPath = path.dirname(csvPath); // /app
|
|
||||||
csvPath = path.dirname(csvPath); // /src
|
|
||||||
csvPath = path.dirname(csvPath); // /[project] // ? not sure why this dirfolder is here...
|
|
||||||
csvPath = path.dirname(csvPath); // /termor-tracker
|
|
||||||
csvPath = path.join(csvPath,"src","databases","Users.csv");
|
|
||||||
//Forms array for user data
|
|
||||||
let results : User[] = [];
|
|
||||||
|
|
||||||
//Reads data and adds it to results
|
|
||||||
fs.createReadStream(csvPath)
|
|
||||||
.pipe(csv())
|
|
||||||
.on("data", (data) => results.push(data))
|
|
||||||
.on("end", () => {
|
|
||||||
resolve(results)
|
|
||||||
})
|
|
||||||
.on("error", (error) => {
|
|
||||||
reject(error)
|
|
||||||
})
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function findUserByEmail(users: User[], email: string): User | undefined {
|
|
||||||
return users.find((user) => user.email === email);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function POST(request: Request) {
|
export async function POST(request: Request) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -1,17 +1,54 @@
|
|||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
|
import {User, readUserCsv, writeUserCsv, findUserByEmail, passwordStrengthCheck} from "../functions/csvReadWrite"
|
||||||
|
|
||||||
export async function POST(request: Request) {
|
export async function POST(request: Request) {
|
||||||
try {
|
try {
|
||||||
const body = await request.json(); // Parse incoming JSON data
|
const body = await request.json(); // Parse incoming JSON data
|
||||||
const {name, email, password } = body;
|
const {name, email, password } = body;
|
||||||
|
console.log("Signin API received data");
|
||||||
|
|
||||||
|
const userData = await readUserCsv();
|
||||||
|
|
||||||
|
console.log(userData)
|
||||||
|
console.log("Name:", name); // ! remove
|
||||||
|
console.log("Email:", email); // ! remove
|
||||||
|
console.log("Password:", password);// ! remove
|
||||||
|
|
||||||
|
const foundUser = findUserByEmail(userData,email)
|
||||||
|
|
||||||
|
if (foundUser) {
|
||||||
|
console.log("Email already in the system")
|
||||||
|
return NextResponse.json({ message: "Sorry, this email is already in use" }, { status: 409 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const passwordCheckResult = await passwordStrengthCheck(password)
|
||||||
|
|
||||||
|
if (passwordCheckResult === "short"){
|
||||||
|
return NextResponse.json({ message: "Your password is shorter than 8 characters" }, { status: 400 });
|
||||||
|
} else if (passwordCheckResult === "long"){
|
||||||
|
return NextResponse.json({ message: "Your password is longer than 16 characters" }, { status: 400 });
|
||||||
|
} else if (passwordCheckResult === "no lower"){
|
||||||
|
return NextResponse.json({ message: "Your password must contain a lowercase letters" }, { status: 400 });
|
||||||
|
} else if (passwordCheckResult === "no upper"){
|
||||||
|
return NextResponse.json({ message: "Your password must contain a uppercase letters" }, { status: 400 });
|
||||||
|
} else if (passwordCheckResult === "no digit"){
|
||||||
|
return NextResponse.json({ message: "Your password must contain a number" }, { status: 400 });
|
||||||
|
} else if (passwordCheckResult === "no special"){
|
||||||
|
return NextResponse.json({ message: "Your password must contain a special character (!@#$%^&*)" }, { status: 400 });
|
||||||
|
} else if (passwordCheckResult === "end of function"){
|
||||||
|
return NextResponse.json({ message: "Password check script failure" }, { status: 500 });
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
userData.push(body)
|
||||||
|
await writeUserCsv(userData)
|
||||||
|
return NextResponse.json({ message: "Account Created" }, { status: 201 });
|
||||||
|
} catch(error) {
|
||||||
|
console.error("Error in writting :", error);
|
||||||
|
return NextResponse.json({ message: "Internal Server Error" }, { status: 500 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
console.log("Signup API received data:");
|
|
||||||
console.log("Name:", name);
|
|
||||||
console.log("Email:", email);
|
|
||||||
console.log("Password:", password);
|
|
||||||
|
|
||||||
// For now, just respond back with a success message
|
|
||||||
return NextResponse.json({ message: "Signup successful!" }, { status: 201 });
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error in signup endpoint:", error);
|
console.error("Error in signup endpoint:", error);
|
||||||
return NextResponse.json({ message: "Internal Server Error" }, { status: 500 });
|
return NextResponse.json({ message: "Internal Server Error" }, { status: 500 });
|
||||||
|
|||||||
@ -20,6 +20,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) { //AuthM
|
|||||||
const [isLogin, setIsLogin] = useState<boolean>(true);
|
const [isLogin, setIsLogin] = useState<boolean>(true);
|
||||||
const modalRef = useRef<HTMLDivElement>(null);
|
const modalRef = useRef<HTMLDivElement>(null);
|
||||||
const [isFailed, setIsFailed] = useState<boolean>(false);
|
const [isFailed, setIsFailed] = useState<boolean>(false);
|
||||||
|
const [failMessage, setFailMessage] = useState<boolean>(false);
|
||||||
/*
|
/*
|
||||||
useState is a React Hook that declares state variables in a functional component. It returns a two-element array
|
useState is a React Hook that declares state variables in a functional component. It returns a two-element array
|
||||||
The state variable (isLogin) : Represents the current state value (e.g., true initially). This is the value you can use in your component.
|
The state variable (isLogin) : Represents the current state value (e.g., true initially). This is the value you can use in your component.
|
||||||
@ -90,8 +91,10 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) { //AuthM
|
|||||||
if (res.ok) { //res.ok checks if the response is between 200-299
|
if (res.ok) { //res.ok checks if the response is between 200-299
|
||||||
console.log("Success!");
|
console.log("Success!");
|
||||||
onClose(); // closes UI
|
onClose(); // closes UI
|
||||||
} else if (res.status === 401){
|
} else if (res.status >= 400 && res.status <500){
|
||||||
console.log("Incorrect details provided")
|
const responseBody = await res.json()
|
||||||
|
console.log("4xx error:", responseBody.message)
|
||||||
|
setFailMessage(responseBody.message)
|
||||||
setIsFailed(true)
|
setIsFailed(true)
|
||||||
} else{
|
} else{
|
||||||
console.error("Error:", await res.text()); // logs error with error message sent to console
|
console.error("Error:", await res.text()); // logs error with error message sent to console
|
||||||
@ -104,7 +107,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) { //AuthM
|
|||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center z-50" onClick={handleOverlayClick}>
|
<div className="fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center z-50" onClick={handleOverlayClick}>
|
||||||
<div ref={modalRef} className="bg-white rounded-lg shadow-lg p-6 w-full max-w-md relative">
|
<div ref={modalRef} className="bg-white rounded-lg shadow-lg p-6 w-full max-w-md relative">
|
||||||
<button onClick={onClose} className="absolute text-xl top-0 right-2 text-gray-500 hover:text-gray-700" aria-label="Close modal">
|
<button onClick={() => {setIsFailed(false);onClose();}} className="absolute text-xl top-0 right-2 text-gray-500 hover:text-gray-700" aria-label="Close modal">
|
||||||
×
|
×
|
||||||
</button>
|
</button>
|
||||||
<h2 className="text-2xl font-bold text-center mb-4">{isLogin ? "Login" : "Sign Up"}</h2>
|
<h2 className="text-2xl font-bold text-center mb-4">{isLogin ? "Login" : "Sign Up"}</h2>
|
||||||
@ -143,7 +146,7 @@ export default function AuthModal({ isOpen, onClose }: AuthModalProps) { //AuthM
|
|||||||
<div>
|
<div>
|
||||||
{ isFailed && (
|
{ isFailed && (
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-red-700">Incorrect email or password</label>
|
<label className="block text-sm font-medium text-red-700">{failMessage}</label>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user