+ signup and + verify
All checks were successful
gitea/MERN_STACK_TEMPLATE/pipeline/head This commit looks good

This commit is contained in:
2025-05-02 22:19:30 +02:00
parent 7333cf79bd
commit 3f76d4f3d4
12 changed files with 589 additions and 22 deletions

View File

@ -1 +1,3 @@
Change example.env to .env
Change example.env to .env
>> Join Postman Workspace by following [link](https://app.getpostman.com/join-team?invite_code=2d2ef31819c048b241f82bd7f85ac6dd332460290748fd1f36bee2aedb38200e&target_code=ca1aae0c6efdc09edabb6d99534b9323)

View File

@ -0,0 +1,92 @@
import { User } from "../models/user.model.js";
import bcryptjs from 'bcryptjs';
import {generateTokenAndSetCookie} from "../utils/generateTokenAndSetCookie.js"
import { sendVerificationEmail, sendWelcomeEmail } from "../mailtrap/emails.js";
export const signup = async (req, res) => {
const { email, password, name } = req.body;
try {
if (!email || !password || !name) {
throw new Error("All fields are required");
}
const userAlreadyExists = await User.findOne({ email });
console.log("userAlreadyExists", userAlreadyExists);
if (userAlreadyExists) {
return res.status(400).json({ success: false, message: "User already exists" });
}
const hashedPassword = await bcryptjs.hash(password, 10);
const verificationToken = Math.floor(100000 + Math.random() * 900000).toString();
const user = new User({
email,
password: hashedPassword,
name,
verificationToken,
verificationTokenExpiresAt: Date.now() + 24 * 60 * 60 * 1000, // 24 hours
});
await user.save();
// jwt
generateTokenAndSetCookie(res, user._id);
await sendVerificationEmail(user.email, verificationToken);
res.status(201).json({
success: true,
message: "User created successfully",
user: {
...user._doc,
password: undefined,
},
});
} catch (error) {
res.status(400).json({ success: false, message: error.message });
}
};
export const verifyEmail = async (req, res) => {
const { code } = req.body;
try {
const user = await User.findOne({
verificationToken: code,
verificationTokenExpiresAt: { $gt: Date.now() },
});
if (!user) {
return res.status(400).json({ success: false, message: "Invalid or expired verification code" });
}
user.isVerified = true;
user.verificationToken = undefined;
user.verificationTokenExpiresAt = undefined;
await user.save();
await sendWelcomeEmail(user.email, user.name);
res.status(200).json({
success: true,
message: "Email verified successfully",
user: {
...user._doc,
password: undefined,
},
});
} catch (error) {
console.log("error in verifyEmail ", error);
res.status(500).json({ success: false, message: "Server error" });
}
};
export const login = async (req, res) => {
res.send("login route");
};
export const logout = async (req, res) => {
res.send("logout route")
};

View File

@ -0,0 +1,95 @@
export const VERIFICATION_EMAIL_TEMPLATE = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Verify Your Email</title>
</head>
<body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px;">
<div style="background: linear-gradient(to right, #4CAF50, #45a049); padding: 20px; text-align: center;">
<h1 style="color: white; margin: 0;">Verify Your Email</h1>
</div>
<div style="background-color: #f9f9f9; padding: 20px; border-radius: 0 0 5px 5px; box-shadow: 0 2px 5px rgba(0,0,0,0.1);">
<p>Hello,</p>
<p>Thank you for signing up! Your verification code is:</p>
<div style="text-align: center; margin: 30px 0;">
<span style="font-size: 32px; font-weight: bold; letter-spacing: 5px; color: #4CAF50;">{verificationCode}</span>
</div>
<p>Enter this code on the verification page to complete your registration.</p>
<p>This code will expire in 15 minutes for security reasons.</p>
<p>If you didn't create an account with us, please ignore this email.</p>
<p>Best regards,<br>Your App Team</p>
</div>
<div style="text-align: center; margin-top: 20px; color: #888; font-size: 0.8em;">
<p>This is an automated message, please do not reply to this email.</p>
</div>
</body>
</html>
`;
export const PASSWORD_RESET_SUCCESS_TEMPLATE = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Password Reset Successful</title>
</head>
<body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px;">
<div style="background: linear-gradient(to right, #4CAF50, #45a049); padding: 20px; text-align: center;">
<h1 style="color: white; margin: 0;">Password Reset Successful</h1>
</div>
<div style="background-color: #f9f9f9; padding: 20px; border-radius: 0 0 5px 5px; box-shadow: 0 2px 5px rgba(0,0,0,0.1);">
<p>Hello,</p>
<p>We're writing to confirm that your password has been successfully reset.</p>
<div style="text-align: center; margin: 30px 0;">
<div style="background-color: #4CAF50; color: white; width: 50px; height: 50px; line-height: 50px; border-radius: 50%; display: inline-block; font-size: 30px;">
</div>
</div>
<p>If you did not initiate this password reset, please contact our support team immediately.</p>
<p>For security reasons, we recommend that you:</p>
<ul>
<li>Use a strong, unique password</li>
<li>Enable two-factor authentication if available</li>
<li>Avoid using the same password across multiple sites</li>
</ul>
<p>Thank you for helping us keep your account secure.</p>
<p>Best regards,<br>Your App Team</p>
</div>
<div style="text-align: center; margin-top: 20px; color: #888; font-size: 0.8em;">
<p>This is an automated message, please do not reply to this email.</p>
</div>
</body>
</html>
`;
export const PASSWORD_RESET_REQUEST_TEMPLATE = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Reset Your Password</title>
</head>
<body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px;">
<div style="background: linear-gradient(to right, #4CAF50, #45a049); padding: 20px; text-align: center;">
<h1 style="color: white; margin: 0;">Password Reset</h1>
</div>
<div style="background-color: #f9f9f9; padding: 20px; border-radius: 0 0 5px 5px; box-shadow: 0 2px 5px rgba(0,0,0,0.1);">
<p>Hello,</p>
<p>We received a request to reset your password. If you didn't make this request, please ignore this email.</p>
<p>To reset your password, click the button below:</p>
<div style="text-align: center; margin: 30px 0;">
<a href="{resetURL}" style="background-color: #4CAF50; color: white; padding: 12px 20px; text-decoration: none; border-radius: 5px; font-weight: bold;">Reset Password</a>
</div>
<p>This link will expire in 1 hour for security reasons.</p>
<p>Best regards,<br>Your App Team</p>
</div>
<div style="text-align: center; margin-top: 20px; color: #888; font-size: 0.8em;">
<p>This is an automated message, please do not reply to this email.</p>
</div>
</body>
</html>
`;

View File

@ -0,0 +1,44 @@
import { VERIFICATION_EMAIL_TEMPLATE } from "./emailTemplates.js"
import { mailtrapClient, sender} from "./mailtrap.config.js"
export const sendVerificationEmail = async (email, verificationToken) => {
const recepient = [{ email }]
try {
const response = await mailtrapClient.send({
from: sender,
to: recepient,
subject: "Verify your email",
html: VERIFICATION_EMAIL_TEMPLATE.replace("{verificationCode}", verificationToken),
category: "Email Verification"
})
} catch (error) {
console.error(`Error sending verification`, error);
throw new Error(`Error sending verification email: ${error}`);
}
}
export const sendWelcomeEmail = async (email, name) => {
const recipients = [{email}];
try {
const response = await mailtrapClient.send({
from: sender,
to: recipients,
template_uuid: "eee83ead-5e6d-4784-bd67-c7296f4649b5",
template_variables: {
"company_info_name": "Ai Laplace Lab",
"name": name,
"company_info_address": "Rinstraße 19C",
"company_info_city": "Schwabhausen",
"company_info_zip_code": "85247",
"company_info_country": "Germany"
},
});
console.log("Welcome email sent successfully", response);
} catch (error) {
console.error(`Error sending welcome email`, error);
throw new Error(`Error sending welcome email: ${error}`);
}
};

View File

@ -0,0 +1,13 @@
import { MailtrapClient } from "mailtrap"
import dotenv from "dotenv";
dotenv.config();
export const mailtrapClient = new MailtrapClient({
token: process.env.MAILTRAP_TOKEN,
});
export const sender = {
email: "hello@demomailtrap.co",
name: "Mailtrap Test",
};

View File

@ -0,0 +1,34 @@
import mongoose from "mongoose";
const userSchema = new mongoose.Schema(
{
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
name: {
type: String,
required: true,
},
lastLogin: {
type: Date,
default: Date.now,
},
isVerified: {
type: Boolean,
default: false,
},
resetPasswordToken: String,
resetPasswordExpiresAt: Date,
verificationToken: String,
verificationTokenExpiresAt: Date,
},
{ timestamps: true }
);
export const User = mongoose.model("User", userSchema);

View File

@ -9,8 +9,11 @@
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"bcryptjs": "^3.0.2",
"dotenv": "^16.5.0",
"express": "^5.1.0",
"jsonwebtoken": "^9.0.2",
"mailtrap": "^4.1.0",
"mongoose": "^8.14.1",
"nodemon": "^3.1.10"
}
@ -65,12 +68,38 @@
"node": ">= 8"
}
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"license": "MIT"
},
"node_modules/axios": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz",
"integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"license": "MIT"
},
"node_modules/bcryptjs": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.2.tgz",
"integrity": "sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog==",
"license": "BSD-3-Clause",
"bin": {
"bcrypt": "bin/bcrypt"
}
},
"node_modules/binary-extensions": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
@ -134,6 +163,12 @@
"node": ">=16.20.1"
}
},
"node_modules/buffer-equal-constant-time": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
"license": "BSD-3-Clause"
},
"node_modules/bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@ -196,6 +231,18 @@
"fsevents": "~2.3.2"
}
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"license": "MIT",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@ -258,6 +305,15 @@
}
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"license": "MIT",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
@ -293,6 +349,15 @@
"node": ">= 0.4"
}
},
"node_modules/ecdsa-sig-formatter": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
"license": "Apache-2.0",
"dependencies": {
"safe-buffer": "^5.0.1"
}
},
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@ -338,6 +403,21 @@
"node": ">= 0.4"
}
},
"node_modules/es-set-tostringtag": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.6",
"has-tostringtag": "^1.0.2",
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@ -424,6 +504,62 @@
"node": ">= 0.8"
}
},
"node_modules/follow-redirects": {
"version": "1.15.9",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"license": "MIT",
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/form-data": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
"integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/form-data/node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/form-data/node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"license": "MIT",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@ -547,6 +683,21 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-tostringtag": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/hasown": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
@ -656,6 +807,49 @@
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
"license": "MIT"
},
"node_modules/jsonwebtoken": {
"version": "9.0.2",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
"integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
"license": "MIT",
"dependencies": {
"jws": "^3.2.2",
"lodash.includes": "^4.3.0",
"lodash.isboolean": "^3.0.3",
"lodash.isinteger": "^4.0.4",
"lodash.isnumber": "^3.0.3",
"lodash.isplainobject": "^4.0.6",
"lodash.isstring": "^4.0.1",
"lodash.once": "^4.0.0",
"ms": "^2.1.1",
"semver": "^7.5.4"
},
"engines": {
"node": ">=12",
"npm": ">=6"
}
},
"node_modules/jwa": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
"license": "MIT",
"dependencies": {
"buffer-equal-constant-time": "1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1"
}
},
"node_modules/jws": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
"license": "MIT",
"dependencies": {
"jwa": "^1.4.1",
"safe-buffer": "^5.0.1"
}
},
"node_modules/kareem": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz",
@ -665,6 +859,73 @@
"node": ">=12.0.0"
}
},
"node_modules/lodash.includes": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
"integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
"license": "MIT"
},
"node_modules/lodash.isboolean": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
"integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
"license": "MIT"
},
"node_modules/lodash.isinteger": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
"integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
"license": "MIT"
},
"node_modules/lodash.isnumber": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
"integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
"license": "MIT"
},
"node_modules/lodash.isplainobject": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
"license": "MIT"
},
"node_modules/lodash.isstring": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
"license": "MIT"
},
"node_modules/lodash.once": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
"license": "MIT"
},
"node_modules/mailtrap": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/mailtrap/-/mailtrap-4.1.0.tgz",
"integrity": "sha512-rCuumv0ZcLvxMukV8Pn9sh5hmk2TL23THrpwgE/yXwDfeJQdJGVENa2rNzGR9zcGsUK3LSXuyvjKrTwc21RBOQ==",
"license": "MIT",
"dependencies": {
"axios": ">=0.27"
},
"engines": {
"node": ">=16.20.1",
"yarn": ">=1.22.17"
},
"peerDependencies": {
"@types/nodemailer": "^6.4.9",
"nodemailer": "^6.9.4"
},
"peerDependenciesMeta": {
"@types/nodemailer": {
"optional": true
},
"nodemailer": {
"optional": true
}
}
},
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@ -961,6 +1222,12 @@
"node": ">= 0.10"
}
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"license": "MIT"
},
"node_modules/pstree.remy": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",

View File

@ -13,8 +13,11 @@
"license": "ISC",
"description": "",
"dependencies": {
"bcryptjs": "^3.0.2",
"dotenv": "^16.5.0",
"express": "^5.1.0",
"jsonwebtoken": "^9.0.2",
"mailtrap": "^4.1.0",
"mongoose": "^8.14.1",
"nodemon": "^3.1.10"
}

View File

@ -1,18 +1,13 @@
import express from "express";
import {login, signup, logout, verifyEmail} from "../controllers/auth.controller.js";
const router = express.Router();
router.get("/signup", (req, res) => {
res.send("Signup route");
})
router.post("/signup", signup);
router.post("/login", login);
router.post("/logout", logout);
router.get("/login", (req, res) => {
res.send("Signup route");
})
router.post("/verify-email", verifyEmail);
router.get("/logout", (req, res) => {
res.send("Signup route");
})
export default router;

View File

@ -1,22 +1,18 @@
import express from "express";
import dotenv from "dotenv";
import {connectDB} from "./db/connectDB.js";
import { connectDB } from "./db/connectDB.js";
import authRoutes from "./routes/auth.route.js"
import authRoutes from "./routes/auth.route.js";
dotenv.config();
const app = express();
app.get("/", (req, res) => {
res.send("Hello World!");
});
app.use("/api/auth", authRoutes)
const PORT = process.env.PORT || 8080;
app.use(express.json()); // allows us to parse incoming requests:req.body
app.use("/api/auth", authRoutes);
app.listen(8080, () => {
app.listen(PORT, () => {
connectDB();
console.log("Server Started at 0.0.0.0:8080");
console.log("Server Started at 0.0.0.0: ", PORT);
});

View File

@ -0,0 +1,16 @@
import jwt from "jsonwebtoken";
export const generateTokenAndSetCookie = (res, userId) => {
const token = jwt.sign({ userId}, process.env.JWT_SECRET, {
expiresIn: "7d",
});
res.cookie("token", token, {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
sameSite: "strict",
maxAge: 7 * 24 * 60 * 60 * 1000,
});
return token;
}

10
docker-compose.mongo.yaml Normal file
View File

@ -0,0 +1,10 @@
services:
mongo:
image: mongo
restart: always
ports:
- "27017:27017"
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: test