Skip to content

Commit

Permalink
Initial commits of project
Browse files Browse the repository at this point in the history
  • Loading branch information
sAchin-680 committed Sep 22, 2024
0 parents commit 9a9e99d
Show file tree
Hide file tree
Showing 29 changed files with 9,379 additions and 0 deletions.
29 changes: 29 additions & 0 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: CI/CD Pipeline

on:
push:
branches:
- main

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: '16'

- name: Install dependencies
run: npm install

- name: Run tests
run: npm test

- name: Deploy to Heroku
run: git push heroku main
env:
HEROKU_API_KEY: ${{ secrets.HEROKU_API_KEY }}
36 changes: 36 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Node modules
node_modules/

# Environment variables
.env

# Docker-related files
.dockerignore

# Log files
npm-debug.log
yarn-error.log

# Build artifacts
build/
dist/

# Temporary files
.DS_Store
Thumbs.db

# Coverage reports
coverage/

# Local development configurations
.vscode/
.idea/

# Miscellaneous
.env.local
.env.development.local
.env.test

# Additional
error.log
combined.log
20 changes: 20 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Base image
FROM node:16-alpine

# Create app directory
WORKDIR /app

# Copy package.json and package-lock.json
COPY package*.json ./

# Install dependencies
RUN npm install

# Copy the rest of the app files
COPY . .

# Expose port
EXPOSE 5000

# Start the application
CMD ["npm", "start"]
1 change: 1 addition & 0 deletions Procfile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
web: npm start
36 changes: 36 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const express = require('express');
const dotenv = require('dotenv');
const morgan = require('morgan');
const { ApolloServer } = require('apollo-server-express');
const typeDefs = require('./graphql/schema');
const resolvers = require('./graphql/resolvers');
const rateLimiter = require('./middlewares/rateLimiter');
const csrf = require('csurf');
const cookieParser = require('cookie-parser');
const setupSwagger = require('./swagger');

dotenv.config();

const app = express();
app.use(cookieParser());
app.use(express.json());
app.use(morgan('dev'));
app.use(rateLimiter);

const csrfProtection = csrf({ cookie: true });

app.use((req, res, next) => {
if (req.path === '/graphql') {
return next();
}
csrfProtection(req, res, next);
});

const server = new ApolloServer({ typeDefs, resolvers });
server.start().then(() => {
server.applyMiddleware({ app });
});

setupSwagger(app);

module.exports = app;
19 changes: 19 additions & 0 deletions config/db.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const mongoose = require('mongoose');
const dotenv = require('dotenv');

dotenv.config();

const connectDB = async () => {
try {
await mongoose.connect(process.env.MONGO_URI, {
// useNewUrlParser: true,
// useUnifiedTopology: true,
});
console.log('MongoDB connected');
} catch (error) {
console.error(`Error: ${error.message}`);
process.exit(1); // Exit process with failure
}
};

module.exports = connectDB;
13 changes: 13 additions & 0 deletions config/redisClient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const redis = require('redis');

const client = redis.createClient({
url: process.env.REDIS_URL,
});

client.on('error', (err) => {
console.error('Redis connection error:', err);
});

client.connect();

module.exports = client;
75 changes: 75 additions & 0 deletions controllers/authController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
const User = require('../models/User');
const generateToken = require('../utils/generateToken');

// @desc Register a new user
// @route POST /api/auth/register
// @access Public
const registerUser = async (req, res) => {
const { name, email, password } = req.body;

// Check if user already exists
const userExists = await User.findOne({ email });

if (userExists) {
return res.status(400).json({ message: 'User already exists' });
}

// Create new user
const user = await User.create({
name,
email,
password,
});

if (user) {
res.status(201).json({
_id: user._id,
name: user.name,
email: user.email,
role: user.role,
token: generateToken(user._id),
});
} else {
res.status(400).json({ message: 'Invalid user data' });
}
};

// @desc Authenticate user and get token
// @route POST /api/auth/login
// @access Public
const loginUser = async (req, res) => {
const { email, password } = req.body;

const user = await User.findOne({ email });

if (user && (await user.matchPassword(password))) {
res.json({
_id: user._id,
name: user.name,
email: user.email,
role: user.role,
token: generateToken(user._id),
});
} else {
res.status(401).json({ message: 'Invalid email or password' });
}
};

// @desc Get user profile
// @route GET /api/auth/profile
// @access Private
const getUserProfile = async (req, res) => {
const user = await User.findById(req.user.id).select('-password');

if (user) {
res.json(user);
} else {
res.status(404).json({ message: 'User not found' });
}
};

module.exports = {
registerUser,
loginUser,
getUserProfile,
};
142 changes: 142 additions & 0 deletions controllers/productController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
const Product = require('../models/Product');
const redisClient = require('../config/redisClient');

// @desc Create a new product
// @route POST /api/products
// @access Public or Admin (adjust based on your needs)
const createProduct = async (req, res) => {
try {
const { name, description, price, category } = req.body;

// Validate inputs
if (!name || !description || !price || !category) {
return res.status(400).json({ message: 'All fields are required' });
}

// Create a new product
const product = new Product({
name,
description,
price,
category,
});

// Save product to the database
const savedProduct = await product.save();

res.status(201).json({
success: true,
message: 'Product created successfully',
data: savedProduct,
});
} catch (error) {
res.status(500).json({ message: error.message });
}
};

// @desc Get all products with pagination & filtering
// @route GET /api/products
// @access Public
const getProducts = async (req, res) => {
try {
const pageSize = Number(req.query.pageSize) || 10; // Default page size is 10
const page = Number(req.query.page) || 1;

const keyword = req.query.keyword
? {
name: {
$regex: req.query.keyword,
$options: 'i', // Case-insensitive search
},
}
: {};

const count = await Product.countDocuments({ ...keyword });
const products = await Product.find({ ...keyword })
.limit(pageSize)
.skip(pageSize * (page - 1));

res.json({
products,
page,
pages: Math.ceil(count / pageSize),
});
} catch (error) {
res.status(500).json({ message: error.message });
}
};

// @desc Update product by ID
// @route PUT /api/products/:id
// @access Public or Admin
const updateProduct = async (req, res) => {
try {
const { name, description, price, category } = req.body;
const product = await Product.findById(req.params.id);

if (!product) {
return res.status(404).json({ message: 'Product not found' });
}

// Update product fields
product.name = name || product.name;
product.description = description || product.description;
product.price = price || product.price;
product.category = category || product.category;

const updatedProduct = await product.save();

res.json(updatedProduct);
} catch (error) {
res.status(500).json({ message: error.message });
}
};

// @desc Delete product by ID
// @route DELETE /api/products/:id
// @access Public or Admin
const deleteProduct = async (req, res) => {
try {
const product = await Product.findById(req.params.id);

if (!product) {
return res.status(404).json({ message: 'Product not found' });
}

await product.remove();
res.json({ message: 'Product deleted successfully' });
} catch (error) {
res.status(500).json({ message: error.message });
}
};

// @desc Get product by ID
// @route GET /api/products/:id
// @access Public
const getProductById = async (req, res) => {
try {
const product = await Product.findById(req.params.id);

if (!product) {
return res.status(404).json({ message: 'Product not found' });
}

// Store product in Redis cache for future requests
await redisClient.setEx(
`product:${product._id}`,
3600,
JSON.stringify(product)
); // Cache for 1 hour

res.json(product);
} catch (error) {
res.status(500).json({ message: error.message });
}
};
module.exports = {
createProduct,
getProducts,
getProductById,
updateProduct,
deleteProduct,
};
Loading

0 comments on commit 9a9e99d

Please sign in to comment.