const express = require('express'); const router = express.Router(); const { CalendarUser } = require('../models'); const CalendarService = require('../services/CalendarService'); // Get all calendar users router.get('/users', async (req, res) => { try { const users = await CalendarUser.findAll({ where: { isActive: true }, attributes: ['id', 'name', 'nextcloudUrl', 'username', 'calendarName', 'isActive'] }); res.json(users); } catch (error) { console.error('Error fetching calendar users:', error); res.status(500).json({ error: 'Failed to fetch calendar users' }); } }); // Add a new calendar user router.post('/users', async (req, res) => { try { const { name, nextcloudUrl, username, password, calendarName } = req.body; if (!name || !nextcloudUrl || !username || !password) { return res.status(400).json({ error: 'Missing required fields: name, nextcloudUrl, username, password' }); } // Test connection before saving const testConfig = { name, nextcloudUrl, username, password, calendarName }; const connectionTest = await CalendarService.testConnection(testConfig); if (!connectionTest) { return res.status(400).json({ error: 'Failed to connect to Nextcloud instance. Please check your credentials.' }); } const user = await CalendarUser.create({ name, nextcloudUrl, username, password, calendarName }); // Return user without password const { password: _, ...userWithoutPassword } = user.toJSON(); res.status(201).json(userWithoutPassword); } catch (error) { console.error('Error creating calendar user:', error); if (error.name === 'SequelizeUniqueConstraintError') { res.status(400).json({ error: 'User name already exists' }); } else { res.status(500).json({ error: 'Failed to create calendar user' }); } } }); // Update a calendar user router.put('/users/:id', async (req, res) => { try { const { id } = req.params; const { name, nextcloudUrl, username, password, calendarName, isActive } = req.body; const user = await CalendarUser.findByPk(id); if (!user) { return res.status(404).json({ error: 'Calendar user not found' }); } // Test connection if credentials are being updated if (nextcloudUrl || username || password) { const testConfig = { name: name || user.name, nextcloudUrl: nextcloudUrl || user.nextcloudUrl, username: username || user.username, password: password || user.password, calendarName: calendarName || user.calendarName }; const connectionTest = await CalendarService.testConnection(testConfig); if (!connectionTest) { return res.status(400).json({ error: 'Failed to connect to Nextcloud instance. Please check your credentials.' }); } } await user.update({ ...(name && { name }), ...(nextcloudUrl && { nextcloudUrl }), ...(username && { username }), ...(password && { password }), ...(calendarName !== undefined && { calendarName }), ...(isActive !== undefined && { isActive }) }); // Return user without password const { password: _, ...userWithoutPassword } = user.toJSON(); res.json(userWithoutPassword); } catch (error) { console.error('Error updating calendar user:', error); res.status(500).json({ error: 'Failed to update calendar user' }); } }); // Delete a calendar user router.delete('/users/:id', async (req, res) => { try { const { id } = req.params; const user = await CalendarUser.findByPk(id); if (!user) { return res.status(404).json({ error: 'Calendar user not found' }); } await user.destroy(); res.json({ message: 'Calendar user deleted successfully' }); } catch (error) { console.error('Error deleting calendar user:', error); res.status(500).json({ error: 'Failed to delete calendar user' }); } }); // Get calendar events for a specific month // GET /api/calendar/events/:year/:month?user=username&type=family|individual router.get('/events/:year/:month', async (req, res) => { try { const { year, month } = req.params; const { user, type } = req.query; // Validate year and month if (!year || !month || !/^\d{4}$/.test(year) || !/^(0[1-9]|1[0-2])$/.test(month)) { return res.status(400).json({ error: 'Invalid year or month format. Use YYYY for year and MM for month.' }); } if (type === 'family') { // Get events from all active users const users = await CalendarUser.findAll({ where: { isActive: true }, attributes: ['name', 'nextcloudUrl', 'username', 'password', 'calendarName'] }); if (users.length === 0) { return res.json([]); } const events = await CalendarService.getFamilyEventsForMonth(users, year, month); res.json(events); } else { // Get events for a specific user if (!user) { return res.status(400).json({ error: 'User parameter required for individual calendar view' }); } const userConfig = await CalendarUser.findOne({ where: { name: user, isActive: true }, attributes: ['name', 'nextcloudUrl', 'username', 'password', 'calendarName'] }); if (!userConfig) { return res.status(404).json({ error: 'User not found or inactive' }); } const events = await CalendarService.getEventsForMonth(userConfig, year, month); res.json(events); } } catch (error) { console.error('Error retrieving calendar events:', error.message); res.status(500).json({ error: 'Failed to retrieve calendar events' }); } }); // Create a new calendar event // POST /api/calendar/events router.post('/events', async (req, res) => { try { const { user, date, text } = req.body; if (!user || !date || !text) { return res.status(400).json({ error: 'Missing required fields: user, date, text' }); } // Validate date format (YYYY-MM-DD) if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) { return res.status(400).json({ error: 'Invalid date format. Use YYYY-MM-DD.' }); } const userConfig = await CalendarUser.findOne({ where: { name: user, isActive: true }, attributes: ['name', 'nextcloudUrl', 'username', 'password', 'calendarName'] }); if (!userConfig) { return res.status(404).json({ error: 'User not found or inactive' }); } const event = await CalendarService.createEvent(userConfig, date, text); res.status(201).json(event); } catch (error) { console.error('Error creating calendar event:', error.message); res.status(500).json({ error: 'Failed to create calendar event' }); } }); // Update a calendar event // PUT /api/calendar/events/:eventId router.put('/events/:eventId', async (req, res) => { try { const { eventId } = req.params; const { user, date, text } = req.body; if (!user || !date || !text) { return res.status(400).json({ error: 'Missing required fields: user, date, text' }); } // Validate date format (YYYY-MM-DD) if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) { return res.status(400).json({ error: 'Invalid date format. Use YYYY-MM-DD.' }); } const userConfig = await CalendarUser.findOne({ where: { name: user, isActive: true }, attributes: ['name', 'nextcloudUrl', 'username', 'password', 'calendarName'] }); if (!userConfig) { return res.status(404).json({ error: 'User not found or inactive' }); } const event = await CalendarService.updateEvent(userConfig, eventId, date, text); res.json(event); } catch (error) { console.error('Error updating calendar event:', error); if (error.message === 'Event not found') { res.status(404).json({ error: 'Event not found' }); } else if (error.message.includes('Permission denied')) { res.status(403).json({ error: error.message }); } else { res.status(500).json({ error: 'Failed to update calendar event' }); } } }); // Delete a calendar event // DELETE /api/calendar/events/:eventId router.delete('/events/:eventId', async (req, res) => { try { const { eventId } = req.params; const { user } = req.body; if (!user) { return res.status(400).json({ error: 'Missing required field: user' }); } const userConfig = await CalendarUser.findOne({ where: { name: user, isActive: true }, attributes: ['name', 'nextcloudUrl', 'username', 'password', 'calendarName'] }); if (!userConfig) { return res.status(404).json({ error: 'User not found or inactive' }); } await CalendarService.deleteEvent(userConfig, eventId); res.json({ message: 'Event deleted successfully' }); } catch (error) { console.error('Error deleting calendar event:', error); if (error.message === 'Event not found') { res.status(404).json({ error: 'Event not found' }); } else if (error.message.includes('Permission denied')) { res.status(403).json({ error: error.message }); } else { res.status(500).json({ error: 'Failed to delete calendar event' }); } } }); // Test Nextcloud connection for a user router.post('/users/:id/test-connection', async (req, res) => { try { const { id } = req.params; const user = await CalendarUser.findByPk(id); if (!user) { return res.status(404).json({ error: 'Calendar user not found' }); } const connectionTest = await CalendarService.testConnection({ name: user.name, nextcloudUrl: user.nextcloudUrl, username: user.username, password: user.password, calendarName: user.calendarName }); res.json({ success: connectionTest, message: connectionTest ? 'Connection successful' : 'Connection failed' }); } catch (error) { console.error('Error testing connection:', error); res.status(500).json({ error: 'Failed to test connection' }); } }); module.exports = router;