Objective:
Create an assignment submission portal with the following functionality and structure.

Scenario:
You are tasked with developing a backend system for an assignment submission portal. The system should support users and admins where:

Users can upload assignments.
Assignments in this case can just be an object like below

{
    'userId':Soumik,
    'task':'Hello World',
    'admin':'Alok',
}
Admins can accept or reject these assignments.
Admin can see all assignments tagged to them
Admins will see each the user name, task and timedate data
Admin can either reject or accept them
Requirements:
Database:
Use MongoDB as your database.
Structure and Functionality:
There should be two types of users: Admin and User.
Users can:
Register and log in.
Upload assignments.
Admins can:
Register and log in.
View assignments tagged to them.
Accept or reject assignments.
Endpoints:
User Endpoints:
POST /register - Register a new user.
POST /login - User login.
POST /upload - Upload an assignment.
GET /admins- fetch all admins
Admin Endpoints:
POST /register - Register a new admin.
POST /login - Admin login.
GET /assignments - View assignments tagged to the admin.
POST /assignments/:id/accept - Accept an assignment.
POST /assignments/:id/reject - Reject an assignment.
Validation:
Ensure all inputs are validated.
Provide proper error messages for invalid inputs.
User Management:
Implement proper user management.
(Optional) Implement OAuth2 for user authentication.
Modularity:
Ensure the code is modular and well-structured for readability and maintainability.
Deliverables:
A fully functional backend system that meets the requirements.
Proper documentation on how to set up and run the system.
Clear and concise comments in your code for readability.
Can you do it for me and also first start with the file structure

Sure, I can help you design and implement the backend for your assignment submission portal. Let's start by outlining a well-structured file architecture that promotes modularity, scalability, and maintainability. We'll use Node.js with Express and MongoDB (via Mongoose) to build the backend.

Proposed File Structure

assignment-portal/
├── config/
│   ├── db.js
│   └── default.json
├── controllers/
│   ├── adminController.js
│   └── userController.js
├── middleware/
│   ├── authMiddleware.js
│   └── errorHandler.js
├── models/
│   ├── Admin.js
│   ├── Assignment.js
│   └── User.js
├── routes/
│   ├── adminRoutes.js
│   ├── userRoutes.js
│   └── assignmentRoutes.js
├── utils/
│   └── validators.js
├── .env
├── .gitignore
├── app.js
├── package.json
└── README.md
Directory & File Breakdown
config/
db.js: Handles the connection to the MongoDB database.
default.json: Configuration file for default settings (optional if using .env).
controllers/
userController.js: Contains logic for user-related actions like registration, login, and assignment uploads.
adminController.js: Contains logic for admin-related actions like viewing, accepting, and rejecting assignments.
middleware/
authMiddleware.js: Handles authentication and authorization for different routes.
errorHandler.js: Centralized error handling middleware.
models/
User.js: Defines the User schema and model.
Admin.js: Defines the Admin schema and model.
Assignment.js: Defines the Assignment schema and model.
routes/
userRoutes.js: Defines all user-related API endpoints.
adminRoutes.js: Defines all admin-related API endpoints.
assignmentRoutes.js: (Optional) If assignments have separate routes.
utils/
validators.js: Contains input validation functions using libraries like Joi or express-validator.
Root Files
.env: Environment variables (e.g., database URI, JWT secret).
.gitignore: Specifies intentionally untracked files to ignore.
app.js: Initializes Express app, middlewares, and routes.
package.json: Lists dependencies and scripts.
README.md: Documentation for setting up and running the project.
Step-by-Step Implementation Guide
1. Initialize the Project
Start by setting up a new Node.js project.


mkdir assignment-portal
cd assignment-portal
npm init -y
2. Install Dependencies
Install the necessary dependencies.


npm install express mongoose dotenv bcryptjs jsonwebtoken cors
npm install --save-dev nodemon
express: Web framework.
mongoose: MongoDB object modeling.
dotenv: Environment variable management.
bcryptjs: Password hashing.
jsonwebtoken: JWT authentication.
cors: Enable Cross-Origin Resource Sharing.
nodemon: Development utility for auto-restarting the server.
3. Configure Environment Variables
Create a .env file in the root directory.


PORT=5000
MONGO_URI=your_mongodb_connection_string
JWT_SECRET=your_jwt_secret
Note: Replace your_mongodb_connection_string and your_jwt_secret with actual values. Ensure .env is added to .gitignore to prevent sensitive information from being exposed.

4. Setup Database Connection
Create config/db.js to handle MongoDB connection.


// config/db.js
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('MongoDB connection failed:', error.message);
        process.exit(1);
    }
};

module.exports = connectDB;
5. Define Mongoose Models
a. User Model

// models/User.js
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');

const userSchema = new mongoose.Schema({
    username: {
        type: String,
        required: [true, 'Please provide a username'],
        unique: true,
    },
    password: {
        type: String,
        required: [true, 'Please provide a password'],
    },
    role: {
        type: String,
        enum: ['user', 'admin'],
        default: 'user',
    },
}, { timestamps: true });

// Pre-save hook to hash password
userSchema.pre('save', async function(next) {
    if (!this.isModified('password')) {
        next();
    }
    const salt = await bcrypt.genSalt(10);
    this.password = await bcrypt.hash(this.password, salt);
    next();
});

// Method to compare password
userSchema.methods.matchPassword = async function(enteredPassword) {
    return await bcrypt.compare(enteredPassword, this.password);
};

module.exports = mongoose.model('User', userSchema);
Note: We're using a single User model with a role field to differentiate between users and admins. This approach simplifies authentication and authorization.

b. Assignment Model

// models/Assignment.js
const mongoose = require('mongoose');

const assignmentSchema = new mongoose.Schema({
    user: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'User',
        required: true,
    },
    task: {
        type: String,
        required: [true, 'Please provide a task description'],
    },
    admin: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'User', // Reference to Admin in User model
        required: true,
    },
    status: {
        type: String,
        enum: ['pending', 'accepted', 'rejected'],
        default: 'pending',
    },
}, { timestamps: true });

module.exports = mongoose.model('Assignment', assignmentSchema);
6. Implement Middleware
a. Authentication & Authorization Middleware

// middleware/authMiddleware.js
const jwt = require('jsonwebtoken');
const User = require('../models/User');
const dotenv = require('dotenv');

dotenv.config();

const protect = async (req, res, next) => {
    let token;

    if (req.headers.authorization && req.headers.authorization.startsWith('Bearer')) {
        try {
            token = req.headers.authorization.split(' ')[1];
            const decoded = jwt.verify(token, process.env.JWT_SECRET);
            req.user = await User.findById(decoded.id).select('-password');
            next();
        } catch (error) {
            console.error(error);
            res.status(401).json({ message: 'Not authorized, token failed' });
        }
    }

    if (!token) {
        res.status(401).json({ message: 'Not authorized, no token' });
    }
};

const authorize = (roles) => {
    return (req, res, next) => {
        if (!roles.includes(req.user.role)) {
            return res.status(403).json({ message: `User role '${req.user.role}' is not authorized` });
        }
        next();
    };
};

module.exports = { protect, authorize };
b. Error Handling Middleware

// middleware/errorHandler.js
const errorHandler = (err, req, res, next) => {
    console.error(err.stack);
    res.status(err.statusCode || 500).json({
        message: err.message || 'Server Error',
    });
};

module.exports = errorHandler;
7. Create Controllers
a. User Controller

// controllers/userController.js
const User = require('../models/User');
const Assignment = require('../models/Assignment');
const jwt = require('jsonwebtoken');
const dotenv = require('dotenv');

dotenv.config();

// Generate JWT Token
const generateToken = (id) => {
    return jwt.sign({ id }, process.env.JWT_SECRET, { expiresIn: '30d' });
};

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

    try {
        const userExists = await User.findOne({ username });

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

        const user = await User.create({
            username,
            password,
            role: 'user',
        });

        res.status(201).json({
            _id: user._id,
            username: user.username,
            role: user.role,
            token: generateToken(user._id),
        });
    } catch (error) {
        res.status(500).json({ message: 'Server Error' });
    }
};

// @desc    Login user
// @route   POST /api/users/login
// @access  Public
exports.loginUser = async (req, res) => {
    const { username, password } = req.body;

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

        if (user && (await user.matchPassword(password))) {
            res.json({
                _id: user._id,
                username: user.username,
                role: user.role,
                token: generateToken(user._id),
            });
        } else {
            res.status(401).json({ message: 'Invalid credentials' });
        }
    } catch (error) {
        res.status(500).json({ message: 'Server Error' });
    }
};

// @desc    Upload an assignment
// @route   POST /api/users/upload
// @access  Private (User)
exports.uploadAssignment = async (req, res) => {
    const { task, adminId } = req.body;

    try {
        const admin = await User.findById(adminId);

        if (!admin || admin.role !== 'admin') {
            return res.status(400).json({ message: 'Invalid admin selected' });
        }

        const assignment = await Assignment.create({
            user: req.user._id,
            task,
            admin: admin._id,
        });

        res.status(201).json(assignment);
    } catch (error) {
        res.status(500).json({ message: 'Server Error' });
    }
};

// @desc    Get all admins
// @route   GET /api/users/admins
// @access  Private (User)
exports.getAllAdmins = async (req, res) => {
    try {
        const admins = await User.find({ role: 'admin' }).select('-password');
        res.json(admins);
    } catch (error) {
        res.status(500).json({ message: 'Server Error' });
    }
};
b. Admin Controller

// controllers/adminController.js
const Assignment = require('../models/Assignment');
const User = require('../models/User');

// @desc    Register a new admin
// @route   POST /api/admins/register
// @access  Public
exports.registerAdmin = async (req, res) => {
    const { username, password } = req.body;

    try {
        const adminExists = await User.findOne({ username });

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

        const admin = await User.create({
            username,
            password,
            role: 'admin',
        });

        res.status(201).json({
            _id: admin._id,
            username: admin.username,
            role: admin.role,
            token: generateToken(admin._id),
        });
    } catch (error) {
        res.status(500).json({ message: 'Server Error' });
    }
};

// @desc    Login admin
// @route   POST /api/admins/login
// @access  Public
exports.loginAdmin = async (req, res) => {
    const { username, password } = req.body;

    try {
        const admin = await User.findOne({ username, role: 'admin' });

        if (admin && (await admin.matchPassword(password))) {
            res.json({
                _id: admin._id,
                username: admin.username,
                role: admin.role,
                token: generateToken(admin._id),
            });
        } else {
            res.status(401).json({ message: 'Invalid credentials' });
        }
    } catch (error) {
        res.status(500).json({ message: 'Server Error' });
    }
};

// @desc    Get assignments for admin
// @route   GET /api/admins/assignments
// @access  Private (Admin)
exports.getAssignments = async (req, res) => {
    try {
        const assignments = await Assignment.find({ admin: req.user._id })
            .populate('user', 'username')
            .sort({ createdAt: -1 });
        res.json(assignments);
    } catch (error) {
        res.status(500).json({ message: 'Server Error' });
    }
};

// @desc    Accept an assignment
// @route   POST /api/admins/assignments/:id/accept
// @access  Private (Admin)
exports.acceptAssignment = async (req, res) => {
    try {
        const assignment = await Assignment.findById(req.params.id);

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

        if (assignment.admin.toString() !== req.user._id.toString()) {
            return res.status(403).json({ message: 'Not authorized to accept this assignment' });
        }

        assignment.status = 'accepted';
        await assignment.save();

        res.json({ message: 'Assignment accepted', assignment });
    } catch (error) {
        res.status(500).json({ message: 'Server Error' });
    }
};

// @desc    Reject an assignment
// @route   POST /api/admins/assignments/:id/reject
// @access  Private (Admin)
exports.rejectAssignment = async (req, res) => {
    try {
        const assignment = await Assignment.findById(req.params.id);

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

        if (assignment.admin.toString() !== req.user._id.toString()) {
            return res.status(403).json({ message: 'Not authorized to reject this assignment' });
        }

        assignment.status = 'rejected';
        await assignment.save();

        res.json({ message: 'Assignment rejected', assignment });
    } catch (error) {
        res.status(500).json({ message: 'Server Error' });
    }
};

// Helper function to generate token
const jwt = require('jsonwebtoken');

const generateToken = (id) => {
    return jwt.sign({ id }, process.env.JWT_SECRET, { expiresIn: '30d' });
};
8. Define Routes
a. User Routes

// routes/userRoutes.js
const express = require('express');
const router = express.Router();
const {
    registerUser,
    loginUser,
    uploadAssignment,
    getAllAdmins,
} = require('../controllers/userController');
const { protect, authorize } = require('../middleware/authMiddleware');

// Public routes
router.post('/register', registerUser);
router.post('/login', loginUser);

// Protected routes (User)
router.post('/upload', protect, authorize(['user']), uploadAssignment);
router.get('/admins', protect, authorize(['user']), getAllAdmins);

module.exports = router;
b. Admin Routes

// routes/adminRoutes.js
const express = require('express');
const router = express.Router();
const {
    registerAdmin,
    loginAdmin,
    getAssignments,
    acceptAssignment,
    rejectAssignment,
} = require('../controllers/adminController');
const { protect, authorize } = require('../middleware/authMiddleware');

// Public routes
router.post('/register', registerAdmin);
router.post('/login', loginAdmin);

// Protected routes (Admin)
router.get('/assignments', protect, authorize(['admin']), getAssignments);
router.post('/assignments/:id/accept', protect, authorize(['admin']), acceptAssignment);
router.post('/assignments/:id/reject', protect, authorize(['admin']), rejectAssignment);

module.exports = router;
9. Initialize Express App

// app.js
const express = require('express');
const dotenv = require('dotenv');
const connectDB = require('./config/db');
const userRoutes = require('./routes/userRoutes');
const adminRoutes = require('./routes/adminRoutes');
const errorHandler = require('./middleware/errorHandler');
const cors = require('cors');

dotenv.config();
connectDB();

const app = express();

// Middleware
app.use(cors());
app.use(express.json());

// Routes
app.use('/api/users', userRoutes);
app.use('/api/admins', adminRoutes);

// Error Handler
app.use(errorHandler);

module.exports = app;
10. Start the Server

// server.js
const app = require('./app');
const dotenv = require('dotenv');

dotenv.config();

const PORT = process.env.PORT || 5000;

app.listen(PORT, () => {
    console.log(`Server running on port ${PORT}`);
});
11. Update package.json Scripts

// package.json
{
  // ... other configurations
  "scripts": {
    "start": "node server.js",
    "dev": "nodemon server.js"
  },
  // ... other configurations
}
12. Validation (Optional but Recommended)
For robust input validation, consider using Joi or express-validator. Here's an example using express-validator.

a. Install express-validator

npm install express-validator
b. Update Routes with Validation

// routes/userRoutes.js
const { check, validationResult } = require('express-validator');

// Example for registration
router.post(
    '/register',
    [
        check('username', 'Username is required').not().isEmpty(),
        check('password', 'Password must be 6 or more characters').isLength({ min: 6 }),
    ],
    (req, res, next) => {
        const errors = validationResult(req);
        if (!errors.isEmpty()) {
            return res.status(400).json({ errors: errors.array() });
        }
        next();
    },
    registerUser
);

// Repeat similar validation for other endpoints
13. Documentation
Create a README.md with instructions on setting up and running the project.


# Assignment Submission Portal Backend

## Overview

This is a backend system for an assignment submission portal that allows users to upload assignments and admins to manage them.

## Features

- **Users:**
  - Register and login.
  - Upload assignments.
  - View available admins.

- **Admins:**
  - Register and login.
  - View assignments assigned to them.
  - Accept or reject assignments.

## Technologies

- **Node.js & Express:** Server and routing.
- **MongoDB & Mongoose:** Database and ORM.
- **JWT:** Authentication.
- **bcryptjs:** Password hashing.
- **express-validator:** Input validation.

## Setup Instructions

1. **Clone the Repository**

   ```bash
   git clone https://github.com/yourusername/assignment-portal.git
   cd assignment-portal
Install Dependencies

npm install
Configure Environment Variables Create a .env file in the root directory:

PORT=5000
MONGO_URI=your_mongodb_connection_string
JWT_SECRET=your_jwt_secret
Run the Server
For development with auto-restart:

npm run dev
For production:

npm start
API Endpoints
User Endpoints:
POST /api/users/register - Register a new user.
POST /api/users/login - User login.
POST /api/users/upload - Upload an assignment.
GET /api/users/admins - Fetch all admins.
Admin Endpoints:
POST /api/admins/register - Register a new admin.
POST /api/admins/login - Admin login.
GET /api/admins/assignments - View assignments tagged to the admin.
POST /api/admins/assignments/:id/accept - Accept an assignment.
POST /api/admins/assignments/:id/reject - Reject an assignment.
Notes
Ensure MongoDB is running and accessible via the connection string provided in .env.
Passwords are hashed using bcrypt before storing in the database.
JWT tokens are used for authenticating requests. Include the token in the Authorization header as Bearer <token>.
License
This project is licensed under the MIT License.



## **Final Notes**

- **Security:**
  - Always hash passwords before storing them.
  - Protect routes using authentication and authorization.
  - Validate all inputs to prevent injection attacks.

- **Error Handling:**
  - Centralize error handling to maintain clean controllers.
  - Provide meaningful error messages to the client.

- **Modularity:**
  - Separate concerns by organizing files into directories like `controllers`, `routes`, `models`, etc.
  - This makes the codebase easier to navigate and maintain.

- **Scalability:**
  - Using a single `User` model with roles (`user` and `admin`) simplifies user management.
  - Relationships between users and assignments are managed via MongoDB references.

- **Testing:**
  - Implement unit and integration tests to ensure the reliability of the backend.
  - Tools like Jest and Supertest can be useful for testing.

By following this structure and guidelines, you'll have a robust backend system for your assignment submission portal that is easy to maintain and scale as needed.

I have named server.js from app.js now
Error: Cannot find module 'C:\Node js programs\GrowthX\assignment-portal\app'
at Module._resolveFilename (node:internal/modules/cjs/loader:1145:15)
at Module._load (node:internal/modules/cjs/loader:986:27)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:174:12)
at node:internal/main/run_main_module:28:49 {
code: 'MODULE_NOT_FOUND',
requireStack: []
}

Node.js v20.13.1
Correct this error