From 0b686f799a13ed7fa4a8561a09008c0edf2a13ec Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 21 Feb 2022 11:08:48 +0000 Subject: [PATCH 01/24] Support for icalendar format --- daemon.py | 53 +++++++- epicyon-calendar.css | 15 ++ happening.py | 188 ++++++++++++++++++++++++-- theme/blue/icons/ical.png | Bin 0 -> 7210 bytes theme/debian/icons/ical.png | Bin 0 -> 7210 bytes theme/default/icons/ical.png | Bin 0 -> 7210 bytes theme/hacker/icons/ical.png | Bin 0 -> 9502 bytes theme/henge/icons/ical.png | Bin 0 -> 9190 bytes theme/indymediaclassic/icons/ical.png | Bin 0 -> 11140 bytes theme/indymediamodern/icons/ical.png | Bin 0 -> 9391 bytes theme/lcd/icons/ical.png | Bin 0 -> 8650 bytes theme/light/icons/ical.png | Bin 0 -> 9391 bytes theme/night/icons/ical.png | Bin 0 -> 7210 bytes theme/pixel/icons/ical.png | Bin 0 -> 10661 bytes theme/purple/icons/ical.png | Bin 0 -> 11258 bytes theme/rc3/icons/ical.png | Bin 0 -> 12028 bytes theme/solidaric/icons/ical.png | Bin 0 -> 9548 bytes theme/starlight/icons/ical.png | Bin 0 -> 11627 bytes theme/zen/icons/ical.png | Bin 0 -> 11550 bytes webapp_calendar.py | 27 +++- 20 files changed, 270 insertions(+), 13 deletions(-) create mode 100644 theme/blue/icons/ical.png create mode 100644 theme/debian/icons/ical.png create mode 100644 theme/default/icons/ical.png create mode 100644 theme/hacker/icons/ical.png create mode 100644 theme/henge/icons/ical.png create mode 100644 theme/indymediaclassic/icons/ical.png create mode 100644 theme/indymediamodern/icons/ical.png create mode 100644 theme/lcd/icons/ical.png create mode 100644 theme/light/icons/ical.png create mode 100644 theme/night/icons/ical.png create mode 100644 theme/pixel/icons/ical.png create mode 100644 theme/purple/icons/ical.png create mode 100644 theme/rc3/icons/ical.png create mode 100644 theme/solidaric/icons/ical.png create mode 100644 theme/starlight/icons/ical.png create mode 100644 theme/zen/icons/ical.png diff --git a/daemon.py b/daemon.py index 33b497c4f..6baf527d7 100644 --- a/daemon.py +++ b/daemon.py @@ -679,6 +679,16 @@ class PubServer(BaseHTTPRequestHandler): return False return True + def _request_icalendar(self) -> bool: + """Should an icalendar response be given? + """ + if not self.headers.get('Accept'): + return False + accept_str = self.headers['Accept'] + if 'text/calendar' in accept_str: + return True + return False + def _signed_ge_tkey_id(self) -> str: """Returns the actor from the signed GET key_id """ @@ -14056,9 +14066,12 @@ class PubServer(BaseHTTPRequestHandler): # is this a html request? html_getreq = False + icalendar_getreq = False if self._has_accept(calling_domain): if self._request_http(): html_getreq = True + elif self._request_icalendar(): + icalendar_getreq = True else: if self.headers.get('Connection'): # https://developer.mozilla.org/en-US/ @@ -15532,7 +15545,7 @@ class PubServer(BaseHTTPRequestHandler): '_GET', 'search screen shown done', self.server.debug) - # Show the calendar for a user + # Show the html calendar for a user if html_getreq and users_in_path: if '/calendar' in self.path: nickname = self.path.split('/users/')[1] @@ -15551,9 +15564,11 @@ class PubServer(BaseHTTPRequestHandler): self.server.http_prefix, self.server.domain_full, self.server.text_mode_banner, - access_keys).encode('utf-8') + access_keys, + False).encode('utf-8') msglen = len(msg) - self._set_headers('text/html', msglen, cookie, calling_domain, + self._set_headers('text/html', + msglen, cookie, calling_domain, False) self._write(msg) fitness_performance(getreq_start_time, self.server.fitness, @@ -15562,6 +15577,38 @@ class PubServer(BaseHTTPRequestHandler): self.server.getreq_busy = False return + # Show the icalendar for a user + if icalendar_getreq and users_in_path: + if '/calendar' in self.path: + nickname = self.path.split('/users/')[1] + if '/' in nickname: + nickname = nickname.split('/')[0] + + access_keys = self.server.access_keys + if self.server.key_shortcuts.get(nickname): + access_keys = self.server.key_shortcuts[nickname] + + # show the calendar screen + msg = html_calendar(self.server.person_cache, + self.server.css_cache, + self.server.translate, + self.server.base_dir, self.path, + self.server.http_prefix, + self.server.domain_full, + self.server.text_mode_banner, + access_keys, + True).encode('utf-8') + msglen = len(msg) + self._set_headers('text/calendar', + msglen, cookie, calling_domain, + False) + self._write(msg) + fitness_performance(getreq_start_time, self.server.fitness, + '_GET', 'icalendar shown', + self.server.debug) + self.server.getreq_busy = False + return + fitness_performance(getreq_start_time, self.server.fitness, '_GET', 'calendar shown done', self.server.debug) diff --git a/epicyon-calendar.css b/epicyon-calendar.css index eb279a995..8adc6d590 100644 --- a/epicyon-calendar.css +++ b/epicyon-calendar.css @@ -32,6 +32,9 @@ --calendar-header-font-style: italic; --main-link-color-hover: blue; --rendering: normal; + --ical-icon-size: 32px; + --ical-icon-size-mobile: 80px; + --ical-icon-size-tiny: 80px; } @font-face { @@ -256,6 +259,10 @@ tr:nth-child(even) > .calendar__day__cell:nth-child(even) { body { font-size: var(--font-size-calendar); } + img ical { + width: var(--ical-icon-size); + float: right; + } } @media screen and (max-width: 1000px) { @@ -276,6 +283,10 @@ tr:nth-child(even) > .calendar__day__cell:nth-child(even) { body { font-size: var(--font-size-calendar-mobile); } + img ical { + width: var(--ical-icon-size-mobile); + float: right; + } } @media screen and (max-width: 480px) { @@ -296,4 +307,8 @@ tr:nth-child(even) > .calendar__day__cell:nth-child(even) { body { font-size: var(--font-size-calendar-tiny); } + img ical { + width: var(--ical-icon-size-tiny); + float: right; + } } diff --git a/happening.py b/happening.py index 4670fc64e..733017fc7 100644 --- a/happening.py +++ b/happening.py @@ -18,6 +18,8 @@ from utils import save_json from utils import locate_post from utils import has_object_dict from utils import acct_dir +from utils import remove_html +from utils import get_display_name def _valid_uuid(test_uuid: str, version: int): @@ -175,20 +177,20 @@ def _is_happening_post(post_json_object: {}) -> bool: def get_todays_events(base_dir: str, nickname: str, domain: str, - currYear: int, currMonthNumber: int, + curr_year: int, curr_month_number: int, currDayOfMonth: int) -> {}: """Retrieves calendar events for today Returns a dictionary of lists containing Event and Place activities """ now = datetime.now() - if not currYear: + if not curr_year: year = now.year else: - year = currYear - if not currMonthNumber: + year = curr_year + if not curr_month_number: month_number = now.month else: - month_number = currMonthNumber + month_number = curr_month_number if not currDayOfMonth: day_number = now.day else: @@ -263,13 +265,181 @@ def get_todays_events(base_dir: str, nickname: str, domain: str, return events +def _icalendar_day(base_dir: str, nickname: str, domain: str, + day_events: [], person_cache: {}) -> str: + """Returns a day's events in icalendar format + """ + ical_str = '' + for event_post in day_events: + event_description = None + event_place = None + post_id = None + sender_name = '' + sender_actor = None + event_is_public = False + event_start = None + event_end = None + + for evnt in event_post: + if evnt['type'] == 'Event': + if evnt.get('post_id'): + post_id = evnt['post_id'] + if evnt.get('startTime'): + event_start = \ + datetime.strptime(evnt['startTime'], + "%Y%m%dT%H%M%S%Z") + evnt_end = evnt['startTime'] + timedelta(hours=1) + event_end = \ + datetime.strptime(evnt_end, + "%Y%m%dT%H%M%S%Z") + if 'public' in evnt: + if evnt['public'] is True: + event_is_public = True + if evnt.get('sender'): + # get display name from sending actor + if evnt.get('sender'): + sender_actor = evnt['sender'] + disp_name = \ + get_display_name(base_dir, sender_actor, + person_cache) + if disp_name: + sender_name = \ + '' + \ + disp_name + ': ' + if evnt.get('name'): + event_description = evnt['name'].strip() + elif evnt['type'] == 'Place': + if evnt.get('name'): + event_place = evnt['name'] + + if not post_id or not event_start or \ + not event_description or not sender_actor: + continue + + # find the corresponding post + post_filename = locate_post(base_dir, nickname, domain, post_id) + if not post_filename: + continue + + post_json_object = load_json(post_filename) + if not post_json_object: + continue + + # get the published date from the post + if not post_json_object.get('object'): + continue + if not isinstance(post_json_object['object'], dict): + continue + if not post_json_object['object'].get('published'): + continue + if not isinstance(post_json_object['object']['published'], str): + continue + published = post_json_object['object']['published'] + published = published.replace('-', '') + published = published.replace(':', '') + published = published.replace(' ', '') + + ical_str += \ + 'BEGIN:VEVENT\n' + \ + 'DTSTAMP:' + published + '\n' + \ + 'UID:' + post_id + '\n' + \ + 'DTSTART:' + event_start + '\n' + \ + 'DTEND:' + event_end + '\n' + \ + 'STATUS:CONFIRMED\n' + descr = remove_html(event_description) + if len(descr) < 255: + ical_str += \ + 'SUMMARY:' + descr + '\n' + else: + ical_str += \ + 'SUMMARY:' + descr[255:] + '\n' + ical_str += \ + 'DESCRIPTION:' + descr + '\n' + if event_is_public: + ical_str += \ + 'CATEGORIES:APPOINTMENT,PUBLIC\n' + else: + ical_str += \ + 'CATEGORIES:APPOINTMENT\n' + if sender_name: + ical_str += \ + 'ORGANIZER;CN=' + remove_html(sender_name) + ':' + \ + sender_actor + '\n' + else: + ical_str += \ + 'ORGANIZER:' + sender_actor + '\n' + if event_place: + ical_str += \ + 'LOCATION:' + remove_html(event_place) + '\n' + ical_str += 'END:VEVENT\n' + return ical_str + + +def get_todays_events_icalendar(base_dir: str, nickname: str, domain: str, + year: int, month_number: int, + day_number: int, person_cache: {}) -> str: + """Returns today's events in icalendar format + """ + events = \ + get_todays_events(base_dir, nickname, domain, + year, month_number, day_number) + ical_str = \ + 'BEGIN:VCALENDAR\n' + \ + 'PRODID:-//Fediverse//NONSGML Epicyon//EN' + \ + 'VERSION:2.0' + if not events: + ical_str += 'END:VCALENDAR\n' + return ical_str + + if not events.get(str(day_number)): + ical_str += 'END:VCALENDAR\n' + return ical_str + + day_events = events[str(day_number)] + + ical_str += \ + _icalendar_day(base_dir, nickname, domain, day_events, person_cache) + + ical_str += 'END:VCALENDAR\n' + return ical_str + + +def get_month_events_icalendar(base_dir: str, nickname: str, domain: str, + curr_year: int, + curr_month_number: int, + person_cache: {}) -> str: + """Returns today's events in icalendar format + """ + events = \ + get_calendar_events(base_dir, nickname, domain, curr_year, + curr_month_number) + ical_str = \ + 'BEGIN:VCALENDAR\n' + \ + 'PRODID:-//Fediverse//NONSGML Epicyon//EN' + \ + 'VERSION:2.0' + if not events: + ical_str += 'END:VCALENDAR\n' + return ical_str + + for day_number in range(1, 32): + if not events.get(str(day_number)): + continue + day_events = events[str(day_number)] + ical_str += \ + _icalendar_day(base_dir, nickname, domain, day_events, + person_cache) + + ical_str += 'END:VCALENDAR\n' + return ical_str + + def day_events_check(base_dir: str, nickname: str, domain: str, - currDate) -> bool: + curr_date) -> bool: """Are there calendar events for the given date? """ - year = currDate.year - month_number = currDate.month - day_number = currDate.day + year = curr_date.year + month_number = curr_date.month + day_number = curr_date.day calendar_filename = \ acct_dir(base_dir, nickname, domain) + \ diff --git a/theme/blue/icons/ical.png b/theme/blue/icons/ical.png new file mode 100644 index 0000000000000000000000000000000000000000..b8b17a1a0c8a0d482d5c8fc78e11454d148d792a GIT binary patch literal 7210 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 BXwU!v literal 0 HcmV?d00001 diff --git a/theme/debian/icons/ical.png b/theme/debian/icons/ical.png new file mode 100644 index 0000000000000000000000000000000000000000..b8b17a1a0c8a0d482d5c8fc78e11454d148d792a GIT binary patch literal 7210 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 BXwU!v literal 0 HcmV?d00001 diff --git a/theme/default/icons/ical.png b/theme/default/icons/ical.png new file mode 100644 index 0000000000000000000000000000000000000000..b8b17a1a0c8a0d482d5c8fc78e11454d148d792a GIT binary patch literal 7210 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 BXwU!v literal 0 HcmV?d00001 diff --git a/theme/hacker/icons/ical.png b/theme/hacker/icons/ical.png new file mode 100644 index 0000000000000000000000000000000000000000..5226ffbaef949e3ff382cabe3406b2e5d4e58a57 GIT binary patch literal 9502 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 literal 0 HcmV?d00001 diff --git a/theme/henge/icons/ical.png b/theme/henge/icons/ical.png new file mode 100644 index 0000000000000000000000000000000000000000..7929edc793c42ccb63baeaa36ddc4aee419ad53e GIT binary patch literal 9190 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 literal 0 HcmV?d00001 diff --git a/theme/indymediaclassic/icons/ical.png b/theme/indymediaclassic/icons/ical.png new file mode 100644 index 0000000000000000000000000000000000000000..1bdbd43c5275b69d0344a671456da0ab3ada1ad8 GIT binary patch literal 11140 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 literal 0 HcmV?d00001 diff --git a/theme/light/icons/ical.png b/theme/light/icons/ical.png new file mode 100644 index 0000000000000000000000000000000000000000..93d2f809a525142bdac9b783b38f54a7a19dda7b GIT binary patch literal 9391 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 BXwU!v literal 0 HcmV?d00001 diff --git a/theme/pixel/icons/ical.png b/theme/pixel/icons/ical.png new file mode 100644 index 0000000000000000000000000000000000000000..bc14f0e7ad5d3e0b33ea9082b44372c921807545 GIT binary patch literal 10661 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 X40x}TB|xKZ6acJ_fp)RxrJ(-@db2IA literal 0 HcmV?d00001 diff --git a/theme/purple/icons/ical.png b/theme/purple/icons/ical.png new file mode 100644 index 0000000000000000000000000000000000000000..0c54320def83407e5e3b023afa7c376627ebf4e4 GIT binary patch literal 11258 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 literal 0 HcmV?d00001 diff --git a/theme/solidaric/icons/ical.png b/theme/solidaric/icons/ical.png new file mode 100644 index 0000000000000000000000000000000000000000..5e60ea3412d5975fff6057c5222370c641881b97 GIT binary patch literal 9548 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∨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 literal 0 HcmV?d00001 diff --git a/webapp_calendar.py b/webapp_calendar.py index 131e71493..e44f5761e 100644 --- a/webapp_calendar.py +++ b/webapp_calendar.py @@ -24,6 +24,8 @@ from utils import local_actor_url from utils import replace_users_with_at from happening import get_todays_events from happening import get_calendar_events +from happening import get_todays_events_icalendar +from happening import get_month_events_icalendar from webapp_utils import set_custom_background from webapp_utils import html_header_with_external_style from webapp_utils import html_footer @@ -241,6 +243,13 @@ def _html_calendar_day(person_cache: {}, css_cache: {}, translate: {}, event_place + '' + \ delete_button_str + '\n' + # icalendar download link + calendar_str += \ + ' ' + \ + 'iCalendar\n' + calendar_str += '\n' calendar_str += '\n' calendar_str += html_footer() @@ -251,7 +260,8 @@ def _html_calendar_day(person_cache: {}, css_cache: {}, translate: {}, def html_calendar(person_cache: {}, css_cache: {}, translate: {}, base_dir: str, path: str, http_prefix: str, domain_full: str, - text_mode_banner: str, access_keys: {}) -> str: + text_mode_banner: str, access_keys: {}, + icalendar: bool) -> str: """Show the calendar for a person """ domain = remove_domain_port(domain_full) @@ -277,6 +287,10 @@ def html_calendar(person_cache: {}, css_cache: {}, translate: {}, num_str = part.split('=')[1] if num_str.isdigit(): day_number = int(num_str) + elif part.split('=')[0] == 'ical': + bool_str = part.split('=')[1] + if bool_str.tolower().startswith('t'): + icalendar = True first = False actor = actor.split('?')[0] @@ -297,6 +311,13 @@ def html_calendar(person_cache: {}, css_cache: {}, translate: {}, month_name = translate[months[month_number - 1]] if day_number: + if icalendar: + return get_todays_events_icalendar(base_dir, + nickname, domain, + year, month_number, + day_number, + person_cache) + day_events = None events = \ get_todays_events(base_dir, nickname, domain, @@ -310,6 +331,10 @@ def html_calendar(person_cache: {}, css_cache: {}, translate: {}, nickname, domain, day_events, month_name, actor) + if icalendar: + return get_month_events_icalendar(base_dir, nickname, domain, + year, month_number, person_cache) + events = \ get_calendar_events(base_dir, nickname, domain, year, month_number) From 1d8e6922097430fd88ff3bb21372936712250a1e Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 21 Feb 2022 11:37:18 +0000 Subject: [PATCH 02/24] icalendar icon style --- epicyon-calendar.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/epicyon-calendar.css b/epicyon-calendar.css index 8adc6d590..412bf9efa 100644 --- a/epicyon-calendar.css +++ b/epicyon-calendar.css @@ -259,7 +259,7 @@ tr:nth-child(even) > .calendar__day__cell:nth-child(even) { body { font-size: var(--font-size-calendar); } - img ical { + body img.ical { width: var(--ical-icon-size); float: right; } @@ -283,7 +283,7 @@ tr:nth-child(even) > .calendar__day__cell:nth-child(even) { body { font-size: var(--font-size-calendar-mobile); } - img ical { + body img.ical { width: var(--ical-icon-size-mobile); float: right; } @@ -307,7 +307,7 @@ tr:nth-child(even) > .calendar__day__cell:nth-child(even) { body { font-size: var(--font-size-calendar-tiny); } - img ical { + body img.ical { width: var(--ical-icon-size-tiny); float: right; } From d27982fbe19269f3f71a75aee0b434810a3afc93 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 21 Feb 2022 11:40:14 +0000 Subject: [PATCH 03/24] Lower case --- webapp_calendar.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/webapp_calendar.py b/webapp_calendar.py index e44f5761e..4da04e069 100644 --- a/webapp_calendar.py +++ b/webapp_calendar.py @@ -289,7 +289,7 @@ def html_calendar(person_cache: {}, css_cache: {}, translate: {}, day_number = int(num_str) elif part.split('=')[0] == 'ical': bool_str = part.split('=')[1] - if bool_str.tolower().startswith('t'): + if bool_str.lower().startswith('t'): icalendar = True first = False actor = actor.split('?')[0] @@ -494,8 +494,14 @@ def html_calendar(person_cache: {}, css_cache: {}, translate: {}, '➕ ' + \ translate['Add to the calendar'] + '\n

\n\n' + calendar_icon_str += \ + ' ' + \ + 'iCalendar\n' + cal_str = \ header_str + screen_reader_cal + calendar_str + \ - new_event_str + html_footer() + new_event_str + calendar_icon_str + html_footer() return cal_str From 2b74e71ea98299747e926b5cbf4c2f4daa2930ad Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 21 Feb 2022 11:43:10 +0000 Subject: [PATCH 04/24] Return calendar mime type for download --- daemon.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/daemon.py b/daemon.py index 6baf527d7..dc3fe58ab 100644 --- a/daemon.py +++ b/daemon.py @@ -15567,9 +15567,14 @@ class PubServer(BaseHTTPRequestHandler): access_keys, False).encode('utf-8') msglen = len(msg) - self._set_headers('text/html', - msglen, cookie, calling_domain, - False) + if 'ical=true' in self.path: + self._set_headers('text/calendar', + msglen, cookie, calling_domain, + False) + else: + self._set_headers('text/html', + msglen, cookie, calling_domain, + False) self._write(msg) fitness_performance(getreq_start_time, self.server.fitness, '_GET', 'calendar shown', From 0dea3f303495cb968767d950b4cdf1170cd9c2c8 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 21 Feb 2022 11:45:29 +0000 Subject: [PATCH 05/24] Line endings --- happening.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/happening.py b/happening.py index 733017fc7..0a3c76743 100644 --- a/happening.py +++ b/happening.py @@ -385,8 +385,8 @@ def get_todays_events_icalendar(base_dir: str, nickname: str, domain: str, year, month_number, day_number) ical_str = \ 'BEGIN:VCALENDAR\n' + \ - 'PRODID:-//Fediverse//NONSGML Epicyon//EN' + \ - 'VERSION:2.0' + 'PRODID:-//Fediverse//NONSGML Epicyon//EN\n' + \ + 'VERSION:2.0\n' if not events: ical_str += 'END:VCALENDAR\n' return ical_str From b85059b4d93be08bfa645954741930081ced5fe9 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 21 Feb 2022 11:49:12 +0000 Subject: [PATCH 06/24] equals --- webapp_calendar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp_calendar.py b/webapp_calendar.py index 4da04e069..055e16127 100644 --- a/webapp_calendar.py +++ b/webapp_calendar.py @@ -494,7 +494,7 @@ def html_calendar(person_cache: {}, css_cache: {}, translate: {}, '➕ ' + \ translate['Add to the calendar'] + '\n

\n\n' - calendar_icon_str += \ + calendar_icon_str = \ ' ' + \ ' Date: Mon, 21 Feb 2022 11:51:11 +0000 Subject: [PATCH 07/24] Icon at bottom --- webapp_calendar.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/webapp_calendar.py b/webapp_calendar.py index 055e16127..d5f6f24e2 100644 --- a/webapp_calendar.py +++ b/webapp_calendar.py @@ -243,6 +243,9 @@ def _html_calendar_day(person_cache: {}, css_cache: {}, translate: {}, event_place + '' + \ delete_button_str + '\n' + calendar_str += '\n' + calendar_str += '\n' + # icalendar download link calendar_str += \ ' \n' - calendar_str += '\n' - calendar_str += '\n' calendar_str += html_footer() return calendar_str From e7a931ec756c4412d83e9efbebcd5132ace4c5d6 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 21 Feb 2022 11:51:43 +0000 Subject: [PATCH 08/24] Line endings --- happening.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/happening.py b/happening.py index 0a3c76743..35a574b58 100644 --- a/happening.py +++ b/happening.py @@ -415,8 +415,8 @@ def get_month_events_icalendar(base_dir: str, nickname: str, domain: str, curr_month_number) ical_str = \ 'BEGIN:VCALENDAR\n' + \ - 'PRODID:-//Fediverse//NONSGML Epicyon//EN' + \ - 'VERSION:2.0' + 'PRODID:-//Fediverse//NONSGML Epicyon//EN\n' + \ + 'VERSION:2.0\n' if not events: ical_str += 'END:VCALENDAR\n' return ical_str From 057c2cf875ed19c1846a2628766dcda6ad8007bd Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 21 Feb 2022 14:46:46 +0000 Subject: [PATCH 09/24] Debug --- happening.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/happening.py b/happening.py index 35a574b58..13d40ca79 100644 --- a/happening.py +++ b/happening.py @@ -312,6 +312,10 @@ def _icalendar_day(base_dir: str, nickname: str, domain: str, if evnt.get('name'): event_place = evnt['name'] + print('icalendar: ' + str(post_id) + ' ' + + str(event_start) + ' ' + str(event_description) + ' ' + + str(sender_actor)) + if not post_id or not event_start or \ not event_description or not sender_actor: continue @@ -405,14 +409,14 @@ def get_todays_events_icalendar(base_dir: str, nickname: str, domain: str, def get_month_events_icalendar(base_dir: str, nickname: str, domain: str, - curr_year: int, - curr_month_number: int, + year: int, + month_number: int, person_cache: {}) -> str: """Returns today's events in icalendar format """ events = \ - get_calendar_events(base_dir, nickname, domain, curr_year, - curr_month_number) + get_calendar_events(base_dir, nickname, domain, year, + month_number) ical_str = \ 'BEGIN:VCALENDAR\n' + \ 'PRODID:-//Fediverse//NONSGML Epicyon//EN\n' + \ @@ -421,13 +425,13 @@ def get_month_events_icalendar(base_dir: str, nickname: str, domain: str, ical_str += 'END:VCALENDAR\n' return ical_str - for day_number in range(1, 32): - if not events.get(str(day_number)): + for day_of_month in range(1, 32): + if not events.get(str(day_of_month)): continue - day_events = events[str(day_number)] + day_events = events[str(day_of_month)] ical_str += \ - _icalendar_day(base_dir, nickname, domain, day_events, - person_cache) + _icalendar_day(base_dir, nickname, domain, + day_events, person_cache) ical_str += 'END:VCALENDAR\n' return ical_str From 8b20597cd74249badd7fb92b07080a7f05b0da8a Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 21 Feb 2022 14:49:19 +0000 Subject: [PATCH 10/24] Debug --- happening.py | 1 + 1 file changed, 1 insertion(+) diff --git a/happening.py b/happening.py index 13d40ca79..00e83a3f0 100644 --- a/happening.py +++ b/happening.py @@ -270,6 +270,7 @@ def _icalendar_day(base_dir: str, nickname: str, domain: str, """Returns a day's events in icalendar format """ ical_str = '' + print('icalendar: ' + str(day_events)) for event_post in day_events: event_description = None event_place = None From d2901ece128922614c519c8e5592bfbb952d2672 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 21 Feb 2022 14:51:12 +0000 Subject: [PATCH 11/24] Debug --- happening.py | 1 + 1 file changed, 1 insertion(+) diff --git a/happening.py b/happening.py index 00e83a3f0..5590de4df 100644 --- a/happening.py +++ b/happening.py @@ -426,6 +426,7 @@ def get_month_events_icalendar(base_dir: str, nickname: str, domain: str, ical_str += 'END:VCALENDAR\n' return ical_str + print('icalendar month: ' + str(events)) for day_of_month in range(1, 32): if not events.get(str(day_of_month)): continue From afba6a4364baffd20f135f3e276a550c206199bd Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 21 Feb 2022 16:58:37 +0000 Subject: [PATCH 12/24] Snake case --- happening.py | 6 +++--- webapp_calendar.py | 9 +++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/happening.py b/happening.py index 5590de4df..afb7ec281 100644 --- a/happening.py +++ b/happening.py @@ -178,7 +178,7 @@ def _is_happening_post(post_json_object: {}) -> bool: def get_todays_events(base_dir: str, nickname: str, domain: str, curr_year: int, curr_month_number: int, - currDayOfMonth: int) -> {}: + curr_day_of_month: int) -> {}: """Retrieves calendar events for today Returns a dictionary of lists containing Event and Place activities """ @@ -191,10 +191,10 @@ def get_todays_events(base_dir: str, nickname: str, domain: str, month_number = now.month else: month_number = curr_month_number - if not currDayOfMonth: + if not curr_day_of_month: day_number = now.day else: - day_number = currDayOfMonth + day_number = curr_day_of_month calendar_filename = \ acct_dir(base_dir, nickname, domain) + \ diff --git a/webapp_calendar.py b/webapp_calendar.py index d5f6f24e2..be512ab86 100644 --- a/webapp_calendar.py +++ b/webapp_calendar.py @@ -267,9 +267,11 @@ def html_calendar(person_cache: {}, css_cache: {}, translate: {}, """ domain = remove_domain_port(domain_full) - month_number = 0 + default_year = 1970 + default_month = 0 + month_number = default_month day_number = None - year = 1970 + year = default_year actor = http_prefix + '://' + domain_full + path.replace('/calendar', '') if '?' in actor: first = True @@ -296,7 +298,7 @@ def html_calendar(person_cache: {}, css_cache: {}, translate: {}, actor = actor.split('?')[0] curr_date = datetime.now() - if year == 1970 and month_number == 0: + if year == default_year and month_number == default_month: year = curr_date.year month_number = curr_date.month @@ -318,7 +320,6 @@ def html_calendar(person_cache: {}, css_cache: {}, translate: {}, year, month_number, day_number, person_cache) - day_events = None events = \ get_todays_events(base_dir, nickname, domain, From 3ce5cc963fd6b7aecc916b54f55d632a0419d8e2 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 21 Feb 2022 16:59:38 +0000 Subject: [PATCH 13/24] debug --- happening.py | 1 + 1 file changed, 1 insertion(+) diff --git a/happening.py b/happening.py index afb7ec281..733b074bf 100644 --- a/happening.py +++ b/happening.py @@ -392,6 +392,7 @@ def get_todays_events_icalendar(base_dir: str, nickname: str, domain: str, 'BEGIN:VCALENDAR\n' + \ 'PRODID:-//Fediverse//NONSGML Epicyon//EN\n' + \ 'VERSION:2.0\n' + print('icalendar daily: ' + str(events)) if not events: ical_str += 'END:VCALENDAR\n' return ical_str From aa1bda4a70018a1285ce19050a980ee4ea5324bb Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 21 Feb 2022 17:17:07 +0000 Subject: [PATCH 14/24] Debug --- happening.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/happening.py b/happening.py index 733b074bf..d43063a50 100644 --- a/happening.py +++ b/happening.py @@ -392,8 +392,9 @@ def get_todays_events_icalendar(base_dir: str, nickname: str, domain: str, 'BEGIN:VCALENDAR\n' + \ 'PRODID:-//Fediverse//NONSGML Epicyon//EN\n' + \ 'VERSION:2.0\n' - print('icalendar daily: ' + str(events)) if not events: + print('icalendar daily: ' + str(year) + '-' + str(month_number) + + '-' + str(day_number) + ' ' + str(events)) ical_str += 'END:VCALENDAR\n' return ical_str From 961fd358e32c37732aa268de5b52b803b86dbbb9 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 21 Feb 2022 17:27:37 +0000 Subject: [PATCH 15/24] Getting day events --- happening.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/happening.py b/happening.py index d43063a50..1ccc7a063 100644 --- a/happening.py +++ b/happening.py @@ -385,16 +385,21 @@ def get_todays_events_icalendar(base_dir: str, nickname: str, domain: str, day_number: int, person_cache: {}) -> str: """Returns today's events in icalendar format """ + day_events = None events = \ get_todays_events(base_dir, nickname, domain, year, month_number, day_number) + if events: + if events.get(str(day_number)): + day_events = events[str(day_number)] + ical_str = \ 'BEGIN:VCALENDAR\n' + \ 'PRODID:-//Fediverse//NONSGML Epicyon//EN\n' + \ 'VERSION:2.0\n' - if not events: + if not day_events: print('icalendar daily: ' + str(year) + '-' + str(month_number) + - '-' + str(day_number) + ' ' + str(events)) + '-' + str(day_number) + ' ' + str(day_events)) ical_str += 'END:VCALENDAR\n' return ical_str From 28399402966d5d619ae74c0841abae148facd87e Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 21 Feb 2022 17:34:14 +0000 Subject: [PATCH 16/24] Monthly icalendar events --- happening.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/happening.py b/happening.py index 1ccc7a063..40a07c631 100644 --- a/happening.py +++ b/happening.py @@ -403,12 +403,6 @@ def get_todays_events_icalendar(base_dir: str, nickname: str, domain: str, ical_str += 'END:VCALENDAR\n' return ical_str - if not events.get(str(day_number)): - ical_str += 'END:VCALENDAR\n' - return ical_str - - day_events = events[str(day_number)] - ical_str += \ _icalendar_day(base_dir, nickname, domain, day_events, person_cache) @@ -422,22 +416,24 @@ def get_month_events_icalendar(base_dir: str, nickname: str, domain: str, person_cache: {}) -> str: """Returns today's events in icalendar format """ + month_events = None events = \ get_calendar_events(base_dir, nickname, domain, year, month_number) + ical_str = \ 'BEGIN:VCALENDAR\n' + \ 'PRODID:-//Fediverse//NONSGML Epicyon//EN\n' + \ 'VERSION:2.0\n' - if not events: + if not month_events: ical_str += 'END:VCALENDAR\n' return ical_str - print('icalendar month: ' + str(events)) + print('icalendar month: ' + str(month_events)) for day_of_month in range(1, 32): - if not events.get(str(day_of_month)): + if not month_events.get(str(day_of_month)): continue - day_events = events[str(day_of_month)] + day_events = month_events[str(day_of_month)] ical_str += \ _icalendar_day(base_dir, nickname, domain, day_events, person_cache) From e3f30d79ed0ec14177a81a0e2a79a37d000b1438 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 21 Feb 2022 17:38:07 +0000 Subject: [PATCH 17/24] Debug --- happening.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/happening.py b/happening.py index 40a07c631..ee862da7d 100644 --- a/happening.py +++ b/happening.py @@ -398,7 +398,8 @@ def get_todays_events_icalendar(base_dir: str, nickname: str, domain: str, 'PRODID:-//Fediverse//NONSGML Epicyon//EN\n' + \ 'VERSION:2.0\n' if not day_events: - print('icalendar daily: ' + str(year) + '-' + str(month_number) + + print('icalendar daily: ' + nickname + '@' + domain + ' ' + + str(year) + '-' + str(month_number) + '-' + str(day_number) + ' ' + str(day_events)) ical_str += 'END:VCALENDAR\n' return ical_str From f0f775776303e02e976d9caba042398bb21eb04b Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 21 Feb 2022 17:43:55 +0000 Subject: [PATCH 18/24] Extraneous users path --- webapp_calendar.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webapp_calendar.py b/webapp_calendar.py index be512ab86..f6392b8e2 100644 --- a/webapp_calendar.py +++ b/webapp_calendar.py @@ -248,7 +248,7 @@ def _html_calendar_day(person_cache: {}, css_cache: {}, translate: {}, # icalendar download link calendar_str += \ - ' ' + \ 'iCalendar\n' @@ -497,7 +497,7 @@ def html_calendar(person_cache: {}, css_cache: {}, translate: {}, translate['Add to the calendar'] + '\n

\n\n' calendar_icon_str = \ - ' ' + \ 'iCalendar\n' From 1effb9b15a0f52acc5a44c778ed6af5b5ee97e32 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 21 Feb 2022 18:20:59 +0000 Subject: [PATCH 19/24] Date conversions --- happening.py | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/happening.py b/happening.py index ee862da7d..f00ec7e22 100644 --- a/happening.py +++ b/happening.py @@ -265,6 +265,14 @@ def get_todays_events(base_dir: str, nickname: str, domain: str, return events +def _ical_date_string(date_str: str) -> str: + """Returns an icalendar formatted date + """ + date_str = date_str.replace('-', '') + date_str = date_str.replace(':', '') + return date_str.replace(' ', '') + + def _icalendar_day(base_dir: str, nickname: str, domain: str, day_events: [], person_cache: {}) -> str: """Returns a day's events in icalendar format @@ -288,11 +296,9 @@ def _icalendar_day(base_dir: str, nickname: str, domain: str, if evnt.get('startTime'): event_start = \ datetime.strptime(evnt['startTime'], - "%Y%m%dT%H%M%S%Z") - evnt_end = evnt['startTime'] + timedelta(hours=1) - event_end = \ - datetime.strptime(evnt_end, - "%Y%m%dT%H%M%S%Z") + "%Y-%m-%dT%H:%M:%S%z") + evnt_end = event_start + timedelta(hours=1) + event_end = evnt_end.strftime("%Y-%m-%dT%H:%M:%S%z") if 'public' in evnt: if evnt['public'] is True: event_is_public = True @@ -339,10 +345,12 @@ def _icalendar_day(base_dir: str, nickname: str, domain: str, continue if not isinstance(post_json_object['object']['published'], str): continue - published = post_json_object['object']['published'] - published = published.replace('-', '') - published = published.replace(':', '') - published = published.replace(' ', '') + published = \ + _ical_date_string(post_json_object['object']['published']) + + event_start = \ + _ical_date_string(event_start.strftime("%Y-%m-%dT%H:%M:%SZ")) + event_end = _ical_date_string(event_end) ical_str += \ 'BEGIN:VEVENT\n' + \ @@ -417,8 +425,7 @@ def get_month_events_icalendar(base_dir: str, nickname: str, domain: str, person_cache: {}) -> str: """Returns today's events in icalendar format """ - month_events = None - events = \ + month_events = \ get_calendar_events(base_dir, nickname, domain, year, month_number) From 0b4c2603646eedd59b18059f405dd62d59fca201 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 21 Feb 2022 19:01:19 +0000 Subject: [PATCH 20/24] post id within icalendar output --- happening.py | 30 ++++++++++++++++++++---------- webapp_calendar.py | 6 ++++-- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/happening.py b/happening.py index f00ec7e22..138456cde 100644 --- a/happening.py +++ b/happening.py @@ -274,7 +274,8 @@ def _ical_date_string(date_str: str) -> str: def _icalendar_day(base_dir: str, nickname: str, domain: str, - day_events: [], person_cache: {}) -> str: + day_events: [], person_cache: {}, + http_prefix: str) -> str: """Returns a day's events in icalendar format """ ical_str = '' @@ -292,13 +293,17 @@ def _icalendar_day(base_dir: str, nickname: str, domain: str, for evnt in event_post: if evnt['type'] == 'Event': if evnt.get('post_id'): - post_id = evnt['post_id'] + post_id = \ + http_prefix + '://' + domain + \ + '/users/' + nickname + '/statuses/' + evnt['post_id'] if evnt.get('startTime'): event_start = \ datetime.strptime(evnt['startTime'], "%Y-%m-%dT%H:%M:%S%z") - evnt_end = event_start + timedelta(hours=1) - event_end = evnt_end.strftime("%Y-%m-%dT%H:%M:%S%z") + if evnt.get('endTime'): + event_end = \ + datetime.strptime(evnt['startTime'], + "%Y-%m-%dT%H:%M:%S%z") if 'public' in evnt: if evnt['public'] is True: event_is_public = True @@ -323,7 +328,7 @@ def _icalendar_day(base_dir: str, nickname: str, domain: str, str(event_start) + ' ' + str(event_description) + ' ' + str(sender_actor)) - if not post_id or not event_start or \ + if not post_id or not event_start or not event_end or \ not event_description or not sender_actor: continue @@ -350,7 +355,8 @@ def _icalendar_day(base_dir: str, nickname: str, domain: str, event_start = \ _ical_date_string(event_start.strftime("%Y-%m-%dT%H:%M:%SZ")) - event_end = _ical_date_string(event_end) + event_end = \ + _ical_date_string(event_end.strftime("%Y-%m-%dT%H:%M:%SZ")) ical_str += \ 'BEGIN:VEVENT\n' + \ @@ -390,7 +396,8 @@ def _icalendar_day(base_dir: str, nickname: str, domain: str, def get_todays_events_icalendar(base_dir: str, nickname: str, domain: str, year: int, month_number: int, - day_number: int, person_cache: {}) -> str: + day_number: int, person_cache: {}, + http_prefix: str) -> str: """Returns today's events in icalendar format """ day_events = None @@ -413,7 +420,8 @@ def get_todays_events_icalendar(base_dir: str, nickname: str, domain: str, return ical_str ical_str += \ - _icalendar_day(base_dir, nickname, domain, day_events, person_cache) + _icalendar_day(base_dir, nickname, domain, day_events, person_cache, + http_prefix) ical_str += 'END:VCALENDAR\n' return ical_str @@ -422,7 +430,8 @@ def get_todays_events_icalendar(base_dir: str, nickname: str, domain: str, def get_month_events_icalendar(base_dir: str, nickname: str, domain: str, year: int, month_number: int, - person_cache: {}) -> str: + person_cache: {}, + http_prefix: str) -> str: """Returns today's events in icalendar format """ month_events = \ @@ -444,7 +453,8 @@ def get_month_events_icalendar(base_dir: str, nickname: str, domain: str, day_events = month_events[str(day_of_month)] ical_str += \ _icalendar_day(base_dir, nickname, domain, - day_events, person_cache) + day_events, person_cache, + http_prefix) ical_str += 'END:VCALENDAR\n' return ical_str diff --git a/webapp_calendar.py b/webapp_calendar.py index f6392b8e2..38a3afa86 100644 --- a/webapp_calendar.py +++ b/webapp_calendar.py @@ -319,7 +319,8 @@ def html_calendar(person_cache: {}, css_cache: {}, translate: {}, nickname, domain, year, month_number, day_number, - person_cache) + person_cache, + http_prefix) day_events = None events = \ get_todays_events(base_dir, nickname, domain, @@ -335,7 +336,8 @@ def html_calendar(person_cache: {}, css_cache: {}, translate: {}, if icalendar: return get_month_events_icalendar(base_dir, nickname, domain, - year, month_number, person_cache) + year, month_number, person_cache, + http_prefix) events = \ get_calendar_events(base_dir, nickname, domain, year, month_number) From b1615bb1e88bb79e6543144f5875a54bfa27baee Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 21 Feb 2022 19:09:43 +0000 Subject: [PATCH 21/24] Remove extra colon --- happening.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/happening.py b/happening.py index 138456cde..ed1e31d40 100644 --- a/happening.py +++ b/happening.py @@ -317,7 +317,7 @@ def _icalendar_day(base_dir: str, nickname: str, domain: str, if disp_name: sender_name = \ '' + \ - disp_name + ': ' + disp_name + '' if evnt.get('name'): event_description = evnt['name'].strip() elif evnt['type'] == 'Place': From 60ded3b832f586197a0267acaff09c806562d50c Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 21 Feb 2022 19:13:19 +0000 Subject: [PATCH 22/24] Get post id --- happening.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/happening.py b/happening.py index ed1e31d40..e2ad23fb3 100644 --- a/happening.py +++ b/happening.py @@ -240,6 +240,7 @@ def get_todays_events(base_dir: str, nickname: str, domain: str, # link to the id so that the event can be # easily deleted tag['post_id'] = post_id.split('#statuses#')[1] + tag['id'] = post_id tag['sender'] = post_id.split('#statuses#')[0] tag['sender'] = tag['sender'].replace('#', '/') tag['public'] = public_event @@ -292,10 +293,8 @@ def _icalendar_day(base_dir: str, nickname: str, domain: str, for evnt in event_post: if evnt['type'] == 'Event': - if evnt.get('post_id'): - post_id = \ - http_prefix + '://' + domain + \ - '/users/' + nickname + '/statuses/' + evnt['post_id'] + if evnt.get('id'): + post_id = evnt['id'] if evnt.get('startTime'): event_start = \ datetime.strptime(evnt['startTime'], From 010dccaf27903844c3196377b59efcf4dcd6d73f Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 21 Feb 2022 19:15:35 +0000 Subject: [PATCH 23/24] Return of the slashes --- happening.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/happening.py b/happening.py index e2ad23fb3..1454a8c19 100644 --- a/happening.py +++ b/happening.py @@ -240,7 +240,7 @@ def get_todays_events(base_dir: str, nickname: str, domain: str, # link to the id so that the event can be # easily deleted tag['post_id'] = post_id.split('#statuses#')[1] - tag['id'] = post_id + tag['id'] = post_id.replace('#', '/') tag['sender'] = post_id.split('#statuses#')[0] tag['sender'] = tag['sender'].replace('#', '/') tag['public'] = public_event From 8bd278c52c22c7aa15fce339aa9fb9ec9e890d92 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Mon, 21 Feb 2022 19:32:40 +0000 Subject: [PATCH 24/24] Include extra info in month calendar --- happening.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/happening.py b/happening.py index 1454a8c19..237e5e4a3 100644 --- a/happening.py +++ b/happening.py @@ -623,6 +623,11 @@ def get_calendar_events(base_dir: str, nickname: str, domain: str, if int(event_time.strftime("%Y")) == year and \ int(event_time.strftime("%m")) == month_number: day_of_month = str(int(event_time.strftime("%d"))) + if '#statuses#' in post_id: + tag['post_id'] = post_id.split('#statuses#')[1] + tag['id'] = post_id.replace('#', '/') + tag['sender'] = post_id.split('#statuses#')[0] + tag['sender'] = tag['sender'].replace('#', '/') post_event.append(tag) else: # tag is a place