base setup
This commit is contained in:
parent
5530c9d336
commit
804f5b2583
30
src/config/config.js
Normal file
30
src/config/config.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
import dotenv from "dotenv";
|
||||
import path from "path";
|
||||
dotenv.config({ path: path.join(process.cwd(), "../.env") });
|
||||
|
||||
const getDb = () => {
|
||||
return {
|
||||
development: {
|
||||
username: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_NAME,
|
||||
host: process.env.DB_HOST,
|
||||
dialect: "postgres",
|
||||
},
|
||||
test: {
|
||||
username: "root",
|
||||
password: null,
|
||||
database: "database_test",
|
||||
host: "127.0.0.1",
|
||||
dialect: "mysql",
|
||||
},
|
||||
production: {
|
||||
username: "root",
|
||||
password: null,
|
||||
database: "database_production",
|
||||
host: "127.0.0.1",
|
||||
dialect: "mysql",
|
||||
},
|
||||
};
|
||||
};
|
||||
export default getDb();
|
|
@ -1,8 +1,8 @@
|
|||
import User from "../models/user.model.js";
|
||||
import { config } from "dotenv";
|
||||
import dotenv from "dotenv";
|
||||
dotenv.config();
|
||||
import User from "../models/user.js";
|
||||
import jwt from "jsonwebtoken";
|
||||
import twilio from "twilio";
|
||||
config();
|
||||
|
||||
const JWT_SECRET = process.env.JWT_SECRET;
|
||||
const accountSid = process.env.TWILIO_ACCOUNT_SID;
|
||||
|
@ -15,11 +15,11 @@ async function sendOtpFromTwilio(to, otp) {
|
|||
const message = await client.messages.create({
|
||||
body: `Your one-time password is ${otp}`,
|
||||
from: process.env.TWILIO_PHONE_NUMBER, // example: "+18563867972"
|
||||
to: "+918847080824",
|
||||
to: to,
|
||||
});
|
||||
return message;
|
||||
} catch (err) {
|
||||
console.error("Twilio send error:", err);
|
||||
console.error("Error while sending twilio otp:", err);
|
||||
return err.message;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
import User from '../models/user.model.js';
|
||||
import User from '../models/user.js';
|
||||
|
||||
// UPDATE USER
|
||||
const updateUser = async (req, res) => {
|
||||
try {
|
||||
const { name } = req.body;
|
||||
const { id } = req.user;
|
||||
const user = await User.findByPk({ id });
|
||||
const user = await User.findOne({
|
||||
where:{
|
||||
id:id
|
||||
}
|
||||
});
|
||||
if(!user) return res.status(401).json({message:"User not found"})
|
||||
await User.update({
|
||||
name
|
||||
|
@ -14,7 +18,7 @@ const updateUser = async (req, res) => {
|
|||
id:id
|
||||
}
|
||||
})
|
||||
res.status(20).json(user);
|
||||
res.status(200).json(user);
|
||||
} catch (err) {
|
||||
res.status(400).json({ error: err.message });
|
||||
}
|
||||
|
@ -47,6 +51,5 @@ export default {
|
|||
updateUser,
|
||||
getAllUsers,
|
||||
getUserById,
|
||||
updateUser,
|
||||
deleteUser,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
const successResponse = async (res, message, data) => {
|
||||
return res.status(200).json({ success: true, message: message, data: data });
|
||||
};
|
||||
|
||||
const errorResponse = async (res, message, data) => {
|
||||
return res.status(500).json({ success: false, message: message, data: data });
|
||||
};
|
||||
|
||||
export default { successResponse, errorResponse };
|
|
@ -1,20 +1,21 @@
|
|||
// middlewares/auth.middleware.js
|
||||
import jwt from 'jsonwebtoken';
|
||||
import jwt from 'jsonwebtoken'
|
||||
|
||||
const verifyToken = (req, res, next) => {
|
||||
const token = req.headers.token;
|
||||
const authHeader = req.headers.authorization; // lowercase 'authorization'
|
||||
|
||||
if (!token) {
|
||||
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||
return res.status(401).json({ message: 'Access denied. No token provided.' });
|
||||
}
|
||||
|
||||
const token = authHeader.split(' ')[1]; // Extract the token part after 'Bearer'
|
||||
|
||||
try {
|
||||
const decoded = jwt.verify(token, process.env.JWT_SECRET); // Ensure this env var exists
|
||||
req.user = decoded; // Attach user payload to request
|
||||
const decoded = jwt.verify(token, process.env.JWT_SECRET);
|
||||
req.user = decoded;
|
||||
next();
|
||||
} catch (err) {
|
||||
return res.status(400).json({ message: 'Invalid token.' });
|
||||
}
|
||||
};
|
||||
|
||||
export default verifyToken;
|
||||
export default verifyToken
|
||||
|
|
41
src/migrations/20250619062253-create-user.js
Normal file
41
src/migrations/20250619062253-create-user.js
Normal file
|
@ -0,0 +1,41 @@
|
|||
'use strict';
|
||||
/** @type {import('sequelize-cli').Migration} */
|
||||
export async function up(queryInterface, Sequelize) {
|
||||
await queryInterface.createTable('Users', {
|
||||
id: {
|
||||
allowNull: false,
|
||||
autoIncrement: true,
|
||||
primaryKey: true,
|
||||
type: Sequelize.INTEGER
|
||||
},
|
||||
name: {
|
||||
type: Sequelize.STRING
|
||||
},
|
||||
country_code: {
|
||||
type: Sequelize.STRING
|
||||
},
|
||||
phone_number: {
|
||||
type: Sequelize.STRING
|
||||
},
|
||||
full_number: {
|
||||
type: Sequelize.STRING
|
||||
},
|
||||
otp: {
|
||||
type: Sequelize.STRING
|
||||
},
|
||||
otp_expiry: {
|
||||
type: Sequelize.DATE
|
||||
},
|
||||
createdAt: {
|
||||
allowNull: false,
|
||||
type: Sequelize.DATE
|
||||
},
|
||||
updatedAt: {
|
||||
allowNull: false,
|
||||
type: Sequelize.DATE
|
||||
}
|
||||
});
|
||||
}
|
||||
export async function down(queryInterface, Sequelize) {
|
||||
await queryInterface.dropTable('Users');
|
||||
}
|
|
@ -1,14 +1,46 @@
|
|||
import sequelize from '../config/database.js';
|
||||
import User from './user.model.js';
|
||||
import { readdirSync } from 'fs';
|
||||
import { basename as _basename, extname, join, dirname } from 'path';
|
||||
import { fileURLToPath, pathToFileURL } from 'url';
|
||||
import Sequelize, { DataTypes } from 'sequelize';
|
||||
import configFile from '../config/config.js';
|
||||
|
||||
const connectDB = async () => {
|
||||
try {
|
||||
await sequelize.authenticate();
|
||||
console.log('Database connected.');
|
||||
await sequelize.sync(); // use { force: true } for dropping and recreating tables
|
||||
} catch (error) {
|
||||
console.error('Unable to connect to the database:', error);
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
const basename = _basename(__filename);
|
||||
const env = process.env.NODE_ENV || 'development';
|
||||
const config = configFile[env];
|
||||
|
||||
const db = {};
|
||||
let sequelize;
|
||||
|
||||
if (config.use_env_variable) {
|
||||
sequelize = new Sequelize(process.env[config.use_env_variable], config);
|
||||
} else {
|
||||
sequelize = new Sequelize(config.database, config.username, config.password, config);
|
||||
}
|
||||
|
||||
const files = readdirSync(__dirname).filter(
|
||||
(file) =>
|
||||
file.indexOf('.') !== 0 &&
|
||||
file !== basename &&
|
||||
extname(file) === '.js' &&
|
||||
!file.endsWith('.test.js')
|
||||
);
|
||||
|
||||
for (const file of files) {
|
||||
const modelModule = await import(pathToFileURL(join(__dirname, file)));
|
||||
const model = modelModule.default(sequelize, DataTypes);
|
||||
db[model.name] = model;
|
||||
}
|
||||
|
||||
Object.keys(db).forEach((modelName) => {
|
||||
if (db[modelName].associate) {
|
||||
db[modelName].associate(db);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
export { sequelize, connectDB, User };
|
||||
db.sequelize = sequelize;
|
||||
db.Sequelize = Sequelize;
|
||||
|
||||
export default db;
|
||||
|
|
32
src/models/user.js
Normal file
32
src/models/user.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
"use strict";
|
||||
import { Model } from "sequelize";
|
||||
export default (sequelize, DataTypes) => {
|
||||
class User extends Model {
|
||||
/**
|
||||
* Helper method for defining associations.
|
||||
* This method is not a part of Sequelize lifecycle.
|
||||
* The `models/index` file will call this method automatically.
|
||||
*/
|
||||
|
||||
static associate(models) {
|
||||
// define association here
|
||||
}
|
||||
}
|
||||
User.init(
|
||||
{
|
||||
name: DataTypes.STRING,
|
||||
country_code: DataTypes.STRING,
|
||||
phone_number: DataTypes.STRING,
|
||||
full_number: DataTypes.STRING,
|
||||
otp: DataTypes.STRING,
|
||||
otp_expiry: DataTypes.DATE,
|
||||
},
|
||||
{
|
||||
sequelize,
|
||||
modelName: "User",
|
||||
underscored: true,
|
||||
timestamps: true,
|
||||
}
|
||||
);
|
||||
return User;
|
||||
};
|
|
@ -1,31 +0,0 @@
|
|||
import { DataTypes } from "sequelize";
|
||||
import sequelize from "../config/database.js";
|
||||
|
||||
const User = sequelize.define("users", {
|
||||
name: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: true,
|
||||
},
|
||||
country_code: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
},
|
||||
phone_number: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
},
|
||||
full_number: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
},
|
||||
otp: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: true,
|
||||
},
|
||||
otp_expiry: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
},
|
||||
});
|
||||
|
||||
export default User;
|
|
@ -1,5 +1,17 @@
|
|||
import { Router } from 'express';
|
||||
import { Router } from "express";
|
||||
const router = Router();
|
||||
import userController from "../controllers/user.controller.js";
|
||||
import validate from "../middleware/validate.js";
|
||||
import { updateUserSchema } from "../validators/user.validator.js";
|
||||
import verifyToken from "../middleware/authenticate.js";
|
||||
|
||||
|
||||
router.put(
|
||||
"/update-user",
|
||||
verifyToken,
|
||||
validate(updateUserSchema),
|
||||
userController.updateUser
|
||||
);
|
||||
|
||||
|
||||
export default router;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import config from 'dotenv'
|
||||
// config()
|
||||
import dotenv from 'dotenv'
|
||||
dotenv.config()
|
||||
import express, { urlencoded, json } from "express";
|
||||
import { connectDB } from "./models/index.js";
|
||||
// import { connectDB } from "./models/index.js";
|
||||
import indexRoutes from "./routes/index.js";
|
||||
import { serve, setup } from "swagger-ui-express";
|
||||
import swaggerSpec from "./swaggerUI/swagger.js";
|
||||
|
@ -14,7 +14,6 @@ app.use("/api-docs", serve, setup(swaggerSpec));
|
|||
app.use("/api", indexRoutes);
|
||||
|
||||
const PORT = process.env.PORT || 3001;
|
||||
|
||||
connectDB().then(() => {
|
||||
// connectDB().then(() => {
|
||||
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
|
||||
});
|
||||
// });
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
import joi from "joi";
|
||||
import { connectDB } from "../models/index.js";
|
||||
import { User } from "../models/index.js";
|
||||
|
||||
const registerSchema = joi.object({
|
||||
countryCode: joi.string().required(),
|
||||
|
|
|
@ -1,22 +1,9 @@
|
|||
import joi from 'joi';
|
||||
|
||||
const createUserSchema = joi.object({
|
||||
name: joi.string().min(1).required(),
|
||||
phone_number: joi.string()
|
||||
.pattern(/^[0-9+\-\s()]+$/)
|
||||
.required()
|
||||
.messages({ 'string.pattern.base': 'Invalid phone number format' }),
|
||||
});
|
||||
|
||||
const updateUserSchema = joi.object({
|
||||
name: joi.string().min(1).optional(),
|
||||
phone_number: joi.string()
|
||||
.pattern(/^[0-9+\-\s()]+$/)
|
||||
.optional()
|
||||
.messages({ 'string.pattern.base': 'Invalid phone number format' }),
|
||||
});
|
||||
|
||||
export default {
|
||||
createUserSchema,
|
||||
updateUserSchema,
|
||||
export {
|
||||
updateUserSchema
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue