epicyon/happening.py

649 lines
24 KiB
Python
Raw Normal View History

2020-04-03 11:53:31 +00:00
__filename__ = "happening.py"
__author__ = "Bob Mottram"
__license__ = "AGPL3+"
2022-02-03 13:58:20 +00:00
__version__ = "1.3.0"
2020-04-03 11:53:31 +00:00
__maintainer__ = "Bob Mottram"
2021-09-10 16:14:50 +00:00
__email__ = "bob@libreserver.org"
2020-04-03 11:53:31 +00:00
__status__ = "Production"
2021-06-25 16:10:09 +00:00
__module_group__ = "Core"
2020-04-03 11:53:31 +00:00
import os
2020-08-13 13:40:38 +00:00
from uuid import UUID
from datetime import datetime
2021-05-31 13:00:17 +00:00
from datetime import timedelta
2021-12-28 14:41:10 +00:00
from utils import is_public_post
2021-12-26 15:13:34 +00:00
from utils import load_json
2021-12-26 14:47:21 +00:00
from utils import save_json
2021-12-26 20:36:08 +00:00
from utils import locate_post
2021-12-26 10:57:03 +00:00
from utils import has_object_dict
2021-12-26 12:02:29 +00:00
from utils import acct_dir
2022-02-21 11:08:48 +00:00
from utils import remove_html
from utils import get_display_name
2020-04-03 11:53:31 +00:00
2022-01-02 15:16:47 +00:00
def _valid_uuid(test_uuid: str, version: int):
2020-08-13 13:40:38 +00:00
"""Check if uuid_to_test is a valid UUID
"""
try:
2022-01-02 15:16:47 +00:00
uuid_obj = UUID(test_uuid, version=version)
2020-08-13 13:40:38 +00:00
except ValueError:
return False
2022-01-02 15:16:47 +00:00
return str(uuid_obj) == test_uuid
2020-08-13 13:40:38 +00:00
2022-01-02 15:16:47 +00:00
def _remove_event_from_timeline(event_id: str,
tl_events_filename: str) -> None:
2020-08-13 13:40:38 +00:00
"""Removes the given event Id from the timeline
"""
2022-01-02 15:16:47 +00:00
if event_id + '\n' not in open(tl_events_filename).read():
2020-08-13 13:40:38 +00:00
return
2022-01-02 15:16:47 +00:00
with open(tl_events_filename, 'r') as fp_tl:
events_timeline = fp_tl.read().replace(event_id + '\n', '')
try:
2022-01-02 15:16:47 +00:00
with open(tl_events_filename, 'w+') as fp2:
fp2.write(events_timeline)
2021-11-25 21:18:53 +00:00
except OSError:
2021-10-29 18:48:15 +00:00
print('EX: ERROR: unable to save events timeline')
2020-08-13 13:40:38 +00:00
2021-12-29 21:55:09 +00:00
def save_event_post(base_dir: str, handle: str, post_id: str,
2022-01-02 15:16:47 +00:00
event_json: {}) -> bool:
2020-08-13 13:40:38 +00:00
"""Saves an event to the calendar and/or the events timeline
If an event has extra fields, as per Mobilizon,
Then it is saved as a separate entity and added to the
events timeline
2020-08-20 17:08:25 +00:00
See https://framagit.org/framasoft/mobilizon/-/blob/
master/lib/federation/activity_stream/converter/event.ex
2020-08-13 11:58:05 +00:00
"""
2021-12-25 16:17:53 +00:00
if not os.path.isdir(base_dir + '/accounts/' + handle):
print('WARN: Account does not exist at ' +
2021-12-25 16:17:53 +00:00
base_dir + '/accounts/' + handle)
2022-01-02 15:16:47 +00:00
calendar_path = base_dir + '/accounts/' + handle + '/calendar'
if not os.path.isdir(calendar_path):
os.mkdir(calendar_path)
2020-08-13 11:58:05 +00:00
# get the year, month and day from the event
2022-01-02 15:16:47 +00:00
event_time = datetime.strptime(event_json['startTime'],
"%Y-%m-%dT%H:%M:%S%z")
event_year = int(event_time.strftime("%Y"))
if event_year < 2020 or event_year >= 2100:
2020-08-13 13:40:38 +00:00
return False
2022-01-02 15:16:47 +00:00
event_month_number = int(event_time.strftime("%m"))
if event_month_number < 1 or event_month_number > 12:
2020-08-13 13:40:38 +00:00
return False
2022-01-02 15:16:47 +00:00
event_day_of_month = int(event_time.strftime("%d"))
if event_day_of_month < 1 or event_day_of_month > 31:
2020-08-13 13:40:38 +00:00
return False
2022-01-02 15:16:47 +00:00
if event_json.get('name') and event_json.get('actor') and \
event_json.get('uuid') and event_json.get('content'):
if not _valid_uuid(event_json['uuid'], 4):
2020-08-13 13:40:38 +00:00
return False
2020-08-20 16:51:48 +00:00
print('Mobilizon type event')
2020-08-13 13:40:38 +00:00
# if this is a full description of an event then save it
# as a separate json file
2022-01-02 15:16:47 +00:00
events_path = base_dir + '/accounts/' + handle + '/events'
if not os.path.isdir(events_path):
os.mkdir(events_path)
events_year_path = \
base_dir + '/accounts/' + handle + '/events/' + str(event_year)
if not os.path.isdir(events_year_path):
os.mkdir(events_year_path)
event_id = str(event_year) + '-' + event_time.strftime("%m") + '-' + \
event_time.strftime("%d") + '_' + event_json['uuid']
event_filename = events_year_path + '/' + event_id + '.json'
save_json(event_json, event_filename)
2020-08-13 13:40:38 +00:00
# save to the events timeline
2022-01-02 15:16:47 +00:00
tl_events_filename = base_dir + '/accounts/' + handle + '/events.txt'
2020-08-13 13:40:38 +00:00
2022-01-02 15:16:47 +00:00
if os.path.isfile(tl_events_filename):
_remove_event_from_timeline(event_id, tl_events_filename)
2020-08-13 13:40:38 +00:00
try:
2022-01-02 15:16:47 +00:00
with open(tl_events_filename, 'r+') as tl_events_file:
content = tl_events_file.read()
if event_id + '\n' not in content:
tl_events_file.seek(0, 0)
tl_events_file.write(event_id + '\n' + content)
2021-12-25 15:28:52 +00:00
except OSError as ex:
2021-11-25 22:22:54 +00:00
print('EX: Failed to write entry to events file ' +
2022-01-02 15:16:47 +00:00
tl_events_filename + ' ' + str(ex))
2020-08-13 13:40:38 +00:00
return False
else:
2021-11-25 21:18:53 +00:00
try:
2022-01-02 15:16:47 +00:00
with open(tl_events_filename, 'w+') as tl_events_file:
tl_events_file.write(event_id + '\n')
2021-11-25 21:18:53 +00:00
except OSError:
2022-01-02 15:16:47 +00:00
print('EX: unable to write ' + tl_events_filename)
2020-08-13 11:58:05 +00:00
# create a directory for the calendar year
2022-01-02 15:16:47 +00:00
if not os.path.isdir(calendar_path + '/' + str(event_year)):
os.mkdir(calendar_path + '/' + str(event_year))
2020-08-13 11:58:05 +00:00
# calendar month file containing event post Ids
2022-01-02 15:16:47 +00:00
calendar_filename = calendar_path + '/' + str(event_year) + \
'/' + str(event_month_number) + '.txt'
2020-08-13 11:58:05 +00:00
# Does this event post already exist within the calendar month?
2022-01-02 15:16:47 +00:00
if os.path.isfile(calendar_filename):
if post_id in open(calendar_filename).read():
2020-08-13 11:58:05 +00:00
# Event post already exists
return False
# append the post Id to the file for the calendar month
2021-11-25 21:18:53 +00:00
try:
2022-01-02 15:16:47 +00:00
with open(calendar_filename, 'a+') as calendar_file:
calendar_file.write(post_id + '\n')
2021-11-25 21:18:53 +00:00
except OSError:
2022-01-02 15:16:47 +00:00
print('EX: unable to append ' + calendar_filename)
2020-08-13 11:58:05 +00:00
# create a file which will trigger a notification that
# a new event has been added
2022-01-02 15:16:47 +00:00
cal_notify_filename = base_dir + '/accounts/' + handle + '/.newCalendar'
notify_str = \
'/calendar?year=' + str(event_year) + '?month=' + \
str(event_month_number) + '?day=' + str(event_day_of_month)
2021-11-25 21:18:53 +00:00
try:
2022-01-02 15:16:47 +00:00
with open(cal_notify_filename, 'w+') as cal_file:
cal_file.write(notify_str)
2021-11-25 21:18:53 +00:00
except OSError:
2022-01-02 15:16:47 +00:00
print('EX: unable to write ' + cal_notify_filename)
2021-11-25 21:18:53 +00:00
return False
2020-08-13 11:58:05 +00:00
return True
2021-12-29 21:55:09 +00:00
def _is_happening_event(tag: {}) -> bool:
2020-02-24 11:10:48 +00:00
"""Is this tag an Event or Place ActivityStreams type?
"""
if not tag.get('type'):
return False
2020-04-03 11:53:31 +00:00
if tag['type'] != 'Event' and tag['type'] != 'Place':
2020-02-24 11:10:48 +00:00
return False
return True
2020-04-03 11:53:31 +00:00
2021-12-29 21:55:09 +00:00
def _is_happening_post(post_json_object: {}) -> bool:
2020-02-24 11:10:48 +00:00
"""Is this a post with tags?
"""
2021-12-25 22:09:19 +00:00
if not post_json_object:
2020-02-24 11:10:48 +00:00
return False
2021-12-26 10:57:03 +00:00
if not has_object_dict(post_json_object):
2020-02-24 11:10:48 +00:00
return False
2021-12-25 22:09:19 +00:00
if not post_json_object['object'].get('tag'):
2020-02-24 11:10:48 +00:00
return False
return True
2020-04-03 11:53:31 +00:00
2021-12-29 21:55:09 +00:00
def get_todays_events(base_dir: str, nickname: str, domain: str,
2022-02-21 11:08:48 +00:00
curr_year: int, curr_month_number: int,
2021-12-29 21:55:09 +00:00
currDayOfMonth: int) -> {}:
"""Retrieves calendar events for today
Returns a dictionary of lists containing Event and Place activities
"""
2020-04-03 11:53:31 +00:00
now = datetime.now()
2022-02-21 11:08:48 +00:00
if not curr_year:
2020-04-03 11:53:31 +00:00
year = now.year
else:
2022-02-21 11:08:48 +00:00
year = curr_year
if not curr_month_number:
2022-01-02 15:16:47 +00:00
month_number = now.month
else:
2022-02-21 11:08:48 +00:00
month_number = curr_month_number
if not currDayOfMonth:
2022-01-02 15:16:47 +00:00
day_number = now.day
else:
2022-01-02 15:16:47 +00:00
day_number = currDayOfMonth
2020-02-23 09:45:04 +00:00
2022-01-02 15:16:47 +00:00
calendar_filename = \
2021-12-26 12:02:29 +00:00
acct_dir(base_dir, nickname, domain) + \
2022-01-02 15:16:47 +00:00
'/calendar/' + str(year) + '/' + str(month_number) + '.txt'
2020-04-03 11:53:31 +00:00
events = {}
2022-01-02 15:16:47 +00:00
if not os.path.isfile(calendar_filename):
return events
2020-02-23 09:45:04 +00:00
2022-01-02 15:16:47 +00:00
calendar_post_ids = []
recreate_events_file = False
with open(calendar_filename, 'r') as events_file:
for post_id in events_file:
2021-12-26 19:47:06 +00:00
post_id = post_id.replace('\n', '').replace('\r', '')
2021-12-26 23:41:34 +00:00
post_filename = locate_post(base_dir, nickname, domain, post_id)
if not post_filename:
2022-01-02 15:16:47 +00:00
recreate_events_file = True
2020-02-23 09:49:10 +00:00
continue
2021-12-26 23:41:34 +00:00
post_json_object = load_json(post_filename)
2021-12-29 21:55:09 +00:00
if not _is_happening_post(post_json_object):
2020-02-23 09:49:10 +00:00
continue
2022-01-02 15:16:47 +00:00
public_event = is_public_post(post_json_object)
2022-01-02 15:16:47 +00:00
post_event = []
day_of_month = None
2021-12-25 22:09:19 +00:00
for tag in post_json_object['object']['tag']:
2021-12-29 21:55:09 +00:00
if not _is_happening_event(tag):
continue
2020-02-24 11:10:48 +00:00
# this tag is an event or a place
2020-04-03 11:53:31 +00:00
if tag['type'] == 'Event':
2020-02-23 09:49:10 +00:00
# tag is an event
if not tag.get('startTime'):
continue
2022-01-02 15:16:47 +00:00
event_time = \
2020-04-03 11:53:31 +00:00
datetime.strptime(tag['startTime'],
2020-02-23 09:49:10 +00:00
"%Y-%m-%dT%H:%M:%S%z")
2022-01-02 15:16:47 +00:00
if int(event_time.strftime("%Y")) == year and \
int(event_time.strftime("%m")) == month_number and \
int(event_time.strftime("%d")) == day_number:
day_of_month = str(int(event_time.strftime("%d")))
2021-12-26 19:47:06 +00:00
if '#statuses#' in post_id:
2020-02-24 10:55:49 +00:00
# link to the id so that the event can be
# easily deleted
2021-12-26 19:47:06 +00:00
tag['post_id'] = post_id.split('#statuses#')[1]
tag['sender'] = post_id.split('#statuses#')[0]
2021-03-06 18:38:36 +00:00
tag['sender'] = tag['sender'].replace('#', '/')
2022-01-02 15:16:47 +00:00
tag['public'] = public_event
post_event.append(tag)
2020-02-23 09:49:10 +00:00
else:
# tag is a place
2022-01-02 15:16:47 +00:00
post_event.append(tag)
if post_event and day_of_month:
calendar_post_ids.append(post_id)
if not events.get(day_of_month):
events[day_of_month] = []
events[day_of_month].append(post_event)
# if some posts have been deleted then regenerate the calendar file
2022-01-02 15:16:47 +00:00
if recreate_events_file:
2021-11-25 21:18:53 +00:00
try:
2022-01-02 15:16:47 +00:00
with open(calendar_filename, 'w+') as calendar_file:
for post_id in calendar_post_ids:
calendar_file.write(post_id + '\n')
2021-11-25 21:18:53 +00:00
except OSError:
2022-01-02 15:16:47 +00:00
print('EX: unable to write ' + calendar_filename)
return events
2020-04-03 11:53:31 +00:00
2022-02-21 11:08:48 +00:00
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 = \
'<a href="' + sender_actor + '">' + \
disp_name + '</a>: '
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' + \
2022-02-21 11:45:29 +00:00
'PRODID:-//Fediverse//NONSGML Epicyon//EN\n' + \
'VERSION:2.0\n'
2022-02-21 11:08:48 +00:00
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
2021-12-29 21:55:09 +00:00
def day_events_check(base_dir: str, nickname: str, domain: str,
2022-02-21 11:08:48 +00:00
curr_date) -> bool:
2021-05-31 11:57:36 +00:00
"""Are there calendar events for the given date?
"""
2022-02-21 11:08:48 +00:00
year = curr_date.year
month_number = curr_date.month
day_number = curr_date.day
2020-04-03 11:53:31 +00:00
2022-01-02 15:16:47 +00:00
calendar_filename = \
2021-12-26 12:02:29 +00:00
acct_dir(base_dir, nickname, domain) + \
2022-01-02 15:16:47 +00:00
'/calendar/' + str(year) + '/' + str(month_number) + '.txt'
if not os.path.isfile(calendar_filename):
return False
2020-02-23 09:45:04 +00:00
2022-01-02 15:16:47 +00:00
events_exist = False
with open(calendar_filename, 'r') as events_file:
for post_id in events_file:
2021-12-26 19:47:06 +00:00
post_id = post_id.replace('\n', '').replace('\r', '')
2021-12-26 23:41:34 +00:00
post_filename = locate_post(base_dir, nickname, domain, post_id)
if not post_filename:
2020-02-23 09:49:10 +00:00
continue
2021-12-26 23:41:34 +00:00
post_json_object = load_json(post_filename)
2021-12-29 21:55:09 +00:00
if not _is_happening_post(post_json_object):
2020-02-23 09:49:10 +00:00
continue
2021-12-25 22:09:19 +00:00
for tag in post_json_object['object']['tag']:
2021-12-29 21:55:09 +00:00
if not _is_happening_event(tag):
continue
2020-02-24 11:10:48 +00:00
# this tag is an event or a place
2020-04-03 11:53:31 +00:00
if tag['type'] != 'Event':
continue
2020-02-24 11:10:48 +00:00
# tag is an event
if not tag.get('startTime'):
continue
2022-01-02 15:16:47 +00:00
event_time = \
2020-04-03 11:53:31 +00:00
datetime.strptime(tag['startTime'],
2020-02-24 11:10:48 +00:00
"%Y-%m-%dT%H:%M:%S%z")
2022-01-02 15:16:47 +00:00
if int(event_time.strftime("%d")) != day_number:
2021-05-31 10:24:48 +00:00
continue
2022-01-02 15:16:47 +00:00
if int(event_time.strftime("%m")) != month_number:
2021-05-31 10:24:48 +00:00
continue
2022-01-02 15:16:47 +00:00
if int(event_time.strftime("%Y")) != year:
2021-05-31 10:24:48 +00:00
continue
2022-01-02 15:16:47 +00:00
events_exist = True
2021-05-31 10:24:48 +00:00
break
2022-01-02 15:16:47 +00:00
return events_exist
2020-04-03 11:53:31 +00:00
2021-12-29 21:55:09 +00:00
def get_this_weeks_events(base_dir: str, nickname: str, domain: str) -> {}:
"""Retrieves calendar events for this week
2020-02-24 10:55:49 +00:00
Returns a dictionary indexed by day number of lists containing
Event and Place activities
2020-02-23 09:42:09 +00:00
Note: currently not used but could be with a weekly calendar screen
"""
2020-04-03 11:53:31 +00:00
now = datetime.now()
2022-01-02 15:16:47 +00:00
end_of_week = now + timedelta(7)
2020-04-03 11:53:31 +00:00
year = now.year
2022-01-02 15:16:47 +00:00
month_number = now.month
2020-02-23 09:45:04 +00:00
2022-01-02 15:16:47 +00:00
calendar_filename = \
2021-12-26 12:02:29 +00:00
acct_dir(base_dir, nickname, domain) + \
2022-01-02 15:16:47 +00:00
'/calendar/' + str(year) + '/' + str(month_number) + '.txt'
2020-02-23 09:45:04 +00:00
2020-04-03 11:53:31 +00:00
events = {}
2022-01-02 15:16:47 +00:00
if not os.path.isfile(calendar_filename):
return events
2020-02-23 09:45:04 +00:00
2022-01-02 15:16:47 +00:00
calendar_post_ids = []
recreate_events_file = False
with open(calendar_filename, 'r') as events_file:
for post_id in events_file:
2021-12-26 19:47:06 +00:00
post_id = post_id.replace('\n', '').replace('\r', '')
2021-12-26 23:41:34 +00:00
post_filename = locate_post(base_dir, nickname, domain, post_id)
if not post_filename:
2022-01-02 15:16:47 +00:00
recreate_events_file = True
2020-02-23 09:49:10 +00:00
continue
2021-12-26 23:41:34 +00:00
post_json_object = load_json(post_filename)
2021-12-29 21:55:09 +00:00
if not _is_happening_post(post_json_object):
2020-02-23 09:49:10 +00:00
continue
2022-01-02 15:16:47 +00:00
post_event = []
week_day_index = None
2021-12-25 22:09:19 +00:00
for tag in post_json_object['object']['tag']:
2021-12-29 21:55:09 +00:00
if not _is_happening_event(tag):
continue
2020-02-24 11:10:48 +00:00
# this tag is an event or a place
2020-04-03 11:53:31 +00:00
if tag['type'] == 'Event':
2020-02-23 09:49:10 +00:00
# tag is an event
if not tag.get('startTime'):
continue
2022-01-02 15:16:47 +00:00
event_time = \
2020-04-03 11:53:31 +00:00
datetime.strptime(tag['startTime'],
2020-02-23 09:49:10 +00:00
"%Y-%m-%dT%H:%M:%S%z")
2022-01-02 15:16:47 +00:00
if event_time >= now and event_time <= end_of_week:
week_day_index = (event_time - now).days()
post_event.append(tag)
2020-02-23 09:49:10 +00:00
else:
# tag is a place
2022-01-02 15:16:47 +00:00
post_event.append(tag)
if post_event and week_day_index:
calendar_post_ids.append(post_id)
if not events.get(week_day_index):
events[week_day_index] = []
events[week_day_index].append(post_event)
# if some posts have been deleted then regenerate the calendar file
2022-01-02 15:16:47 +00:00
if recreate_events_file:
2021-11-25 21:18:53 +00:00
try:
2022-01-02 15:16:47 +00:00
with open(calendar_filename, 'w+') as calendar_file:
for post_id in calendar_post_ids:
calendar_file.write(post_id + '\n')
2021-11-25 21:18:53 +00:00
except OSError:
2022-01-02 15:16:47 +00:00
print('EX: unable to write ' + calendar_filename)
return events
2020-04-03 11:53:31 +00:00
2021-12-29 21:55:09 +00:00
def get_calendar_events(base_dir: str, nickname: str, domain: str,
2022-01-02 15:16:47 +00:00
year: int, month_number: int) -> {}:
"""Retrieves calendar events
2020-02-24 10:55:49 +00:00
Returns a dictionary indexed by day number of lists containing
Event and Place activities
"""
2022-01-02 15:16:47 +00:00
calendar_filename = \
2021-12-26 12:02:29 +00:00
acct_dir(base_dir, nickname, domain) + \
2022-01-02 15:16:47 +00:00
'/calendar/' + str(year) + '/' + str(month_number) + '.txt'
2020-02-23 09:45:04 +00:00
2020-04-03 11:53:31 +00:00
events = {}
2022-01-02 15:16:47 +00:00
if not os.path.isfile(calendar_filename):
return events
2020-02-23 09:45:04 +00:00
2022-01-02 15:16:47 +00:00
calendar_post_ids = []
recreate_events_file = False
with open(calendar_filename, 'r') as events_file:
for post_id in events_file:
2021-12-26 19:47:06 +00:00
post_id = post_id.replace('\n', '').replace('\r', '')
2021-12-26 23:41:34 +00:00
post_filename = locate_post(base_dir, nickname, domain, post_id)
if not post_filename:
2022-01-02 15:16:47 +00:00
recreate_events_file = True
2020-02-23 09:42:09 +00:00
continue
2020-02-24 11:10:48 +00:00
2021-12-26 23:41:34 +00:00
post_json_object = load_json(post_filename)
2021-12-29 21:55:09 +00:00
if not _is_happening_post(post_json_object):
2020-02-23 09:42:09 +00:00
continue
2022-01-02 15:16:47 +00:00
post_event = []
day_of_month = None
2021-12-25 22:09:19 +00:00
for tag in post_json_object['object']['tag']:
2021-12-29 21:55:09 +00:00
if not _is_happening_event(tag):
2020-02-23 09:42:09 +00:00
continue
2020-02-24 11:10:48 +00:00
# this tag is an event or a place
2020-04-03 11:53:31 +00:00
if tag['type'] == 'Event':
2020-02-23 09:42:09 +00:00
# tag is an event
if not tag.get('startTime'):
continue
2022-01-02 15:16:47 +00:00
event_time = \
2020-04-03 11:53:31 +00:00
datetime.strptime(tag['startTime'],
2020-02-23 09:42:09 +00:00
"%Y-%m-%dT%H:%M:%S%z")
2022-01-02 15:16:47 +00:00
if int(event_time.strftime("%Y")) == year and \
int(event_time.strftime("%m")) == month_number:
day_of_month = str(int(event_time.strftime("%d")))
post_event.append(tag)
2020-02-23 09:42:09 +00:00
else:
# tag is a place
2022-01-02 15:16:47 +00:00
post_event.append(tag)
2020-02-23 09:42:09 +00:00
2022-01-02 15:16:47 +00:00
if post_event and day_of_month:
calendar_post_ids.append(post_id)
if not events.get(day_of_month):
events[day_of_month] = []
events[day_of_month].append(post_event)
# if some posts have been deleted then regenerate the calendar file
2022-01-02 15:16:47 +00:00
if recreate_events_file:
2021-11-25 21:18:53 +00:00
try:
2022-01-02 15:16:47 +00:00
with open(calendar_filename, 'w+') as calendar_file:
for post_id in calendar_post_ids:
calendar_file.write(post_id + '\n')
2021-11-25 21:18:53 +00:00
except OSError:
2022-01-02 15:16:47 +00:00
print('EX: unable to write ' + calendar_filename)
2020-03-22 21:16:02 +00:00
return events
2020-02-23 13:28:27 +00:00
2020-04-03 11:53:31 +00:00
2021-12-29 21:55:09 +00:00
def remove_calendar_event(base_dir: str, nickname: str, domain: str,
2022-01-02 15:16:47 +00:00
year: int, month_number: int,
message_id: str) -> None:
2020-02-23 13:28:27 +00:00
"""Removes a calendar event
"""
2022-01-02 15:16:47 +00:00
calendar_filename = \
2021-12-26 12:02:29 +00:00
acct_dir(base_dir, nickname, domain) + \
2022-01-02 15:16:47 +00:00
'/calendar/' + str(year) + '/' + str(month_number) + '.txt'
if not os.path.isfile(calendar_filename):
2020-02-23 13:28:27 +00:00
return
2022-01-02 15:16:47 +00:00
if '/' in message_id:
message_id = message_id.replace('/', '#')
if message_id not in open(calendar_filename).read():
2020-02-23 13:28:27 +00:00
return
2020-04-03 11:53:31 +00:00
lines = None
2022-01-02 15:16:47 +00:00
with open(calendar_filename, 'r') as fp_cal:
lines = fp_cal.readlines()
2020-02-23 13:28:27 +00:00
if not lines:
return
2021-11-25 21:18:53 +00:00
try:
2022-01-02 15:16:47 +00:00
with open(calendar_filename, 'w+') as fp_cal:
2021-11-25 21:18:53 +00:00
for line in lines:
2022-01-02 15:16:47 +00:00
if message_id not in line:
fp_cal.write(line)
2021-11-25 21:18:53 +00:00
except OSError:
2022-01-02 15:16:47 +00:00
print('EX: unable to write ' + calendar_filename)