const express = require('express'); const argon2 = require('argon2'); const { initDb, getAllArticles, getArticle, createArticle, updateArticle, deleteArticle, searchArticles, createUser, getUserByUsername, getUserByEmail } = require('./db'); const { generateToken, authenticateToken } = require('./auth'); const app = express(); const cors = require('cors'); const PORT = 9000; app.use(cors()) app.use(express.json()); initDb().then(() => { app.get('/', (req, res) => { res.json({message : 'Server is running'}); }); app.get('/api/articles', authenticateToken, (req, res) => { try { const articles = getAllArticles(); res.json(articles); } catch (error) { console.error('Error fetching articles:', error); res.status(500).json({error: 'Failed to fetch articles', 'details': String(error)}); } }); app.get('/api/articles/:ka_number', authenticateToken, (req, res) => { try { const article = getArticle(req.params.ka_number); if (!article) { return res.status(404).json({ error: 'Article not found' }); } res.json(article); } catch (error) { console.error('Error fetching article:', error); res.status(500).json({error: 'Failed to fetch article', 'details': String(error)}); } }); app.post('/api/articles', authenticateToken, (req, res) => { try { const { title, content } = req.body; if (!title) { return res.status(400).json({error: 'Title is required' }); } const article = createArticle(title, content, req.user.display_name); res.status(201).json(article); } catch (error) { console.error('Error creating article:', error); res.status(500).json({error: 'Failed to create article', 'details': String(error)}); } }); app.put('/api/articles/:ka_number', authenticateToken, (req, res) => { try { const { title, content } = req.body; if (!title) { return res.status(400).json({error: 'Title is required' }); } const article = updateArticle(req.params.ka_number, title, content, req.user.display_name); if (!article) { return res.status(404).json({error: 'Article not found'}); } res.json(article); } catch (error) { console.error('Error updating article:', error); return res.status(500).json({error: 'Error while updating article', 'details': String(error)}); } }); app.delete('/api/articles/:ka_number', authenticateToken, (req, res) => { try { deleteArticle(req.params.ka_number); return res.status(200).json({'message': 'Successfully deleted article'}); } catch (error) { console.error('Error when deleting article:', error); return res.status(500).json({error: 'Failed to delete article', 'details': String(error)}); } }); app.get('/api/search', authenticateToken, (req, res) => { try { const query = req.query.q; if (!query) { return res.status(400).json({error: 'Search query is required'}); } const results = searchArticles(query); res.json(results); } catch (error) { console.error('Error when searching articles:', error); return res.status(500).json({error: 'Failed to search articles', 'details': String(error)}); } }); app.post('/api/auth/register', async (req, res) => { try { const {username, email, password, displayName} = req.body; if (!username || !email || !password || !displayName) { return res.status(400).json({error: 'Username, email, password, and display name are required'}); } const cur_user_username = getUserByUsername(username); if (cur_user_username) { return res.status(400).json({error: 'Username already exists'}); } const cur_user_email = getUserByEmail(email); if(cur_user_email) { return res.status(400).json({error: 'email address already in use'}); } const pass_hash = await argon2.hash(password); const newUser = createUser(username, email, pass_hash, displayName); const token = generateToken(newUser); return res.status(201).json({ user: { id: newUser.id, username: newUser.username, email: newUser.email, display_name: newUser.display_name, auth_provider: newUser.auth_provider, created_at: newUser.created_at }, token }); } catch (error) { console.error('Error when registering new user: ', error); return res.status(500).json({error: 'Failed to create user', 'details': String(error)}); } }); app.post('/api/auth/login', async (req, res) => { try { const {username, email, password} = req.body; if (!password || (!username && !email)) { return res.status(400).json({error: 'Username/email & password are required'}); } let user; if (!username) { user = getUserByEmail(email); } else { user = getUserByUsername(username); } if (!user || !await argon2.verify(user.pass_hash, password)) { return res.status(401).json({error: 'Invalid credentials'}); } const token = generateToken(user); return res.status(200).json({ user: { id: user.id, username: user.username, email: user.email, display_name: user.display_name, auth_provider: user.auth_provider, created_at: user.created_at }, token }); } catch (error) { console.log('Failed to log user in:', error); return res.status(500).json({error: 'Failed to login', 'details': String(error)}); } }); app.listen(PORT, () => { console.log(`Server running on http://localhost:${PORT}`); }); }).catch(err => { console.error('Failed to initialize database:', err); });