Added signup route 👤
This commit is contained in:
875
backend/package-lock.json
generated
875
backend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -12,10 +12,14 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"description": "",
|
"description": "",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"bcrypt": "^5.1.1",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"express": "^4.21.1",
|
"express": "^4.21.1",
|
||||||
"mongoose": "^8.8.0",
|
"mongoose": "^8.8.0",
|
||||||
"socket.io": "^4.8.1"
|
"socket.io": "^4.8.1",
|
||||||
|
"swagger-jsdoc": "^6.2.8",
|
||||||
|
"swagger-ui-express": "^5.0.1",
|
||||||
|
"zod": "^3.23.8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ dotenv.config();
|
|||||||
|
|
||||||
export const PORT = Number(process.env.PORT);
|
export const PORT = Number(process.env.PORT);
|
||||||
export const DB_URL = process.env.DB_CONNECTION;
|
export const DB_URL = process.env.DB_CONNECTION;
|
||||||
|
export const SALT = Number(process.env.SALT_ROUNDS);
|
||||||
28
backend/src/controllers/user.controller.js
Normal file
28
backend/src/controllers/user.controller.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import { signupService } from "../services/user.service.js";
|
||||||
|
|
||||||
|
export async function signupController(req, res) {
|
||||||
|
try {
|
||||||
|
const { username, email, password } = req.body;
|
||||||
|
const user = await signupService(username, email, password);
|
||||||
|
res.status(201).json({
|
||||||
|
success : true,
|
||||||
|
message : "User created successfully",
|
||||||
|
data : user
|
||||||
|
})
|
||||||
|
}
|
||||||
|
catch(err){
|
||||||
|
console.log(err);
|
||||||
|
if (err.statusCode){
|
||||||
|
res.status(err.statusCode).json({
|
||||||
|
success : false,
|
||||||
|
message : err.message
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res.status(500).json({
|
||||||
|
success : false,
|
||||||
|
message : err.message
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,10 +4,16 @@ import { createServer } from 'http'
|
|||||||
import { Server } from 'socket.io'
|
import { Server } from 'socket.io'
|
||||||
import { PORT } from './config/veriables.js';
|
import { PORT } from './config/veriables.js';
|
||||||
import { connectDB } from './config/dbConfig.js';
|
import { connectDB } from './config/dbConfig.js';
|
||||||
|
import userRouter from './routes/v1/user.route.js';
|
||||||
|
import swaggerDocs from '../swagger.js';
|
||||||
|
import swaggerUi from 'swagger-ui-express';
|
||||||
|
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const httpServer = createServer(app);
|
const httpServer = createServer(app);
|
||||||
|
|
||||||
|
app.use('/docs', swaggerUi.serve, swaggerUi.setup(swaggerDocs));
|
||||||
|
|
||||||
const io = new Server(httpServer, {
|
const io = new Server(httpServer, {
|
||||||
cors: {
|
cors: {
|
||||||
origin: "*"
|
origin: "*"
|
||||||
@@ -19,6 +25,7 @@ app.use(express.json())
|
|||||||
app.get("/ping", (_req, res) => {
|
app.get("/ping", (_req, res) => {
|
||||||
res.json({ message: "pong" })
|
res.json({ message: "pong" })
|
||||||
})
|
})
|
||||||
|
app.use("/api/v1/user", userRouter);
|
||||||
|
|
||||||
await connectDB();
|
await connectDB();
|
||||||
httpServer.listen(PORT, () => {
|
httpServer.listen(PORT, () => {
|
||||||
|
|||||||
28
backend/src/models/user.model.js
Normal file
28
backend/src/models/user.model.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import mongoose, { Schema } from "mongoose";
|
||||||
|
|
||||||
|
const userSchema = new Schema({
|
||||||
|
username : {
|
||||||
|
type : String,
|
||||||
|
required : true,
|
||||||
|
trim : true
|
||||||
|
},
|
||||||
|
email : {
|
||||||
|
type : String,
|
||||||
|
required : true,
|
||||||
|
trim : true,
|
||||||
|
unique : true
|
||||||
|
},
|
||||||
|
password : {
|
||||||
|
type : String,
|
||||||
|
required : true
|
||||||
|
},
|
||||||
|
bookmarks : {
|
||||||
|
type : [Schema.Types.ObjectId],
|
||||||
|
ref : "Poll",
|
||||||
|
default : []
|
||||||
|
}
|
||||||
|
}, {timestamps : true});
|
||||||
|
|
||||||
|
|
||||||
|
const UserModel = mongoose.model("User", userSchema);
|
||||||
|
export default UserModel;
|
||||||
16
backend/src/repositories/user.repo.js
Normal file
16
backend/src/repositories/user.repo.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import UserModel from "../models/user.model.js"
|
||||||
|
|
||||||
|
export const createUser = async (username, email, password) => {
|
||||||
|
try {
|
||||||
|
const createdUser = await UserModel.create({
|
||||||
|
username,
|
||||||
|
email,
|
||||||
|
password
|
||||||
|
})
|
||||||
|
|
||||||
|
return createdUser;
|
||||||
|
}
|
||||||
|
catch(err) {
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
42
backend/src/routes/v1/user.route.js
Normal file
42
backend/src/routes/v1/user.route.js
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import express from "express";
|
||||||
|
import { signupController } from "../../controllers/user.controller.js";
|
||||||
|
import validate from "../../validations/validator.js";
|
||||||
|
import signupSchema from "../../validations/signupValidation.js";
|
||||||
|
const userRouter = express.Router();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /user/test:
|
||||||
|
* get:
|
||||||
|
* summary: Test route for user
|
||||||
|
* tags: [User]
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Success
|
||||||
|
*/
|
||||||
|
userRouter.get("/test", (req, res) => {
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
message : "User route is working✔️"
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /user/signup:
|
||||||
|
* post:
|
||||||
|
* summary: User signup
|
||||||
|
* tags: [User]
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/User'
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Success
|
||||||
|
*/
|
||||||
|
userRouter.post("/signup", validate(signupSchema), signupController);
|
||||||
|
|
||||||
|
export default userRouter;
|
||||||
26
backend/src/services/user.service.js
Normal file
26
backend/src/services/user.service.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { SALT } from "../config/veriables.js";
|
||||||
|
import { createUser } from "../repositories/user.repo.js";
|
||||||
|
import bcrypt from "bcrypt";
|
||||||
|
|
||||||
|
export async function signupService(username, email, password) {
|
||||||
|
try {
|
||||||
|
if (username.trim() == "" || email.trim() == "" || password.trim() == "") {
|
||||||
|
throw {
|
||||||
|
statusCode: 400,
|
||||||
|
message: "All fields are required",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const hashedPassword = bcrypt.hashSync(password, SALT);
|
||||||
|
const user = await createUser(username, email, hashedPassword);
|
||||||
|
return user;
|
||||||
|
} catch (err) {
|
||||||
|
if (err.code == 11000) {
|
||||||
|
throw {
|
||||||
|
statusCode: 409,
|
||||||
|
message: "User already exists",
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
27
backend/src/validations/signupValidation.js
Normal file
27
backend/src/validations/signupValidation.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
const signupSchema = z.object({
|
||||||
|
username: z
|
||||||
|
.string({
|
||||||
|
required_error: "Username is required",
|
||||||
|
invalid_type_error: "Username must be a string",
|
||||||
|
})
|
||||||
|
.min(3, "Username must be at least 3 characters long")
|
||||||
|
.max(50, "Username must be at most 50 characters long")
|
||||||
|
.trim(),
|
||||||
|
email: z
|
||||||
|
.string({
|
||||||
|
required_error: "Email is required",
|
||||||
|
invalid_type_error: "Email must be a string",
|
||||||
|
})
|
||||||
|
.email("Invalid email"),
|
||||||
|
password: z
|
||||||
|
.string({
|
||||||
|
required_error: "Password is required",
|
||||||
|
invalid_type_error: "Password must be a string",
|
||||||
|
})
|
||||||
|
.min(6, "Password must be at least 6 characters long")
|
||||||
|
.max(50, "Password must be at most 50 characters long"),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default signupSchema;
|
||||||
17
backend/src/validations/validator.js
Normal file
17
backend/src/validations/validator.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
function validate (schema){
|
||||||
|
return async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
await schema.parseAsync(req.body);
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
catch(err){
|
||||||
|
res.status(400).json({
|
||||||
|
success : false,
|
||||||
|
message : "Validation error",
|
||||||
|
errors : err.errors
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default validate;
|
||||||
24
backend/swagger.js
Normal file
24
backend/swagger.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import swaggerJSDoc from 'swagger-jsdoc';
|
||||||
|
|
||||||
|
// Define Swagger options
|
||||||
|
const swaggerOptions = {
|
||||||
|
swaggerDefinition: {
|
||||||
|
openapi: '3.0.0',
|
||||||
|
info: {
|
||||||
|
title: 'LivePoll API',
|
||||||
|
version: '1.0.0',
|
||||||
|
description: 'API documentation for LivePoll',
|
||||||
|
},
|
||||||
|
servers: [
|
||||||
|
{
|
||||||
|
url: 'http://localhost:3000/api/v1', // your server URL
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
apis: ['./src/routes/v1/*.js'], // Path to the API docs
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initialize swagger-jsdoc
|
||||||
|
const swaggerDocs = swaggerJSDoc(swaggerOptions);
|
||||||
|
|
||||||
|
export default swaggerDocs;
|
||||||
Reference in New Issue
Block a user