-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathserver.js
More file actions
128 lines (108 loc) · 3.43 KB
/
server.js
File metadata and controls
128 lines (108 loc) · 3.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
const express = require('express');
const path = require('path');
const fs = require('fs').promises;
const matter = require('gray-matter');
const app = express();
const PORT = process.env.PORT || 3000;
// Set Pug as templating engine
app.set('view engine', 'pug');
app.set('views', path.join(__dirname, 'views'));
// Serve static files
app.use(express.static(path.join(__dirname, 'public')));
// Routes
app.get('/', (req, res) => {
res.render('index', { activePage: 'Home' });
});
app.get('/events', (req, res) => {
res.render('events', { activePage: 'Events' });
});
app.get('/contact', (req, res) => {
res.render('contact', { activePage: 'Visiting / Contact' });
});
app.get('/event-list', (req, res) => {
res.render('event-list');
});
// Shared function to parse all events
async function getAllEvents() {
const eventsDir = path.join(__dirname, 'events');
const files = await fs.readdir(eventsDir, { recursive: true });
const mdFiles = files.filter(file =>
file.endsWith('.md') && file.toLowerCase() !== 'readme.md'
);
const events = [];
for (const file of mdFiles) {
const filePath = path.join(eventsDir, file);
const fileContent = await fs.readFile(filePath, 'utf8');
const { data, content } = matter(fileContent);
// weekly-social.md has no date — handled separately below
if (file.replace(/\\/g, '/') === 'weekly-social.md') {
continue;
}
if (!data.title || !data.date) {
console.warn(`Skipping ${file}: missing required fields (title, date)`);
continue;
}
events.push({
title: data.title,
date: data.date,
end: data.end || null,
description: content.trim(),
uid: `md-${file.replace('.md', '').replace(/\\/g, '/')}`,
source: 'markdown'
});
}
// Weekly social — always shows as next Thursday
const weeklySocialPath = path.join(eventsDir, 'weekly-social.md');
try {
const wsContent = await fs.readFile(weeklySocialPath, 'utf8');
const { data: wsData, content: wsBody } = matter(wsContent);
const now = new Date();
const nextThursday = new Date(now);
nextThursday.setDate(now.getDate() + ((4 - now.getDay() + 7) % 7 || 7));
nextThursday.setHours(20, 0, 0, 0); // 20:00 UTC = 21:00 CET
events.push({
title: wsData.title || 'Weekly Social',
date: nextThursday.toISOString(),
end: null,
description: wsBody.trim(),
uid: 'weekly-social-next',
source: 'markdown'
});
} catch (e) {
// weekly-social.md missing, skip
}
return events;
}
// Individual event page
app.get('/events/:eventId(*)', async (req, res) => {
try {
const rawId = req.params.eventId;
const events = await getAllEvents();
const event = events.find(e => e.uid === `md-${rawId}` || e.uid === rawId);
if (!event) {
return res.redirect('/events');
}
res.render('event-detail', {
activePage: 'Events',
event: event,
eventPath: req.params.eventId
});
} catch (error) {
console.error('Error loading event:', error);
res.redirect('/events');
}
});
// API endpoint for events
app.get('/api/events.json', async (req, res) => {
try {
const events = await getAllEvents();
res.json(events);
} catch (error) {
console.error('Error reading markdown events:', error);
res.status(500).json({ error: 'Failed to load markdown events' });
}
});
// Start server
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});