Add birthday support for mobile calendar
This commit is contained in:
@@ -149,7 +149,10 @@ router.get('/events/:year/:month', async (req, res) => {
|
||||
return res.json([]);
|
||||
}
|
||||
|
||||
const events = await CalendarService.getFamilyEventsForMonth(users, year, month);
|
||||
// Convert Sequelize instances to plain objects
|
||||
const userConfigs = users.map(user => user.toJSON());
|
||||
|
||||
const events = await CalendarService.getFamilyEventsForMonth(userConfigs, year, month);
|
||||
res.json(events);
|
||||
} else {
|
||||
// Get events for a specific user
|
||||
@@ -168,8 +171,31 @@ router.get('/events/:year/:month', async (req, res) => {
|
||||
return res.status(404).json({ error: 'User not found or inactive' });
|
||||
}
|
||||
|
||||
const events = await CalendarService.getEventsForMonth(userConfig, year, month);
|
||||
res.json(events);
|
||||
// Convert Sequelize instance to plain object
|
||||
const userConfigPlain = userConfig.toJSON();
|
||||
|
||||
const events = await CalendarService.getEventsForMonth(userConfigPlain, year, month);
|
||||
const birthdayEvents = await CalendarService.getContactBirthdaysForMonth(userConfigPlain, year, month);
|
||||
|
||||
// Combine regular events and birthday events
|
||||
const allEvents = [...events, ...birthdayEvents];
|
||||
|
||||
// Sort events by date string first (YYYY-MM-DD format) - this ensures proper chronological ordering
|
||||
allEvents.sort((a, b) => {
|
||||
// First, compare dates as strings to avoid timezone issues
|
||||
if (a.date !== b.date) {
|
||||
return a.date.localeCompare(b.date);
|
||||
}
|
||||
|
||||
// If dates are the same, sort by type (birthdays first)
|
||||
if (a.type === 'birthday' && b.type !== 'birthday') return -1;
|
||||
if (a.type !== 'birthday' && b.type === 'birthday') return 1;
|
||||
|
||||
// Then sort by event text for consistent ordering
|
||||
return (a.text || '').localeCompare(b.text || '');
|
||||
});
|
||||
|
||||
res.json(allEvents);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error retrieving calendar events:', error.message);
|
||||
@@ -205,7 +231,7 @@ router.post('/events', async (req, res) => {
|
||||
return res.status(404).json({ error: 'User not found or inactive' });
|
||||
}
|
||||
|
||||
const event = await CalendarService.createEvent(userConfig, date, text);
|
||||
const event = await CalendarService.createEvent(userConfig.toJSON(), date, text);
|
||||
res.status(201).json(event);
|
||||
} catch (error) {
|
||||
console.error('Error creating calendar event:', error.message);
|
||||
@@ -242,14 +268,18 @@ router.put('/events/:eventId', async (req, res) => {
|
||||
return res.status(404).json({ error: 'User not found or inactive' });
|
||||
}
|
||||
|
||||
const event = await CalendarService.updateEvent(userConfig, eventId, date, text);
|
||||
const event = await CalendarService.updateEvent(userConfig.toJSON(), 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('You can only edit events that belong to you')) {
|
||||
res.status(403).json({ error: 'You can only edit events that belong to you' });
|
||||
} else if (error.message.includes('Permission denied')) {
|
||||
res.status(403).json({ error: error.message });
|
||||
} else if (error.message.includes('CalDAV authentication failed')) {
|
||||
res.status(401).json({ error: 'Calendar authentication failed' });
|
||||
} else {
|
||||
res.status(500).json({ error: 'Failed to update calendar event' });
|
||||
}
|
||||
@@ -269,6 +299,13 @@ router.delete('/events/:eventId', async (req, res) => {
|
||||
});
|
||||
}
|
||||
|
||||
// Check if this is a birthday event (birthday events should not be deletable)
|
||||
if (eventId && eventId.includes('birthday-')) {
|
||||
return res.status(403).json({
|
||||
error: 'Birthday events cannot be deleted from the calendar interface'
|
||||
});
|
||||
}
|
||||
|
||||
const userConfig = await CalendarUser.findOne({
|
||||
where: { name: user, isActive: true },
|
||||
attributes: ['name', 'nextcloudUrl', 'username', 'password', 'calendarName']
|
||||
@@ -278,14 +315,20 @@ router.delete('/events/:eventId', async (req, res) => {
|
||||
return res.status(404).json({ error: 'User not found or inactive' });
|
||||
}
|
||||
|
||||
await CalendarService.deleteEvent(userConfig, eventId);
|
||||
await CalendarService.deleteEvent(userConfig.toJSON(), 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(404).json({
|
||||
error: 'Event not found. This event may belong to a different user or have already been deleted.'
|
||||
});
|
||||
} else if (error.message.includes('You can only delete events that belong to you')) {
|
||||
res.status(403).json({ error: 'You can only delete events that belong to you' });
|
||||
} else if (error.message === 'Birthday events cannot be deleted from the calendar interface') {
|
||||
res.status(403).json({ error: error.message });
|
||||
} else if (error.message.includes('Permission denied') || error.message.includes('authentication failed')) {
|
||||
res.status(403).json({ error: 'Permission denied. You may not have access to delete this event.' });
|
||||
} else {
|
||||
res.status(500).json({ error: 'Failed to delete calendar event' });
|
||||
}
|
||||
@@ -320,4 +363,41 @@ router.post('/users/:id/test-connection', async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Get contact birthdays for a specific month
|
||||
// GET /api/calendar/birthdays/:year/:month?user=username
|
||||
router.get('/birthdays/:year/:month', async (req, res) => {
|
||||
try {
|
||||
const { year, month } = req.params;
|
||||
const { user } = 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 (!user) {
|
||||
return res.status(400).json({
|
||||
error: 'User parameter required for birthday calendar access'
|
||||
});
|
||||
}
|
||||
|
||||
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 birthdayEvents = await CalendarService.getContactBirthdaysForMonth(userConfig.toJSON(), year, month);
|
||||
res.json(birthdayEvents);
|
||||
} catch (error) {
|
||||
console.error('Error retrieving contact birthdays:', error.message);
|
||||
res.status(500).json({ error: 'Failed to retrieve contact birthdays' });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
Reference in New Issue
Block a user