DocuCenter/backend/app.js

210 lines
6.1 KiB
JavaScript
Raw Normal View History

2024-12-10 16:32:44 -07:00
// Required modules
const express = require('express');
const { MongoClient, ObjectId } = require('mongodb');
const cors = require('cors');
// Set up express app
const app = express();
const port = process.env.PORT || 3000;
// Parse JSON bodies
app.use(express.json({ limit: '50mb' })); // For JSON data
app.use(express.urlencoded({ limit: '50mb', extended: true })); // For URL-encoded data
// Enabling CORS globally
app.use(cors());
// MongoDB configuration
const mongoUri = 'mongodb://localhost:27017'; // Replace with your MongoDB URI
const dbName = 'docucenter';
let db;
// Connect to MongoDB
MongoClient.connect(mongoUri, { useNewUrlParser: true, useUnifiedTopology: true })
.then(client => {
db = client.db(dbName);
console.log(`Connected to database: ${dbName}`);
})
.catch(err => {
console.error('Failed to connect to MongoDB:', err);
process.exit(1);
});
// Middleware to handle errors
app.use((err, req, res, next) => {
console.error(err);
res.status(500).json({ error: 'Something went wrong!' });
});
// CRUD Routes
// Create a new document
app.post('/documents', async (req, res) => {
const { title, body, tags } = req.body;
// Validate input
if (!title || !body) {
return res.status(400).json({ error: 'Title and body are required' });
}
if (!Array.isArray(tags)) {
return res.status(400).json({ error: 'Tags must be an array' });
}
try {
// Insert the document into the database
const result = await db.collection('documents').insertOne({
title,
body,
tags,
created_at: new Date()
});
// Respond with success
res.status(201).json({ message: 'Document created', id: result.insertedId });
} catch (err) {
console.error('Error saving document:', err);
res.status(500).json({ error: 'Failed to save document' });
}
});
// Get all documents
app.get('/documents', async (req, res) => {
try {
const documents = await db.collection('documents').find().toArray();
// Process each result
const cleanedResults = documents.map(result => {
// Remove <img> tags from the body field
let cleanedBody = result.body.replace(/<img[^>]*>/g, '');
return { ...result, body: cleanedBody };
});
res.json(cleanedResults);
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Failed to retrieve documents' });
}
});
// Get a document by ID
app.get('/documents/:id', async (req, res) => {
const { id } = req.params;
try {
const document = await db.collection('documents').findOne({ _id: new ObjectId(id) });
if (!document) {
return res.status(404).json({ error: 'Document not found' });
}
res.json(document);
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Failed to retrieve document' });
}
});
// Update a document
app.put('/documents/:id', async (req, res) => {
const { id } = req.params;
const { title, body } = req.body;
if (!title || !body) {
return res.status(400).json({ error: 'Title and body are required' });
}
try {
const result = await db.collection('documents').updateOne(
{ _id: new ObjectId(id) },
{ $set: { title, body, updated_at: new Date() } }
);
if (result.matchedCount === 0) {
return res.status(404).json({ error: 'Document not found' });
}
res.json({ message: 'Document updated' });
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Failed to update document' });
}
});
// Delete a document
app.delete('/documents/:id', async (req, res) => {
const { id } = req.params;
try {
const result = await db.collection('documents').deleteOne({ _id: new ObjectId(id) });
if (result.deletedCount === 0) {
return res.status(404).json({ error: 'Document not found' });
}
res.json({ message: 'Document deleted' });
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Failed to delete document' });
}
});
app.get('/search', async (req, res) => {
const { query } = req.query;
if (!query) {
return res.status(400).send('Query parameter is required');
}
try {
// Case-insensitive search using regular expressions
const results = await db.collection('documents').find({
$or: [
{ title: { $regex: query, $options: 'i' } }, // Search in title
{ body: { $regex: query, $options: 'i' } }, // Search in body
{ tags: { $regex: query, $options: 'i' } } // Search in tags (exact match)
]
}).toArray(); // Convert cursor to array
// Process each result
const cleanedResults = results.map(result => {
// Remove <img> tags from the body field
let cleanedBody = result.body.replace(/<img[^>]*>/g, '');
// Surround query matches in the body with <span style="background: yellow;">
const bodyRegex = new RegExp(query, 'gi'); // 'gi' for case-insensitive matching globally
cleanedBody = cleanedBody.replace(bodyRegex, match => {
return `<span style="background: yellow;">${match}</span>`;
});
// Highlight the title if it matches the query
let cleanedTitle = result.title;
const titleRegex = new RegExp(query, 'gi'); // 'gi' for case-insensitive matching globally
cleanedTitle = cleanedTitle.replace(titleRegex, match => {
return `<span style="background: yellow;">${match}</span>`;
});
// Highlight query matches in tags (tags is an array)
const cleanedTags = result.tags.map(tag => {
const tagRegex = new RegExp(query, 'gi');
return tag.replace(tagRegex, match => {
return `<span style="background: yellow; color: black;">${match}</span>`;
});
});
// Return the updated result with highlighted title, body, and tags
return { ...result, title: cleanedTitle, body: cleanedBody, tags: cleanedTags };
});
res.json(cleanedResults);
} catch (error) {
console.error('Error performing search:', error);
res.status(500).send('Server error');
}
});
// Handle invalid routes (404)
app.use((req, res) => {
res.status(404).json({ error: 'Route not found' });
});
// Start the server
app.listen(port, () => {
console.log(`Server running on http://localhost:${port}`);
});