Spaces:
Running
Running
| ```javascript | |
| require('dotenv').config(); | |
| const express = require('express'); | |
| const mongoose = require('mongoose'); | |
| const jwt = require('jsonwebtoken'); | |
| const bcrypt = require('bcryptjs'); | |
| const cors = require('cors'); | |
| const { v4: uuidv4 } = require('uuid'); | |
| const rateLimit = require('express-rate-limit'); | |
| const app = express(); | |
| // Middleware | |
| app.use(cors()); | |
| app.use(express.json()); | |
| // Rate limiting | |
| const limiter = rateLimit({ | |
| windowMs: 15 * 60 * 1000, // 15 minutes | |
| max: 100 // limit each IP to 100 requests per windowMs | |
| }); | |
| app.use('/api/', limiter); | |
| // Database connection | |
| mongoose.connect(process.env.MONGODB_URI, { | |
| useNewUrlParser: true, | |
| useUnifiedTopology: true | |
| }) | |
| .then(() => console.log('Connected to MongoDB')) | |
| .catch(err => console.error('MongoDB connection error:', err)); | |
| // Models | |
| const User = mongoose.model('User', new mongoose.Schema({ | |
| username: { type: String, required: true, unique: true }, | |
| password: { type: String, required: true }, | |
| role: { type: String, default: 'user' }, | |
| apiKey: { type: String, default: uuidv4 } | |
| })); | |
| const Conversation = mongoose.model('Conversation', new mongoose.Schema({ | |
| userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }, | |
| messages: [{ | |
| content: String, | |
| sender: { type: String, enum: ['user', 'ai'] }, | |
| timestamp: { type: Date, default: Date.now } | |
| }], | |
| status: { type: String, enum: ['active', 'resolved'], default: 'active' }, | |
| createdAt: { type: Date, default: Date.now } | |
| })); | |
| const Lead = mongoose.model('Lead', new mongoose.Schema({ | |
| name: String, | |
| email: { type: String, required: true, unique: true }, | |
| phone: String, | |
| status: { type: String, enum: ['new', 'contacted', 'qualified', 'converted'], default: 'new' }, | |
| source: String, | |
| notes: String, | |
| createdAt: { type: Date, default: Date.now } | |
| })); | |
| // Authentication middleware | |
| const authenticate = (req, res, next) => { | |
| const token = req.header('Authorization')?.replace('Bearer ', ''); | |
| if (!token) return res.status(401).send('Access denied'); | |
| try { | |
| const verified = jwt.verify(token, process.env.JWT_SECRET); | |
| req.user = verified; | |
| next(); | |
| } catch (err) { | |
| res.status(400).send('Invalid token'); | |
| } | |
| }; | |
| // Routes | |
| // Auth routes | |
| app.post('/api/auth/register', async (req, res) => { | |
| try { | |
| const { username, password } = req.body; | |
| const hashedPassword = await bcrypt.hash(password, 10); | |
| const user = new User({ username, password: hashedPassword }); | |
| await user.save(); | |
| res.status(201).send({ message: 'User created successfully' }); | |
| } catch (err) { | |
| res.status(400).send(err.message); | |
| } | |
| }); | |
| app.post('/api/auth/login', async (req, res) => { | |
| try { | |
| const { username, password } = req.body; | |
| const user = await User.findOne({ username }); | |
| if (!user) return res.status(400).send('Invalid credentials'); | |
| const validPass = await bcrypt.compare(password, user.password); | |
| if (!validPass) return res.status(400).send('Invalid credentials'); | |
| const token = jwt.sign({ _id: user._id, role: user.role }, process.env.JWT_SECRET, { expiresIn: '1h' }); | |
| res.send({ token, apiKey: user.apiKey }); | |
| } catch (err) { | |
| res.status(400).send(err.message); | |
| } | |
| }); | |
| // Conversation routes | |
| app.get('/api/conversations', authenticate, async (req, res) => { | |
| try { | |
| const conversations = await Conversation.find({ userId: req.user._id }).sort({ createdAt: -1 }); | |
| res.send(conversations); | |
| } catch (err) { | |
| res.status(400).send(err.message); | |
| } | |
| }); | |
| app.post('/api/conversations', authenticate, async (req, res) => { | |
| try { | |
| const conversation = new Conversation({ userId: req.user._id }); | |
| await conversation.save(); | |
| res.status(201).send(conversation); | |
| } catch (err) { | |
| res.status(400).send(err.message); | |
| } | |
| }); | |
| app.post('/api/conversations/:id/messages', authenticate, async (req, res) => { | |
| try { | |
| const conversation = await Conversation.findOne({ | |
| _id: req.params.id, | |
| userId: req.user._id | |
| }); | |
| if (!conversation) return res.status(404).send('Conversation not found'); | |
| // Process AI response (simplified for demo) | |
| const aiResponse = { | |
| content: `AI response to: "${req.body.content}". This is a simulated response.`, | |
| sender: 'ai' | |
| }; | |
| conversation.messages.push({ | |
| content: req.body.content, | |
| sender: 'user' | |
| }); | |
| conversation.messages.push(aiResponse); | |
| await conversation.save(); | |
| res.send(conversation); | |
| } catch (err) { | |
| res.status(400).send(err.message); | |
| } | |
| }); | |
| // Lead routes | |
| app.get('/api/leads', authenticate, async (req, res) => { | |
| try { | |
| const leads = await Lead.find().sort({ createdAt: -1 }); | |
| res.send(leads); | |
| } catch (err) { | |
| res.status(400).send(err.message); | |
| } | |
| }); | |
| app.post('/api/leads', authenticate, async (req, res) => { | |
| try { | |
| const lead = new Lead(req.body); | |
| await lead.save(); | |
| res.status(201).send(lead); | |
| } catch (err) { | |
| res.status(400).send(err.message); | |
| } | |
| }); | |
| app.put('/api/leads/:id', authenticate, async (req, res) => { | |
| try { | |
| const lead = await Lead.findByIdAndUpdate(req.params.id, req.body, { new: true }); | |
| if (!lead) return res.status(404).send('Lead not found'); | |
| res.send(lead); | |
| } catch (err) { | |
| res.status(400).send(err.message); | |
| } | |
| }); | |
| // API Key authentication | |
| app.post('/api/ai/process', async (req, res) => { | |
| try { | |
| const apiKey = req.header('X-API-Key'); | |
| if (!apiKey) return res.status(401).send('API key required'); | |
| const user = await User.findOne({ apiKey }); | |
| if (!user) return res.status(401).send('Invalid API key'); | |
| // Process AI request (simplified for demo) | |
| const response = { | |
| id: uuidv4(), | |
| content: `AI processed: "${req.body.content}". This is a simulated response.`, | |
| timestamp: new Date() | |
| }; | |
| res.send(response); | |
| } catch (err) { | |
| res.status(400).send(err.message); | |
| } | |
| }); | |
| // Start server | |
| const PORT = process.env.PORT || 5000; | |
| app.listen(PORT, () => console.log(`Server running on port ${PORT}`)); | |
| ``` |