' not in xml_str:
return None
response_str = \
'\n' + \
' \n' + \
' /calendars/' + nickname + '/\n' + \
' \n' + \
' \n' + \
' \n' + \
' \n' + \
' \n' + \
' HTTP/1.1 200 OK\n' + \
' \n' + \
' \n' + \
''
return response_str
def _dav_store_event(base_dir: str, nickname: str, domain: str,
event_list: [], http_prefix: str,
system_language: str) -> bool:
"""Stores a calendar event obtained via caldav PUT
"""
event_str = str(event_list)
if 'DTSTAMP:' not in event_str or \
'DTSTART:' not in event_str or \
'DTEND:' not in event_str:
return False
if 'STATUS:' not in event_str and 'DESCRIPTION:' not in event_str:
return False
timestamp = None
start_time = None
end_time = None
description = None
for line in event_list:
if line.startswith('DTSTAMP:'):
timestamp = line.split(':', 1)[1]
elif line.startswith('DTSTART:'):
start_time = line.split(':', 1)[1]
elif line.startswith('DTEND:'):
end_time = line.split(':', 1)[1]
elif line.startswith('SUMMARY:') or line.startswith('DESCRIPTION:'):
description = line.split(':', 1)[1]
elif line.startswith('LOCATION:'):
location = line.split(':', 1)[1]
if not timestamp or \
not start_time or \
not end_time or \
not description:
return False
if len(timestamp) < 15:
return False
if len(start_time) < 15:
return False
if len(end_time) < 15:
return False
# check that the description is valid
if is_filtered(base_dir, nickname, domain, description):
return False
# convert to the expected time format
timestamp_year = timestamp[:4]
timestamp_month = timestamp[4:][:2]
timestamp_day = timestamp[6:][:2]
timestamp_hour = timestamp[9:][:2]
timestamp_min = timestamp[11:][:2]
timestamp_sec = timestamp[13:][:2]
if not timestamp_year.isdigit() or \
not timestamp_month.isdigit() or \
not timestamp_day.isdigit() or \
not timestamp_hour.isdigit() or \
not timestamp_min.isdigit() or \
not timestamp_sec.isdigit():
return False
if int(timestamp_year) < 2020 or int(timestamp_year) > 2100:
return False
published = \
timestamp_year + '-' + timestamp_month + '-' + timestamp_day + 'T' + \
timestamp_hour + ':' + timestamp_min + ':' + timestamp_sec + 'Z'
start_time_year = start_time[:4]
start_time_month = start_time[4:][:2]
start_time_day = start_time[6:][:2]
start_time_hour = start_time[9:][:2]
start_time_min = start_time[11:][:2]
start_time_sec = start_time[13:][:2]
if not start_time_year.isdigit() or \
not start_time_month.isdigit() or \
not start_time_day.isdigit() or \
not start_time_hour.isdigit() or \
not start_time_min.isdigit() or \
not start_time_sec.isdigit():
return False
if int(start_time_year) < 2020 or int(start_time_year) > 2100:
return False
start_time = \
start_time_year + '-' + start_time_month + '-' + \
start_time_day + 'T' + \
start_time_hour + ':' + start_time_min + ':' + start_time_sec + 'Z'
end_time_year = end_time[:4]
end_time_month = end_time[4:][:2]
end_time_day = end_time[6:][:2]
end_time_hour = end_time[9:][:2]
end_time_min = end_time[11:][:2]
end_time_sec = end_time[13:][:2]
if not end_time_year.isdigit() or \
not end_time_month.isdigit() or \
not end_time_day.isdigit() or \
not end_time_hour.isdigit() or \
not end_time_min.isdigit() or \
not end_time_sec.isdigit():
return False
if int(end_time_year) < 2020 or int(end_time_year) > 2100:
return False
end_time = \
end_time_year + '-' + end_time_month + '-' + end_time_day + 'T' + \
end_time_hour + ':' + end_time_min + ':' + end_time_sec + 'Z'
post_id = ''
post_context = get_individual_post_context()
# create the status number from DTSTAMP
status_number, published = get_status_number(published)
# get the post id
actor = http_prefix + "://" + domain + "/users/" + nickname
actor2 = http_prefix + "://" + domain + "/@" + nickname
post_id = actor + "/statuses/" + status_number
next_str = post_id + "/replies?only_other_accounts=true&page=true"
content = \
'@' + nickname + \
'' + remove_html(description) + '
'
event_json = {
"@context": post_context,
"id": post_id + "/activity",
"type": "Create",
"actor": actor,
"published": published,
"to": [actor],
"cc": [],
"object": {
"id": post_id,
"conversation": post_id,
"type": "Note",
"summary": None,
"inReplyTo": None,
"published": published,
"url": actor + "/" + status_number,
"attributedTo": actor,
"to": [actor],
"cc": [],
"sensitive": False,
"atomUri": post_id,
"inReplyToAtomUri": None,
"commentsEnabled": False,
"rejectReplies": True,
"mediaType": "text/html",
"content": content,
"contentMap": {
system_language: content
},
"attachment": [],
"tag": [
{
"href": actor2,
"name": "@" + nickname + "@" + domain,
"type": "Mention"
},
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Event",
"name": content,
"startTime": start_time,
"endTime": end_time
}
],
"replies": {
"id": post_id + "/replies",
"type": "Collection",
"first": {
"type": "CollectionPage",
"next": next_str,
"partOf": post_id + "/replies",
"items": []
}
}
}
}
if location:
event_json['object']['tag'].append({
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Place",
"name": location
})
handle = nickname + '@' + domain
outbox_dir = base_dir + '/accounts/' + handle + '/outbox'
if not os.path.isdir(outbox_dir):
return False
filename = outbox_dir + '/' + post_id.replace('/', '#') + '.json'
save_json(event_json, filename)
save_event_post(base_dir, handle, post_id, event_json)
return True
def dav_put_response(base_dir: str, nickname: str, domain: str,
depth: int, xml_str: str, http_prefix: str,
system_language: str) -> str:
"""Returns the response to caldav PUT
"""
if '\n' not in xml_str:
return None
if 'BEGIN:VCALENDAR' not in xml_str or \
'END:VCALENDAR' not in xml_str:
return None
if 'BEGIN:VEVENT' not in xml_str or \
'END:VEVENT' not in xml_str:
return None
stored_count = 0
reading_event = False
lines_list = xml_str.split('\n')
event_list = []
for line in lines_list:
line = line.strip()
if not reading_event:
if line == 'BEGIN:VEVENT':
reading_event = True
event_list = []
else:
if line == 'END:VEVENT':
if event_list:
_dav_store_event(base_dir, nickname, domain,
event_list, http_prefix,
system_language)
stored_count += 1
reading_event = False
else:
event_list.append(line)
if stored_count == 0:
return None
return 'Ok'
def dav_report_response(base_dir: str, nickname: str, domain: str,
depth: int, xml_str: str) -> str:
"""Returns the response to caldav REPORT
"""
if '' not in xml_str:
if '' not in xml_str:
return None
# TODO
return None
def dav_delete_response(base_dir: str, nickname: str, domain: str,
depth: int, path: str,
http_prefix: str, debug: bool,
recent_posts_cache: {}) -> str:
"""Returns the response to caldav DELETE
"""
token = path.split('/calendars/' + nickname + '/')[1]
token_year, token_month_number, token_post_id = \
_dav_decode_token(token)
if not token_year:
return None
post_filename = locate_post(base_dir, nickname, domain, token_post_id)
if not post_filename:
print('Calendar post not found ' + token_post_id)
return None
post_json_object = load_json(post_filename)
if not _is_happening_post(post_json_object):
print(token_post_id + ' is not a calendar post')
return None
remove_calendar_event(base_dir, nickname, domain,
token_year, token_month_number,
token_post_id)
delete_post(base_dir, http_prefix,
nickname, domain, post_filename,
debug, recent_posts_cache)
return 'Ok'