diff --git a/components/Calendar.vue b/components/Calendar.vue
index b5e58c9c..909c95c4 100644
--- a/components/Calendar.vue
+++ b/components/Calendar.vue
@@ -26,7 +26,7 @@
diff --git a/components/CalendarEvent.vue b/components/CalendarEvent.vue
index b623340d..7d75ee01 100644
--- a/components/CalendarEvent.vue
+++ b/components/CalendarEvent.vue
@@ -1,10 +1,13 @@
- {{ event.getRange(range) }}
+ {{ event.getRange(year) }}
calendar.events.{{eventName}}
+
+
+
@@ -12,7 +15,8 @@
export default {
props: {
event: { required: true },
- range: {},
+ year: { 'default': () => (new Date).getFullYear() },
+ range: { type: Boolean },
},
computed: {
eventName() {
diff --git a/components/CalendarExtra.vue b/components/CalendarExtra.vue
index cf7c1739..91bb7219 100644
--- a/components/CalendarExtra.vue
+++ b/components/CalendarExtra.vue
@@ -25,9 +25,14 @@
iCalendar:
-
+
+
- ICS
+ crud.download
+ .ics
@@ -56,10 +61,29 @@
diff --git a/components/CalendarMonthEvents.vue b/components/CalendarMonthEvents.vue
index fcd6e878..d25e9cb3 100644
--- a/components/CalendarMonthEvents.vue
+++ b/components/CalendarMonthEvents.vue
@@ -1,7 +1,7 @@
diff --git a/components/LinkInput.vue b/components/LinkInput.vue
index e137fbcf..8b8938e1 100644
--- a/components/LinkInput.vue
+++ b/components/LinkInput.vue
@@ -1,7 +1,7 @@
diff --git a/server/routes/calendar.js b/server/routes/calendar.js
index 4b1d9c22..0a390b2b 100644
--- a/server/routes/calendar.js
+++ b/server/routes/calendar.js
@@ -8,26 +8,68 @@ import { clearLinkedText } from '../../src/helpers';
const translations = loadSuml('translations');
+const renderEvents = (yearEvents, res) => {
+ const events = [];
+ let i = 1;
+ for (let year in yearEvents) {
+ if (!yearEvents.hasOwnProperty(year)) { continue; }
+ for (let event of yearEvents[year]) {
+ if (!event) { continue; }
+ const ics = event.toIcs(year, translations, clearLinkedText, i);
+ if (ics !== null) {
+ events.push(ics);
+ }
+ }
+ i++;
+ }
+
+ if (events.length === 0) {
+ return res.status(404).json({error: 'Not found'});
+ }
+
+ createEvents(
+ events,
+ (error, value) => {
+ if (error) {
+ console.error(error);
+ return res.status(500).json({error: 'Unexpected server error'});
+ }
+
+ res.header('Content-type', 'text/calendar');
+ res.send(value);
+ }
+ );
+}
+
const router = Router();
-router.get('/calendar/queer-calendar-:year.ics', handleErrorAsync(async (req, res) => {
+const routeBase = `/queer-calendar-${global.config.locale}`;
+
+router.get(routeBase + '.ics', handleErrorAsync(async (req, res) => {
+ let events = {};
+ for (let year of calendar.getAllYears()) {
+ events[year.year] = year.events;
+ }
+
+ renderEvents(events, res);
+}));
+
+router.get(routeBase + '-:year-:uuid.ics', handleErrorAsync(async (req, res) => {
const year = calendar.getYear(req.params.year);
if (!year) {
return res.status(404).json({error: 'Not found'});
}
- const events = year.events
- .map(e => e.toIcs(req.params.year, translations, clearLinkedText))
- .filter(e => e !== null);
- createEvents(events, (error, value) => {
- if (error) {
- console.error(error);
- return res.status(500).json({error: 'Unexpected server error'});
- }
+ renderEvents({[year.year]: [year.eventsByUuid[req.params.uuid]]}, res)
+}));
- res.header('Content-type', 'text/calendar');
- res.send(value);
- })
+router.get(routeBase + '-:year.ics', handleErrorAsync(async (req, res) => {
+ const year = calendar.getYear(req.params.year);
+ if (!year) {
+ return res.status(404).json({error: 'Not found'});
+ }
+
+ renderEvents({[year.year]: year.events}, res)
}));
export default router;
diff --git a/src/calendar/helpers.js b/src/calendar/helpers.js
index e5e40acd..880229e8 100644
--- a/src/calendar/helpers.js
+++ b/src/calendar/helpers.js
@@ -1,4 +1,5 @@
const md5 = require("js-md5");
+const { v5: uuid5 } = require('uuid');
class Day {
constructor(year, month, day, dayOfWeek) {
@@ -104,7 +105,11 @@ module.exports.Event = class {
return this.getDays(day.year)[0].equals(day);
}
- toIcs(year, translations, clearLinkedText) {
+ getUuid() {
+ return uuid5(`${process.env.BASE_URL}/calendar/event/${this.name}`, uuid5.URL);
+ }
+
+ toIcs(year, translations, clearLinkedText, sequence = 1) {
const days = this.getDays(year);
const first = days[0];
const last = days[days.length - 1].next();
@@ -123,6 +128,7 @@ module.exports.Event = class {
start: [first.year, first.month, first.day],
end: [last.year, last.month, last.day],
calName: translations.calendar.headerLong,
+ sequence,
}
}
}
@@ -194,13 +200,20 @@ class Year {
for (let event of events) {
for (let term of event.terms) {
if (this.eventsByTerm[term] === undefined) { this.eventsByTerm[term] = []; }
- this.eventsByTerm[term].push(event);
+ if (event.getDays(this.year).length) {
+ this.eventsByTerm[term].push(event);
+ }
}
}
for (let term in this.eventsByTerm) {
if (!this.eventsByTerm.hasOwnProperty(term)) { continue; }
this.eventsByTerm[term].sort((a, b) => a.getDays(this.year)[0].toInt() - b.getDays(this.year)[0].toInt())
}
+
+ this.eventsByUuid = {}
+ for (let event of events) {
+ this.eventsByUuid[event.getUuid()] = event;
+ }
}
isCurrent() {