mirror of https://gitlab.com/bashrc2/epicyon
Merge branch 'main' of gitlab.com:bashrc2/epicyon
commit
e26c1b2b56
|
@ -372,3 +372,19 @@ To remove a shared item:
|
||||||
``` bash
|
``` bash
|
||||||
python3 epicyon.py --undoItemName "spanner" --nickname [yournick] --domain [yourdomain] --password [c2s password]
|
python3 epicyon.py --undoItemName "spanner" --nickname [yournick] --domain [yourdomain] --password [c2s password]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Calendar
|
||||||
|
|
||||||
|
The calendar for each account can be accessed via CalDav (RFC4791). This makes it easy to integrate the social calendar into other applications. For example, to obtain events for a month:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 epicyon.py --dav --nickname [yournick] --domain [yourdomain] --year [year] --month [month number]
|
||||||
|
```
|
||||||
|
|
||||||
|
You will be prompted for your login password, or you can use the **--password** option. You can also use the **--day** option to obtain events for a particular day.
|
||||||
|
|
||||||
|
The CalDav endpoint for an account is:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yourdomain/calendars/yournick
|
||||||
|
```
|
||||||
|
|
9
auth.py
9
auth.py
|
@ -94,10 +94,19 @@ def authorize_basic(base_dir: str, path: str, auth_header: str,
|
||||||
'contain a space character')
|
'contain a space character')
|
||||||
return False
|
return False
|
||||||
if not has_users_path(path):
|
if not has_users_path(path):
|
||||||
|
if not path.startswith('/calendars/'):
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: basic auth - ' +
|
print('DEBUG: basic auth - ' +
|
||||||
'path for Authorization does not contain a user')
|
'path for Authorization does not contain a user')
|
||||||
return False
|
return False
|
||||||
|
if path.startswith('/calendars/'):
|
||||||
|
path_users_section = path.split('/calendars/')[1]
|
||||||
|
nickname_from_path = path_users_section
|
||||||
|
if '/' in nickname_from_path:
|
||||||
|
nickname_from_path = nickname_from_path.split('/')[0]
|
||||||
|
if '?' in nickname_from_path:
|
||||||
|
nickname_from_path = nickname_from_path.split('?')[0]
|
||||||
|
else:
|
||||||
path_users_section = path.split('/users/')[1]
|
path_users_section = path.split('/users/')[1]
|
||||||
if '/' not in path_users_section:
|
if '/' not in path_users_section:
|
||||||
if debug:
|
if debug:
|
||||||
|
|
85
daemon.py
85
daemon.py
|
@ -949,7 +949,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
|
|
||||||
def _http_return_code(self, http_code: int, http_description: str,
|
def _http_return_code(self, http_code: int, http_description: str,
|
||||||
long_description: str) -> None:
|
long_description: str, etag: str) -> None:
|
||||||
msg = \
|
msg = \
|
||||||
'<html><head><title>' + str(http_code) + '</title></head>' \
|
'<html><head><title>' + str(http_code) + '</title></head>' \
|
||||||
'<body bgcolor="linen" text="black">' \
|
'<body bgcolor="linen" text="black">' \
|
||||||
|
@ -965,6 +965,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.send_header('Content-Type', 'text/html; charset=utf-8')
|
self.send_header('Content-Type', 'text/html; charset=utf-8')
|
||||||
msg_len_str = str(len(msg))
|
msg_len_str = str(len(msg))
|
||||||
self.send_header('Content-Length', msg_len_str)
|
self.send_header('Content-Length', msg_len_str)
|
||||||
|
if etag:
|
||||||
|
self.send_header('ETag', etag)
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
if not self._write(msg):
|
if not self._write(msg):
|
||||||
print('Error when showing ' + str(http_code))
|
print('Error when showing ' + str(http_code))
|
||||||
|
@ -973,71 +975,77 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
if self.server.translate:
|
if self.server.translate:
|
||||||
ok_str = self.server.translate['This is nothing ' +
|
ok_str = self.server.translate['This is nothing ' +
|
||||||
'less than an utter triumph']
|
'less than an utter triumph']
|
||||||
self._http_return_code(200, self.server.translate['Ok'], ok_str)
|
self._http_return_code(200, self.server.translate['Ok'],
|
||||||
|
ok_str, None)
|
||||||
else:
|
else:
|
||||||
self._http_return_code(200, 'Ok',
|
self._http_return_code(200, 'Ok',
|
||||||
'This is nothing less ' +
|
'This is nothing less ' +
|
||||||
'than an utter triumph')
|
'than an utter triumph', None)
|
||||||
|
|
||||||
def _201(self) -> None:
|
def _201(self, etag: str) -> None:
|
||||||
if self.server.translate:
|
if self.server.translate:
|
||||||
ok_str = self.server.translate['Done']
|
done_str = self.server.translate['It is done']
|
||||||
self._http_return_code(201,
|
self._http_return_code(201,
|
||||||
self.server.translate['Created'], ok_str)
|
self.server.translate['Created'], done_str,
|
||||||
|
etag)
|
||||||
else:
|
else:
|
||||||
self._http_return_code(201, 'Created',
|
self._http_return_code(201, 'Created', 'It is done', etag)
|
||||||
'Done')
|
|
||||||
|
|
||||||
def _207(self) -> None:
|
def _207(self) -> None:
|
||||||
if self.server.translate:
|
if self.server.translate:
|
||||||
multi_str = self.server.translate['Lots of things']
|
multi_str = self.server.translate['Lots of things']
|
||||||
self._http_return_code(207,
|
self._http_return_code(207,
|
||||||
self.server.translate['Multi Status'],
|
self.server.translate['Multi Status'],
|
||||||
multi_str)
|
multi_str, None)
|
||||||
else:
|
else:
|
||||||
self._http_return_code(207, 'Multi Status',
|
self._http_return_code(207, 'Multi Status',
|
||||||
'Lots of things')
|
'Lots of things', None)
|
||||||
|
|
||||||
def _403(self) -> None:
|
def _403(self) -> None:
|
||||||
if self.server.translate:
|
if self.server.translate:
|
||||||
self._http_return_code(403, self.server.translate['Forbidden'],
|
self._http_return_code(403, self.server.translate['Forbidden'],
|
||||||
self.server.translate["You're not allowed"])
|
self.server.translate["You're not allowed"],
|
||||||
|
None)
|
||||||
else:
|
else:
|
||||||
self._http_return_code(403, 'Forbidden',
|
self._http_return_code(403, 'Forbidden',
|
||||||
"You're not allowed")
|
"You're not allowed", None)
|
||||||
|
|
||||||
def _404(self) -> None:
|
def _404(self) -> None:
|
||||||
if self.server.translate:
|
if self.server.translate:
|
||||||
self._http_return_code(404, self.server.translate['Not Found'],
|
self._http_return_code(404, self.server.translate['Not Found'],
|
||||||
self.server.translate['These are not the ' +
|
self.server.translate['These are not the ' +
|
||||||
'droids you are ' +
|
'droids you are ' +
|
||||||
'looking for'])
|
'looking for'],
|
||||||
|
None)
|
||||||
else:
|
else:
|
||||||
self._http_return_code(404, 'Not Found',
|
self._http_return_code(404, 'Not Found',
|
||||||
'These are not the ' +
|
'These are not the ' +
|
||||||
'droids you are ' +
|
'droids you are ' +
|
||||||
'looking for')
|
'looking for', None)
|
||||||
|
|
||||||
def _304(self) -> None:
|
def _304(self) -> None:
|
||||||
if self.server.translate:
|
if self.server.translate:
|
||||||
self._http_return_code(304, self.server.translate['Not changed'],
|
self._http_return_code(304, self.server.translate['Not changed'],
|
||||||
self.server.translate['The contents of ' +
|
self.server.translate['The contents of ' +
|
||||||
'your local cache ' +
|
'your local cache ' +
|
||||||
'are up to date'])
|
'are up to date'],
|
||||||
|
None)
|
||||||
else:
|
else:
|
||||||
self._http_return_code(304, 'Not changed',
|
self._http_return_code(304, 'Not changed',
|
||||||
'The contents of ' +
|
'The contents of ' +
|
||||||
'your local cache ' +
|
'your local cache ' +
|
||||||
'are up to date')
|
'are up to date',
|
||||||
|
None)
|
||||||
|
|
||||||
def _400(self) -> None:
|
def _400(self) -> None:
|
||||||
if self.server.translate:
|
if self.server.translate:
|
||||||
self._http_return_code(400, self.server.translate['Bad Request'],
|
self._http_return_code(400, self.server.translate['Bad Request'],
|
||||||
self.server.translate['Better luck ' +
|
self.server.translate['Better luck ' +
|
||||||
'next time'])
|
'next time'],
|
||||||
|
None)
|
||||||
else:
|
else:
|
||||||
self._http_return_code(400, 'Bad Request',
|
self._http_return_code(400, 'Bad Request',
|
||||||
'Better luck next time')
|
'Better luck next time', None)
|
||||||
|
|
||||||
def _503(self) -> None:
|
def _503(self) -> None:
|
||||||
if self.server.translate:
|
if self.server.translate:
|
||||||
|
@ -1045,11 +1053,11 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.translate['The server is busy. ' +
|
self.server.translate['The server is busy. ' +
|
||||||
'Please try again later']
|
'Please try again later']
|
||||||
self._http_return_code(503, self.server.translate['Unavailable'],
|
self._http_return_code(503, self.server.translate['Unavailable'],
|
||||||
busy_str)
|
busy_str, None)
|
||||||
else:
|
else:
|
||||||
self._http_return_code(503, 'Unavailable',
|
self._http_return_code(503, 'Unavailable',
|
||||||
'The server is busy. Please try again ' +
|
'The server is busy. Please try again ' +
|
||||||
'later')
|
'later', None)
|
||||||
|
|
||||||
def _write(self, msg) -> bool:
|
def _write(self, msg) -> bool:
|
||||||
tries = 0
|
tries = 0
|
||||||
|
@ -16824,13 +16832,15 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
'_GET', 'end benchmarks',
|
'_GET', 'end benchmarks',
|
||||||
self.server.debug)
|
self.server.debug)
|
||||||
|
|
||||||
def _dav_handler(self, endpoint_type: str):
|
def _dav_handler(self, endpoint_type: str, debug: bool):
|
||||||
calling_domain = self.server.domain_full
|
calling_domain = self.server.domain_full
|
||||||
if not self._has_accept(calling_domain):
|
if not self._has_accept(calling_domain):
|
||||||
self._400()
|
self._400()
|
||||||
return
|
return
|
||||||
accept_str = self.headers['Accept']
|
accept_str = self.headers['Accept']
|
||||||
if 'application/xml' not in accept_str:
|
if 'application/xml' not in accept_str:
|
||||||
|
if debug:
|
||||||
|
print(endpoint_type.upper() + ' is not of xml type')
|
||||||
self._400()
|
self._400()
|
||||||
return
|
return
|
||||||
if not self.headers.get('Content-length'):
|
if not self.headers.get('Content-length'):
|
||||||
|
@ -16847,8 +16857,10 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
print(endpoint_type.upper() + ' without /calendars ' + self.path)
|
print(endpoint_type.upper() + ' without /calendars ' + self.path)
|
||||||
self._404()
|
self._404()
|
||||||
return
|
return
|
||||||
|
if debug:
|
||||||
|
print(endpoint_type.upper() + ' checking authorization')
|
||||||
if not self._is_authorized():
|
if not self._is_authorized():
|
||||||
print('PROPFIND Not authorized')
|
print(endpoint_type.upper() + ' not authorized')
|
||||||
self._403()
|
self._403()
|
||||||
return
|
return
|
||||||
nickname = self.path.split('/calendars/')[1]
|
nickname = self.path.split('/calendars/')[1]
|
||||||
|
@ -16869,9 +16881,10 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
propfind_bytes = self.rfile.read(length)
|
propfind_bytes = self.rfile.read(length)
|
||||||
except SocketError as ex:
|
except SocketError as ex:
|
||||||
if ex.errno == errno.ECONNRESET:
|
if ex.errno == errno.ECONNRESET:
|
||||||
print('EX: PROPFIND connection reset by peer')
|
print('EX: ' + endpoint_type.upper() +
|
||||||
|
' connection reset by peer')
|
||||||
else:
|
else:
|
||||||
print('EX: PROPFIND socket error')
|
print('EX: ' + endpoint_type.upper() + ' socket error')
|
||||||
self._400()
|
self._400()
|
||||||
return
|
return
|
||||||
except ValueError as ex:
|
except ValueError as ex:
|
||||||
|
@ -16898,7 +16911,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
nickname, self.server.domain,
|
nickname, self.server.domain,
|
||||||
depth, propfind_xml,
|
depth, propfind_xml,
|
||||||
self.server.http_prefix,
|
self.server.http_prefix,
|
||||||
self.server.system_language)
|
self.server.system_language,
|
||||||
|
self.server.recent_dav_etags)
|
||||||
elif endpoint_type == 'report':
|
elif endpoint_type == 'report':
|
||||||
curr_etag = None
|
curr_etag = None
|
||||||
if self.headers.get('ETag'):
|
if self.headers.get('ETag'):
|
||||||
|
@ -16912,6 +16926,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.person_cache,
|
self.server.person_cache,
|
||||||
self.server.http_prefix,
|
self.server.http_prefix,
|
||||||
curr_etag,
|
curr_etag,
|
||||||
|
self.server.recent_dav_etags,
|
||||||
self.server.domain_full)
|
self.server.domain_full)
|
||||||
elif endpoint_type == 'delete':
|
elif endpoint_type == 'delete':
|
||||||
response_str = \
|
response_str = \
|
||||||
|
@ -16925,7 +16940,13 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self._404()
|
self._404()
|
||||||
return
|
return
|
||||||
if response_str == 'Not modified':
|
if response_str == 'Not modified':
|
||||||
|
if endpoint_type == 'put':
|
||||||
|
return self._200()
|
||||||
|
else:
|
||||||
return self._304()
|
return self._304()
|
||||||
|
elif response_str.startswith('ETag:') and endpoint_type == 'put':
|
||||||
|
response_etag = response_str.split('ETag:', 1)[1]
|
||||||
|
self._201(response_etag)
|
||||||
elif response_str != 'Ok':
|
elif response_str != 'Ok':
|
||||||
message_xml = response_str.encode('utf-8')
|
message_xml = response_str.encode('utf-8')
|
||||||
message_xml_len = len(message_xml)
|
message_xml_len = len(message_xml)
|
||||||
|
@ -16935,22 +16956,19 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self._write(message_xml)
|
self._write(message_xml)
|
||||||
if 'multistatus' in response_str:
|
if 'multistatus' in response_str:
|
||||||
return self._207()
|
return self._207()
|
||||||
if endpoint_type == 'put':
|
|
||||||
self._201()
|
|
||||||
else:
|
|
||||||
self._200()
|
self._200()
|
||||||
|
|
||||||
def do_PROPFIND(self):
|
def do_PROPFIND(self):
|
||||||
self._dav_handler('propfind')
|
self._dav_handler('propfind', self.server.debug)
|
||||||
|
|
||||||
def do_PUT(self):
|
def do_PUT(self):
|
||||||
self._dav_handler('put')
|
self._dav_handler('put', self.server.debug)
|
||||||
|
|
||||||
def do_REPORT(self):
|
def do_REPORT(self):
|
||||||
self._dav_handler('report')
|
self._dav_handler('report', self.server.debug)
|
||||||
|
|
||||||
def do_DELETE(self):
|
def do_DELETE(self):
|
||||||
self._dav_handler('delete')
|
self._dav_handler('delete', self.server.debug)
|
||||||
|
|
||||||
def do_HEAD(self):
|
def do_HEAD(self):
|
||||||
calling_domain = self.server.domain_full
|
calling_domain = self.server.domain_full
|
||||||
|
@ -19274,6 +19292,9 @@ def run_daemon(dyslexic_font: bool,
|
||||||
default_reply_interval_hrs = 9999999
|
default_reply_interval_hrs = 9999999
|
||||||
httpd.default_reply_interval_hrs = default_reply_interval_hrs
|
httpd.default_reply_interval_hrs = default_reply_interval_hrs
|
||||||
|
|
||||||
|
# recent caldav etags for each account
|
||||||
|
httpd.recent_dav_etags = {}
|
||||||
|
|
||||||
httpd.key_shortcuts = {}
|
httpd.key_shortcuts = {}
|
||||||
load_access_keys_for_accounts(base_dir, httpd.key_shortcuts,
|
load_access_keys_for_accounts(base_dir, httpd.key_shortcuts,
|
||||||
httpd.access_keys)
|
httpd.access_keys)
|
||||||
|
|
|
@ -466,6 +466,9 @@ def _desktop_reply_to_post(session, post_id: str,
|
||||||
comments_enabled = True
|
comments_enabled = True
|
||||||
city = 'London, England'
|
city = 'London, England'
|
||||||
say_str = 'Sending reply'
|
say_str = 'Sending reply'
|
||||||
|
event_date = None
|
||||||
|
event_time = None
|
||||||
|
location = None
|
||||||
_say_command(say_str, say_str, screenreader, system_language, espeak)
|
_say_command(say_str, say_str, screenreader, system_language, espeak)
|
||||||
if send_post_via_server(signing_priv_key_pem, __version__,
|
if send_post_via_server(signing_priv_key_pem, __version__,
|
||||||
base_dir, session, nickname, password,
|
base_dir, session, nickname, password,
|
||||||
|
@ -477,6 +480,7 @@ def _desktop_reply_to_post(session, post_id: str,
|
||||||
cached_webfingers, person_cache, is_article,
|
cached_webfingers, person_cache, is_article,
|
||||||
system_language, languages_understood,
|
system_language, languages_understood,
|
||||||
low_bandwidth, content_license_url,
|
low_bandwidth, content_license_url,
|
||||||
|
event_date, event_time, location,
|
||||||
debug, post_id, post_id,
|
debug, post_id, post_id,
|
||||||
conversation_id, subject) == 0:
|
conversation_id, subject) == 0:
|
||||||
say_str = 'Reply sent'
|
say_str = 'Reply sent'
|
||||||
|
@ -535,6 +539,9 @@ def _desktop_new_post(session,
|
||||||
comments_enabled = True
|
comments_enabled = True
|
||||||
subject = None
|
subject = None
|
||||||
say_str = 'Sending'
|
say_str = 'Sending'
|
||||||
|
event_date = None
|
||||||
|
event_time = None
|
||||||
|
location = None
|
||||||
_say_command(say_str, say_str, screenreader, system_language, espeak)
|
_say_command(say_str, say_str, screenreader, system_language, espeak)
|
||||||
if send_post_via_server(signing_priv_key_pem, __version__,
|
if send_post_via_server(signing_priv_key_pem, __version__,
|
||||||
base_dir, session, nickname, password,
|
base_dir, session, nickname, password,
|
||||||
|
@ -546,6 +553,7 @@ def _desktop_new_post(session,
|
||||||
cached_webfingers, person_cache, is_article,
|
cached_webfingers, person_cache, is_article,
|
||||||
system_language, languages_understood,
|
system_language, languages_understood,
|
||||||
low_bandwidth, content_license_url,
|
low_bandwidth, content_license_url,
|
||||||
|
event_date, event_time, location,
|
||||||
debug, None, None,
|
debug, None, None,
|
||||||
conversation_id, subject) == 0:
|
conversation_id, subject) == 0:
|
||||||
say_str = 'Post sent'
|
say_str = 'Post sent'
|
||||||
|
@ -1260,6 +1268,10 @@ def _desktop_new_dm_base(session, to_handle: str,
|
||||||
_say_command(say_str, say_str, screenreader, system_language, espeak)
|
_say_command(say_str, say_str, screenreader, system_language, espeak)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
event_date = None
|
||||||
|
event_time = None
|
||||||
|
location = None
|
||||||
|
|
||||||
say_str = 'Sending'
|
say_str = 'Sending'
|
||||||
_say_command(say_str, say_str, screenreader, system_language, espeak)
|
_say_command(say_str, say_str, screenreader, system_language, espeak)
|
||||||
if send_post_via_server(signing_priv_key_pem, __version__,
|
if send_post_via_server(signing_priv_key_pem, __version__,
|
||||||
|
@ -1272,6 +1284,7 @@ def _desktop_new_dm_base(session, to_handle: str,
|
||||||
cached_webfingers, person_cache, is_article,
|
cached_webfingers, person_cache, is_article,
|
||||||
system_language, languages_understood,
|
system_language, languages_understood,
|
||||||
low_bandwidth, content_license_url,
|
low_bandwidth, content_license_url,
|
||||||
|
event_date, event_time, location,
|
||||||
debug, None, None,
|
debug, None, None,
|
||||||
conversation_id, subject) == 0:
|
conversation_id, subject) == 0:
|
||||||
say_str = 'Direct message sent'
|
say_str = 'Direct message sent'
|
||||||
|
|
94
epicyon.py
94
epicyon.py
|
@ -13,6 +13,7 @@ import sys
|
||||||
import time
|
import time
|
||||||
import argparse
|
import argparse
|
||||||
import getpass
|
import getpass
|
||||||
|
import datetime
|
||||||
from person import get_actor_json
|
from person import get_actor_json
|
||||||
from person import create_person
|
from person import create_person
|
||||||
from person import create_group
|
from person import create_group
|
||||||
|
@ -101,6 +102,8 @@ from announce import send_announce_via_server
|
||||||
from socnet import instances_graph
|
from socnet import instances_graph
|
||||||
from migrate import migrate_accounts
|
from migrate import migrate_accounts
|
||||||
from desktop_client import run_desktop_client
|
from desktop_client import run_desktop_client
|
||||||
|
from happening import dav_month_via_server
|
||||||
|
from happening import dav_day_via_server
|
||||||
|
|
||||||
|
|
||||||
def str2bool(value_str) -> bool:
|
def str2bool(value_str) -> bool:
|
||||||
|
@ -115,7 +118,19 @@ def str2bool(value_str) -> bool:
|
||||||
raise argparse.ArgumentTypeError('Boolean value expected.')
|
raise argparse.ArgumentTypeError('Boolean value expected.')
|
||||||
|
|
||||||
|
|
||||||
|
search_date = datetime.datetime.now()
|
||||||
parser = argparse.ArgumentParser(description='ActivityPub Server')
|
parser = argparse.ArgumentParser(description='ActivityPub Server')
|
||||||
|
parser.add_argument('--eventDate', type=str,
|
||||||
|
default=None,
|
||||||
|
help='Date for an event when sending a c2s post' +
|
||||||
|
' YYYY-MM-DD')
|
||||||
|
parser.add_argument('--eventTime', type=str,
|
||||||
|
default=None,
|
||||||
|
help='Time for an event when sending a c2s post' +
|
||||||
|
' HH:MM')
|
||||||
|
parser.add_argument('--eventLocation', type=str,
|
||||||
|
default=None,
|
||||||
|
help='Location for an event when sending a c2s post')
|
||||||
parser.add_argument('--content_license_url', type=str,
|
parser.add_argument('--content_license_url', type=str,
|
||||||
default='https://creativecommons.org/licenses/by/4.0',
|
default='https://creativecommons.org/licenses/by/4.0',
|
||||||
help='Url of the license used for the instance content')
|
help='Url of the license used for the instance content')
|
||||||
|
@ -172,6 +187,15 @@ parser.add_argument('--i2p_domain', dest='i2p_domain', type=str,
|
||||||
parser.add_argument('-p', '--port', dest='port', type=int,
|
parser.add_argument('-p', '--port', dest='port', type=int,
|
||||||
default=None,
|
default=None,
|
||||||
help='Port number to run on')
|
help='Port number to run on')
|
||||||
|
parser.add_argument('--year', dest='year', type=int,
|
||||||
|
default=search_date.year,
|
||||||
|
help='Year for calendar query')
|
||||||
|
parser.add_argument('--month', dest='month', type=int,
|
||||||
|
default=search_date.month,
|
||||||
|
help='Month for calendar query')
|
||||||
|
parser.add_argument('--day', dest='day', type=int,
|
||||||
|
default=None,
|
||||||
|
help='Day for calendar query')
|
||||||
parser.add_argument('--postsPerSource',
|
parser.add_argument('--postsPerSource',
|
||||||
dest='max_newswire_postsPerSource', type=int,
|
dest='max_newswire_postsPerSource', type=int,
|
||||||
default=4,
|
default=4,
|
||||||
|
@ -329,6 +353,11 @@ parser.add_argument("--repliesEnabled", "--commentsEnabled",
|
||||||
type=str2bool, nargs='?',
|
type=str2bool, nargs='?',
|
||||||
const=True, default=True,
|
const=True, default=True,
|
||||||
help="Enable replies to a post")
|
help="Enable replies to a post")
|
||||||
|
parser.add_argument("--dav",
|
||||||
|
dest='dav',
|
||||||
|
type=str2bool, nargs='?',
|
||||||
|
const=True, default=False,
|
||||||
|
help="Caldav")
|
||||||
parser.add_argument("--show_publish_as_icon",
|
parser.add_argument("--show_publish_as_icon",
|
||||||
dest='show_publish_as_icon',
|
dest='show_publish_as_icon',
|
||||||
type=str2bool, nargs='?',
|
type=str2bool, nargs='?',
|
||||||
|
@ -1296,6 +1325,16 @@ if args.message:
|
||||||
print('Specify a nickname with the --nickname option')
|
print('Specify a nickname with the --nickname option')
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
|
if args.eventDate:
|
||||||
|
if '-' not in args.eventDate or len(args.eventDate) != 10:
|
||||||
|
print('Event date format should be YYYY-MM-DD')
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
if args.eventTime:
|
||||||
|
if ':' not in args.eventTime or len(args.eventTime) != 5:
|
||||||
|
print('Event time format should be HH:MM')
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
if not args.password:
|
if not args.password:
|
||||||
args.password = getpass.getpass('Password: ')
|
args.password = getpass.getpass('Password: ')
|
||||||
if not args.password:
|
if not args.password:
|
||||||
|
@ -1356,8 +1395,8 @@ if args.message:
|
||||||
if args.secure_mode:
|
if args.secure_mode:
|
||||||
signing_priv_key_pem = get_instance_actor_key(base_dir, domain)
|
signing_priv_key_pem = get_instance_actor_key(base_dir, domain)
|
||||||
languages_understood = [args.language]
|
languages_understood = [args.language]
|
||||||
print('Sending post to ' + args.sendto)
|
|
||||||
|
|
||||||
|
print('Sending post to ' + args.sendto)
|
||||||
send_post_via_server(signing_priv_key_pem, __version__,
|
send_post_via_server(signing_priv_key_pem, __version__,
|
||||||
base_dir, session, args.nickname, args.password,
|
base_dir, session, args.nickname, args.password,
|
||||||
domain, port,
|
domain, port,
|
||||||
|
@ -1368,13 +1407,64 @@ if args.message:
|
||||||
cached_webfingers, person_cache, is_article,
|
cached_webfingers, person_cache, is_article,
|
||||||
args.language, languages_understood,
|
args.language, languages_understood,
|
||||||
args.low_bandwidth,
|
args.low_bandwidth,
|
||||||
args.content_license_url, args.debug,
|
args.content_license_url,
|
||||||
|
args.eventDate, args.eventTime, args.eventLocation,
|
||||||
|
args.debug,
|
||||||
reply_to, reply_to, args.conversationId, subject)
|
reply_to, reply_to, args.conversationId, subject)
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
# TODO detect send success/fail
|
# TODO detect send success/fail
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
|
if args.dav:
|
||||||
|
if not args.nickname:
|
||||||
|
print('Please specify a nickname with --nickname')
|
||||||
|
sys.exit()
|
||||||
|
if not args.domain:
|
||||||
|
print('Please specify a domain with --domain')
|
||||||
|
sys.exit()
|
||||||
|
if not args.year:
|
||||||
|
print('Please specify a year with --year')
|
||||||
|
sys.exit()
|
||||||
|
if not args.month:
|
||||||
|
print('Please specify a month with --month')
|
||||||
|
sys.exit()
|
||||||
|
if not args.password:
|
||||||
|
args.password = getpass.getpass('Password: ')
|
||||||
|
if not args.password:
|
||||||
|
print('Specify a password with the --password option')
|
||||||
|
sys.exit()
|
||||||
|
args.password = args.password.replace('\n', '')
|
||||||
|
proxy_type = None
|
||||||
|
if args.tor or domain.endswith('.onion'):
|
||||||
|
proxy_type = 'tor'
|
||||||
|
if domain.endswith('.onion'):
|
||||||
|
args.port = 80
|
||||||
|
elif args.i2p or domain.endswith('.i2p'):
|
||||||
|
proxy_type = 'i2p'
|
||||||
|
if domain.endswith('.i2p'):
|
||||||
|
args.port = 80
|
||||||
|
elif args.gnunet:
|
||||||
|
proxy_type = 'gnunet'
|
||||||
|
session = create_session(proxy_type)
|
||||||
|
if args.day:
|
||||||
|
result = \
|
||||||
|
dav_day_via_server(session, http_prefix,
|
||||||
|
args.nickname, args.domain, args.port,
|
||||||
|
args.debug,
|
||||||
|
args.year, args.month, args.day,
|
||||||
|
args.password)
|
||||||
|
else:
|
||||||
|
result = \
|
||||||
|
dav_month_via_server(session, http_prefix,
|
||||||
|
args.nickname, args.domain, args.port,
|
||||||
|
args.debug,
|
||||||
|
args.year, args.month,
|
||||||
|
args.password)
|
||||||
|
if result:
|
||||||
|
print(str(result))
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
if args.announce:
|
if args.announce:
|
||||||
if not args.nickname:
|
if not args.nickname:
|
||||||
print('Specify a nickname with the --nickname option')
|
print('Specify a nickname with the --nickname option')
|
||||||
|
|
483
happening.py
483
happening.py
|
@ -23,8 +23,36 @@ from utils import remove_html
|
||||||
from utils import get_display_name
|
from utils import get_display_name
|
||||||
from utils import delete_post
|
from utils import delete_post
|
||||||
from utils import get_status_number
|
from utils import get_status_number
|
||||||
|
from utils import get_full_domain
|
||||||
from filters import is_filtered
|
from filters import is_filtered
|
||||||
from context import get_individual_post_context
|
from context import get_individual_post_context
|
||||||
|
from session import get_method
|
||||||
|
from auth import create_basic_auth_header
|
||||||
|
|
||||||
|
|
||||||
|
def _dav_date_from_string(timestamp: str) -> str:
|
||||||
|
"""Returns a datetime from a caldav date
|
||||||
|
"""
|
||||||
|
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 None
|
||||||
|
if int(timestamp_year) < 2020 or int(timestamp_year) > 2100:
|
||||||
|
return None
|
||||||
|
published = \
|
||||||
|
timestamp_year + '-' + timestamp_month + '-' + timestamp_day + 'T' + \
|
||||||
|
timestamp_hour + ':' + timestamp_min + ':' + timestamp_sec + 'Z'
|
||||||
|
return published
|
||||||
|
|
||||||
|
|
||||||
def _valid_uuid(test_uuid: str, version: int):
|
def _valid_uuid(test_uuid: str, version: int):
|
||||||
|
@ -181,9 +209,26 @@ def _is_happening_post(post_json_object: {}) -> bool:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def _event_text_match(content: str, text_match: str) -> bool:
|
||||||
|
"""Returns true of the content matches the search text
|
||||||
|
"""
|
||||||
|
if not text_match:
|
||||||
|
return True
|
||||||
|
if '+' not in text_match:
|
||||||
|
if text_match.strip().lower() in content.lower():
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
match_list = text_match.split('+')
|
||||||
|
for possible_match in match_list:
|
||||||
|
if possible_match.strip().lower() in content.lower():
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def get_todays_events(base_dir: str, nickname: str, domain: str,
|
def get_todays_events(base_dir: str, nickname: str, domain: str,
|
||||||
curr_year: int, curr_month_number: int,
|
curr_year: int, curr_month_number: int,
|
||||||
curr_day_of_month: int) -> {}:
|
curr_day_of_month: int,
|
||||||
|
text_match: str) -> {}:
|
||||||
"""Retrieves calendar events for today
|
"""Retrieves calendar events for today
|
||||||
Returns a dictionary of lists containing Event and Place activities
|
Returns a dictionary of lists containing Event and Place activities
|
||||||
"""
|
"""
|
||||||
|
@ -222,6 +267,12 @@ def get_todays_events(base_dir: str, nickname: str, domain: str,
|
||||||
if not _is_happening_post(post_json_object):
|
if not _is_happening_post(post_json_object):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if post_json_object.get('object'):
|
||||||
|
if post_json_object['object'].get('content'):
|
||||||
|
content = post_json_object['object']['content']
|
||||||
|
if not _event_text_match(content, text_match):
|
||||||
|
continue
|
||||||
|
|
||||||
public_event = is_public_post(post_json_object)
|
public_event = is_public_post(post_json_object)
|
||||||
|
|
||||||
post_event = []
|
post_event = []
|
||||||
|
@ -413,13 +464,15 @@ def _icalendar_day(base_dir: str, nickname: str, domain: str,
|
||||||
def get_todays_events_icalendar(base_dir: str, nickname: str, domain: str,
|
def get_todays_events_icalendar(base_dir: str, nickname: str, domain: str,
|
||||||
year: int, month_number: int,
|
year: int, month_number: int,
|
||||||
day_number: int, person_cache: {},
|
day_number: int, person_cache: {},
|
||||||
http_prefix: str) -> str:
|
http_prefix: str,
|
||||||
|
text_match: str) -> str:
|
||||||
"""Returns today's events in icalendar format
|
"""Returns today's events in icalendar format
|
||||||
"""
|
"""
|
||||||
day_events = None
|
day_events = None
|
||||||
events = \
|
events = \
|
||||||
get_todays_events(base_dir, nickname, domain,
|
get_todays_events(base_dir, nickname, domain,
|
||||||
year, month_number, day_number)
|
year, month_number, day_number,
|
||||||
|
text_match)
|
||||||
if events:
|
if events:
|
||||||
if events.get(str(day_number)):
|
if events.get(str(day_number)):
|
||||||
day_events = events[str(day_number)]
|
day_events = events[str(day_number)]
|
||||||
|
@ -447,12 +500,13 @@ def get_month_events_icalendar(base_dir: str, nickname: str, domain: str,
|
||||||
year: int,
|
year: int,
|
||||||
month_number: int,
|
month_number: int,
|
||||||
person_cache: {},
|
person_cache: {},
|
||||||
http_prefix: str) -> str:
|
http_prefix: str,
|
||||||
|
text_match: str) -> str:
|
||||||
"""Returns today's events in icalendar format
|
"""Returns today's events in icalendar format
|
||||||
"""
|
"""
|
||||||
month_events = \
|
month_events = \
|
||||||
get_calendar_events(base_dir, nickname, domain, year,
|
get_calendar_events(base_dir, nickname, domain, year,
|
||||||
month_number)
|
month_number, text_match)
|
||||||
|
|
||||||
ical_str = \
|
ical_str = \
|
||||||
'BEGIN:VCALENDAR\n' + \
|
'BEGIN:VCALENDAR\n' + \
|
||||||
|
@ -597,7 +651,8 @@ def get_this_weeks_events(base_dir: str, nickname: str, domain: str) -> {}:
|
||||||
|
|
||||||
|
|
||||||
def get_calendar_events(base_dir: str, nickname: str, domain: str,
|
def get_calendar_events(base_dir: str, nickname: str, domain: str,
|
||||||
year: int, month_number: int) -> {}:
|
year: int, month_number: int,
|
||||||
|
text_match: str) -> {}:
|
||||||
"""Retrieves calendar events
|
"""Retrieves calendar events
|
||||||
Returns a dictionary indexed by day number of lists containing
|
Returns a dictionary indexed by day number of lists containing
|
||||||
Event and Place activities
|
Event and Place activities
|
||||||
|
@ -621,9 +676,17 @@ def get_calendar_events(base_dir: str, nickname: str, domain: str,
|
||||||
continue
|
continue
|
||||||
|
|
||||||
post_json_object = load_json(post_filename)
|
post_json_object = load_json(post_filename)
|
||||||
|
if not post_json_object:
|
||||||
|
continue
|
||||||
if not _is_happening_post(post_json_object):
|
if not _is_happening_post(post_json_object):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if post_json_object.get('object'):
|
||||||
|
if post_json_object['object'].get('content'):
|
||||||
|
content = post_json_object['object']['content']
|
||||||
|
if not _event_text_match(content, text_match):
|
||||||
|
continue
|
||||||
|
|
||||||
post_event = []
|
post_event = []
|
||||||
day_of_month = None
|
day_of_month = None
|
||||||
for tag in post_json_object['object']['tag']:
|
for tag in post_json_object['object']['tag']:
|
||||||
|
@ -784,66 +847,15 @@ def _dav_store_event(base_dir: str, nickname: str, domain: str,
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# convert to the expected time format
|
# convert to the expected time format
|
||||||
timestamp_year = timestamp[:4]
|
published = _dav_date_from_string(timestamp)
|
||||||
timestamp_month = timestamp[4:][:2]
|
if not published:
|
||||||
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
|
return False
|
||||||
if int(timestamp_year) < 2020 or int(timestamp_year) > 2100:
|
start_time = _dav_date_from_string(start_time)
|
||||||
|
if not start_time:
|
||||||
return False
|
return False
|
||||||
published = \
|
end_time = _dav_date_from_string(end_time)
|
||||||
timestamp_year + '-' + timestamp_month + '-' + timestamp_day + 'T' + \
|
if not end_time:
|
||||||
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
|
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_id = ''
|
||||||
post_context = get_individual_post_context()
|
post_context = get_individual_post_context()
|
||||||
|
@ -932,9 +944,26 @@ def _dav_store_event(base_dir: str, nickname: str, domain: str,
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def _dav_update_recent_etags(etag: str, nickname: str,
|
||||||
|
recent_dav_etags: {}) -> None:
|
||||||
|
"""Updates the recent etags for each account
|
||||||
|
"""
|
||||||
|
# update the recent caldav etags for each account
|
||||||
|
if not recent_dav_etags.get(nickname):
|
||||||
|
recent_dav_etags[nickname] = [etag]
|
||||||
|
else:
|
||||||
|
# only keep a limited number of recent etags
|
||||||
|
while len(recent_dav_etags[nickname]) > 32:
|
||||||
|
recent_dav_etags[nickname].pop(0)
|
||||||
|
# append the etag to the recent list
|
||||||
|
if etag not in recent_dav_etags[nickname]:
|
||||||
|
recent_dav_etags[nickname].append(etag)
|
||||||
|
|
||||||
|
|
||||||
def dav_put_response(base_dir: str, nickname: str, domain: str,
|
def dav_put_response(base_dir: str, nickname: str, domain: str,
|
||||||
depth: int, xml_str: str, http_prefix: str,
|
depth: int, xml_str: str, http_prefix: str,
|
||||||
system_language: str) -> str:
|
system_language: str,
|
||||||
|
recent_dav_etags: {}) -> str:
|
||||||
"""Returns the response to caldav PUT
|
"""Returns the response to caldav PUT
|
||||||
"""
|
"""
|
||||||
if '\n' not in xml_str:
|
if '\n' not in xml_str:
|
||||||
|
@ -946,6 +975,11 @@ def dav_put_response(base_dir: str, nickname: str, domain: str,
|
||||||
'END:VEVENT' not in xml_str:
|
'END:VEVENT' not in xml_str:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
etag = md5(xml_str.encode('utf-8')).hexdigest()
|
||||||
|
if recent_dav_etags.get(nickname):
|
||||||
|
if etag in recent_dav_etags[nickname]:
|
||||||
|
return 'Not modified'
|
||||||
|
|
||||||
stored_count = 0
|
stored_count = 0
|
||||||
reading_event = False
|
reading_event = False
|
||||||
lines_list = xml_str.split('\n')
|
lines_list = xml_str.split('\n')
|
||||||
|
@ -968,13 +1002,14 @@ def dav_put_response(base_dir: str, nickname: str, domain: str,
|
||||||
event_list.append(line)
|
event_list.append(line)
|
||||||
if stored_count == 0:
|
if stored_count == 0:
|
||||||
return None
|
return None
|
||||||
return 'Ok'
|
_dav_update_recent_etags(etag, nickname, recent_dav_etags)
|
||||||
|
return 'ETag:' + etag
|
||||||
|
|
||||||
|
|
||||||
def dav_report_response(base_dir: str, nickname: str, domain: str,
|
def dav_report_response(base_dir: str, nickname: str, domain: str,
|
||||||
depth: int, xml_str: str,
|
depth: int, xml_str: str,
|
||||||
person_cache: {}, http_prefix: str,
|
person_cache: {}, http_prefix: str,
|
||||||
curr_etag: str,
|
curr_etag: str, recent_dav_etags: {},
|
||||||
domain_full: str) -> str:
|
domain_full: str) -> str:
|
||||||
"""Returns the response to caldav REPORT
|
"""Returns the response to caldav REPORT
|
||||||
"""
|
"""
|
||||||
|
@ -983,42 +1018,227 @@ def dav_report_response(base_dir: str, nickname: str, domain: str,
|
||||||
if '<c:calendar-multiget' not in xml_str or \
|
if '<c:calendar-multiget' not in xml_str or \
|
||||||
'</c:calendar-multiget>' not in xml_str:
|
'</c:calendar-multiget>' not in xml_str:
|
||||||
return None
|
return None
|
||||||
# today's calendar events
|
|
||||||
now = datetime.now()
|
if curr_etag:
|
||||||
|
if recent_dav_etags.get(nickname):
|
||||||
|
if curr_etag in recent_dav_etags[nickname]:
|
||||||
|
return "Not modified"
|
||||||
|
|
||||||
|
xml_str_lower = xml_str.lower()
|
||||||
|
query_start_time = None
|
||||||
|
query_end_time = None
|
||||||
|
if ':time-range' in xml_str_lower:
|
||||||
|
time_range_str = xml_str_lower.split(':time-range')[1]
|
||||||
|
if 'start=' in time_range_str and 'end=' in time_range_str:
|
||||||
|
start_time_str = time_range_str.split('start=')[1]
|
||||||
|
if start_time_str.startswith("'"):
|
||||||
|
query_start_time_str = start_time_str.split("'")[1]
|
||||||
|
query_start_time = _dav_date_from_string(query_start_time_str)
|
||||||
|
elif start_time_str.startswith('"'):
|
||||||
|
query_start_time_str = start_time_str.split('"')[1]
|
||||||
|
query_start_time = _dav_date_from_string(query_start_time_str)
|
||||||
|
|
||||||
|
end_time_str = time_range_str.split('end=')[1]
|
||||||
|
if end_time_str.startswith("'"):
|
||||||
|
query_end_time_str = end_time_str.split("'")[1]
|
||||||
|
query_end_time = _dav_date_from_string(query_end_time_str)
|
||||||
|
elif end_time_str.startswith('"'):
|
||||||
|
query_end_time_str = end_time_str.split('"')[1]
|
||||||
|
query_end_time = _dav_date_from_string(query_end_time_str)
|
||||||
|
|
||||||
|
text_match = ''
|
||||||
|
if ':text-match' in xml_str_lower:
|
||||||
|
match_str = xml_str_lower.split(':text-match')[1]
|
||||||
|
if '>' in match_str and '<' in match_str:
|
||||||
|
text_match = match_str.split('>')[1]
|
||||||
|
if '<' in text_match:
|
||||||
|
text_match = text_match.split('<')[0]
|
||||||
|
else:
|
||||||
|
text_match = ''
|
||||||
|
|
||||||
|
ical_events = None
|
||||||
|
etag = None
|
||||||
|
events_href = ''
|
||||||
|
responses = ''
|
||||||
|
search_date = datetime.now()
|
||||||
|
if query_start_time and query_end_time:
|
||||||
|
query_start_year = int(query_start_time.split('-')[0])
|
||||||
|
query_start_month = int(query_start_time.split('-')[1])
|
||||||
|
query_start_day = query_start_time.split('-')[2]
|
||||||
|
query_start_day = int(query_start_day.split('T')[0])
|
||||||
|
query_end_year = int(query_end_time.split('-')[0])
|
||||||
|
query_end_month = int(query_end_time.split('-')[1])
|
||||||
|
query_end_day = query_end_time.split('-')[2]
|
||||||
|
query_end_day = int(query_end_day.split('T')[0])
|
||||||
|
if query_start_year == query_end_year and \
|
||||||
|
query_start_month == query_end_month:
|
||||||
|
if query_start_day == query_end_day:
|
||||||
|
# calendar for one day
|
||||||
|
search_date = \
|
||||||
|
datetime(year=query_start_year,
|
||||||
|
month=query_start_month,
|
||||||
|
day=query_start_day)
|
||||||
ical_events = \
|
ical_events = \
|
||||||
get_todays_events_icalendar(base_dir, nickname, domain,
|
get_todays_events_icalendar(base_dir, nickname, domain,
|
||||||
now.year, now.month,
|
search_date.year,
|
||||||
now.day, person_cache,
|
search_date.month,
|
||||||
http_prefix)
|
search_date.day, person_cache,
|
||||||
if not ical_events:
|
http_prefix, text_match)
|
||||||
return None
|
|
||||||
if 'VEVENT' not in ical_events:
|
|
||||||
return None
|
|
||||||
|
|
||||||
etag = md5(ical_events).hexdigest()
|
|
||||||
if etag == curr_etag:
|
|
||||||
return "Not modified"
|
|
||||||
events_href = \
|
events_href = \
|
||||||
http_prefix + '://' + domain_full + '/users/' + \
|
http_prefix + '://' + domain_full + '/users/' + \
|
||||||
nickname + '/calendar?year=' + \
|
nickname + '/calendar?year=' + \
|
||||||
str(now.year) + '?month=' + str(now.month) + '?day=' + str(now.day)
|
str(search_date.year) + '?month=' + \
|
||||||
response_str = \
|
str(search_date.month) + '?day=' + str(search_date.day)
|
||||||
'<d:multistatus xmlns:d="DAV:" ' + \
|
if ical_events:
|
||||||
'xmlns:cs="http://calendarserver.org/ns/">\n' + \
|
if 'VEVENT' in ical_events:
|
||||||
|
ical_events_encoded = ical_events.encode('utf-8')
|
||||||
|
etag = md5(ical_events_encoded).hexdigest()
|
||||||
|
responses = \
|
||||||
|
' <d:response>\n' + \
|
||||||
|
' <d:href>' + events_href + \
|
||||||
|
'</d:href>\n' + \
|
||||||
|
' <d:propstat>\n' + \
|
||||||
|
' <d:prop>\n' + \
|
||||||
|
' <d:getetag>"' + \
|
||||||
|
etag + '"</d:getetag>\n' + \
|
||||||
|
' <c:calendar-data>' + \
|
||||||
|
ical_events + \
|
||||||
|
' </c:calendar-data>\n' + \
|
||||||
|
' </d:prop>\n' + \
|
||||||
|
' <d:status>HTTP/1.1 200 OK' + \
|
||||||
|
'</d:status>\n' + \
|
||||||
|
' </d:propstat>\n' + \
|
||||||
|
' </d:response>\n'
|
||||||
|
elif query_start_day == 1 and query_start_day >= 28:
|
||||||
|
# calendar for a month
|
||||||
|
ical_events = \
|
||||||
|
get_month_events_icalendar(base_dir, nickname, domain,
|
||||||
|
query_start_year,
|
||||||
|
query_start_month,
|
||||||
|
person_cache,
|
||||||
|
http_prefix,
|
||||||
|
text_match)
|
||||||
|
events_href = \
|
||||||
|
http_prefix + '://' + domain_full + '/users/' + \
|
||||||
|
nickname + '/calendar?year=' + \
|
||||||
|
str(query_start_year) + '?month=' + \
|
||||||
|
str(query_start_month)
|
||||||
|
if ical_events:
|
||||||
|
if 'VEVENT' in ical_events:
|
||||||
|
ical_events_encoded = ical_events.encode('utf-8')
|
||||||
|
etag = md5(ical_events_encoded).hexdigest()
|
||||||
|
responses = \
|
||||||
|
' <d:response>\n' + \
|
||||||
|
' <d:href>' + events_href + \
|
||||||
|
'</d:href>\n' + \
|
||||||
|
' <d:propstat>\n' + \
|
||||||
|
' <d:prop>\n' + \
|
||||||
|
' <d:getetag>"' + \
|
||||||
|
etag + '"</d:getetag>\n' + \
|
||||||
|
' <c:calendar-data>' + \
|
||||||
|
ical_events + \
|
||||||
|
' </c:calendar-data>\n' + \
|
||||||
|
' </d:prop>\n' + \
|
||||||
|
' <d:status>HTTP/1.1 200 OK' + \
|
||||||
|
'</d:status>\n' + \
|
||||||
|
' </d:propstat>\n' + \
|
||||||
|
' </d:response>\n'
|
||||||
|
if not responses:
|
||||||
|
all_events = ''
|
||||||
|
for year in range(query_start_year, query_end_year+1):
|
||||||
|
if query_start_year == query_end_year:
|
||||||
|
start_month_number = query_start_month
|
||||||
|
end_month_number = query_end_month
|
||||||
|
elif year == query_end_year:
|
||||||
|
start_month_number = 1
|
||||||
|
end_month_number = query_end_month
|
||||||
|
elif year == query_start_year:
|
||||||
|
start_month_number = query_start_month
|
||||||
|
end_month_number = 12
|
||||||
|
else:
|
||||||
|
start_month_number = 1
|
||||||
|
end_month_number = 12
|
||||||
|
for month in range(start_month_number, end_month_number+1):
|
||||||
|
ical_events = \
|
||||||
|
get_month_events_icalendar(base_dir,
|
||||||
|
nickname, domain,
|
||||||
|
year, month,
|
||||||
|
person_cache,
|
||||||
|
http_prefix,
|
||||||
|
text_match)
|
||||||
|
events_href = \
|
||||||
|
http_prefix + '://' + domain_full + '/users/' + \
|
||||||
|
nickname + '/calendar?year=' + \
|
||||||
|
str(year) + '?month=' + \
|
||||||
|
str(month)
|
||||||
|
if ical_events:
|
||||||
|
if 'VEVENT' in ical_events:
|
||||||
|
all_events += ical_events
|
||||||
|
ical_events_encoded = ical_events.encode('utf-8')
|
||||||
|
local_etag = md5(ical_events_encoded).hexdigest()
|
||||||
|
responses += \
|
||||||
|
' <d:response>\n' + \
|
||||||
|
' <d:href>' + events_href + \
|
||||||
|
'</d:href>\n' + \
|
||||||
|
' <d:propstat>\n' + \
|
||||||
|
' <d:prop>\n' + \
|
||||||
|
' <d:getetag>"' + \
|
||||||
|
local_etag + '"</d:getetag>\n' + \
|
||||||
|
' <c:calendar-data>' + \
|
||||||
|
ical_events + \
|
||||||
|
' </c:calendar-data>\n' + \
|
||||||
|
' </d:prop>\n' + \
|
||||||
|
' <d:status>HTTP/1.1 200 OK' + \
|
||||||
|
'</d:status>\n' + \
|
||||||
|
' </d:propstat>\n' + \
|
||||||
|
' </d:response>\n'
|
||||||
|
ical_events_encoded = all_events.encode('utf-8')
|
||||||
|
etag = md5(ical_events_encoded).hexdigest()
|
||||||
|
|
||||||
|
# today's calendar events
|
||||||
|
if not ical_events:
|
||||||
|
ical_events = \
|
||||||
|
get_todays_events_icalendar(base_dir, nickname, domain,
|
||||||
|
search_date.year, search_date.month,
|
||||||
|
search_date.day, person_cache,
|
||||||
|
http_prefix, text_match)
|
||||||
|
events_href = \
|
||||||
|
http_prefix + '://' + domain_full + '/users/' + \
|
||||||
|
nickname + '/calendar?year=' + \
|
||||||
|
str(search_date.year) + '?month=' + \
|
||||||
|
str(search_date.month) + '?day=' + str(search_date.day)
|
||||||
|
if ical_events:
|
||||||
|
if 'VEVENT' in ical_events:
|
||||||
|
ical_events_encoded = ical_events.encode('utf-8')
|
||||||
|
etag = md5(ical_events_encoded).hexdigest()
|
||||||
|
responses = \
|
||||||
' <d:response>\n' + \
|
' <d:response>\n' + \
|
||||||
' <d:href>' + events_href + '</d:href>\n' + \
|
' <d:href>' + events_href + '</d:href>\n' + \
|
||||||
' <d:propstat>\n' + \
|
' <d:propstat>\n' + \
|
||||||
' <d:prop>\n' + \
|
' <d:prop>\n' + \
|
||||||
' <d:getetag>"' + etag + '"</d:getetag>\n' + \
|
' <d:getetag>"' + etag + \
|
||||||
|
'"</d:getetag>\n' + \
|
||||||
' <c:calendar-data>' + ical_events + \
|
' <c:calendar-data>' + ical_events + \
|
||||||
' </c:calendar-data>\n' + \
|
' </c:calendar-data>\n' + \
|
||||||
' </d:prop>\n' + \
|
' </d:prop>\n' + \
|
||||||
' <d:status>HTTP/1.1 200 OK</d:status>\n' + \
|
' <d:status>HTTP/1.1 200 OK</d:status>\n' + \
|
||||||
' </d:propstat>\n' + \
|
' </d:propstat>\n' + \
|
||||||
' </d:response>\n' + \
|
' </d:response>\n'
|
||||||
' <d:response>\n' + \
|
|
||||||
'</d:multistatus>'
|
|
||||||
|
|
||||||
|
if not ical_events or not etag:
|
||||||
|
return None
|
||||||
|
if 'VEVENT' not in ical_events:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if etag == curr_etag:
|
||||||
|
return "Not modified"
|
||||||
|
response_str = \
|
||||||
|
'<?xml version="1.0" encoding="utf-8" ?>\n' + \
|
||||||
|
'<d:multistatus xmlns:d="DAV:" ' + \
|
||||||
|
'xmlns:cs="http://calendarserver.org/ns/">\n' + \
|
||||||
|
responses + '</d:multistatus>'
|
||||||
|
|
||||||
|
_dav_update_recent_etags(etag, nickname, recent_dav_etags)
|
||||||
return response_str
|
return response_str
|
||||||
|
|
||||||
|
|
||||||
|
@ -1048,3 +1268,92 @@ def dav_delete_response(base_dir: str, nickname: str, domain: str,
|
||||||
nickname, domain, post_filename,
|
nickname, domain, post_filename,
|
||||||
debug, recent_posts_cache)
|
debug, recent_posts_cache)
|
||||||
return 'Ok'
|
return 'Ok'
|
||||||
|
|
||||||
|
|
||||||
|
def dav_month_via_server(session, http_prefix: str,
|
||||||
|
nickname: str, domain: str, port: int,
|
||||||
|
debug: bool,
|
||||||
|
year: int, month: int,
|
||||||
|
password: str) -> str:
|
||||||
|
"""Gets the icalendar for a month via caldav
|
||||||
|
"""
|
||||||
|
auth_header = create_basic_auth_header(nickname, password)
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
'host': domain,
|
||||||
|
'Content-type': 'application/xml',
|
||||||
|
'Authorization': auth_header
|
||||||
|
}
|
||||||
|
domain_full = get_full_domain(domain, port)
|
||||||
|
params = {}
|
||||||
|
url = http_prefix + '://' + domain_full + '/calendars/' + nickname
|
||||||
|
month_str = str(month)
|
||||||
|
if month < 10:
|
||||||
|
month_str = '0' + month_str
|
||||||
|
xml_str = \
|
||||||
|
'<?xml version="1.0" encoding="utf-8" ?>\n' + \
|
||||||
|
'<c:calendar-query xmlns:d="DAV:"\n' + \
|
||||||
|
' xmlns:c="urn:ietf:params:xml:ns:caldav">\n' + \
|
||||||
|
' <d:prop>\n' + \
|
||||||
|
' <d:getetag/>\n' + \
|
||||||
|
' </d:prop>\n' + \
|
||||||
|
' <c:filter>\n' + \
|
||||||
|
' <c:comp-filter name="VCALENDAR">\n' + \
|
||||||
|
' <c:comp-filter name="VEVENT">\n' + \
|
||||||
|
' <c:time-range start="' + str(year) + month_str + \
|
||||||
|
'01T000000Z"\n' + \
|
||||||
|
' end="' + str(year) + month_str + \
|
||||||
|
'31T235959Z"/>\n' + \
|
||||||
|
' </c:comp-filter>\n' + \
|
||||||
|
' </c:comp-filter>\n' + \
|
||||||
|
' </c:filter>\n' + \
|
||||||
|
'</c:calendar-query>'
|
||||||
|
result = \
|
||||||
|
get_method("REPORT", xml_str, session, url, params, headers, debug)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def dav_day_via_server(session, http_prefix: str,
|
||||||
|
nickname: str, domain: str, port: int,
|
||||||
|
debug: bool,
|
||||||
|
year: int, month: int, day: int,
|
||||||
|
password: str) -> str:
|
||||||
|
"""Gets the icalendar for a day via caldav
|
||||||
|
"""
|
||||||
|
auth_header = create_basic_auth_header(nickname, password)
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
'host': domain,
|
||||||
|
'Content-type': 'application/xml',
|
||||||
|
'Authorization': auth_header
|
||||||
|
}
|
||||||
|
domain_full = get_full_domain(domain, port)
|
||||||
|
params = {}
|
||||||
|
url = http_prefix + '://' + domain_full + '/calendars/' + nickname
|
||||||
|
month_str = str(month)
|
||||||
|
if month < 10:
|
||||||
|
month_str = '0' + month_str
|
||||||
|
day_str = str(day)
|
||||||
|
if day < 10:
|
||||||
|
day_str = '0' + day_str
|
||||||
|
xml_str = \
|
||||||
|
'<?xml version="1.0" encoding="utf-8" ?>\n' + \
|
||||||
|
'<c:calendar-query xmlns:d="DAV:"\n' + \
|
||||||
|
' xmlns:c="urn:ietf:params:xml:ns:caldav">\n' + \
|
||||||
|
' <d:prop>\n' + \
|
||||||
|
' <d:getetag/>\n' + \
|
||||||
|
' </d:prop>\n' + \
|
||||||
|
' <c:filter>\n' + \
|
||||||
|
' <c:comp-filter name="VCALENDAR">\n' + \
|
||||||
|
' <c:comp-filter name="VEVENT">\n' + \
|
||||||
|
' <c:time-range start="' + str(year) + month_str + \
|
||||||
|
day_str + 'T000000Z"\n' + \
|
||||||
|
' end="' + str(year) + month_str + \
|
||||||
|
day_str + 'T235959Z"/>\n' + \
|
||||||
|
' </c:comp-filter>\n' + \
|
||||||
|
' </c:comp-filter>\n' + \
|
||||||
|
' </c:filter>\n' + \
|
||||||
|
'</c:calendar-query>'
|
||||||
|
result = \
|
||||||
|
get_method("REPORT", xml_str, session, url, params, headers, debug)
|
||||||
|
return result
|
||||||
|
|
7
posts.py
7
posts.py
|
@ -2490,6 +2490,8 @@ def send_post_via_server(signing_priv_key_pem: str, project_version: str,
|
||||||
languages_understood: [],
|
languages_understood: [],
|
||||||
low_bandwidth: bool,
|
low_bandwidth: bool,
|
||||||
content_license_url: str,
|
content_license_url: str,
|
||||||
|
event_date: str, event_time: str,
|
||||||
|
location: str,
|
||||||
debug: bool = False,
|
debug: bool = False,
|
||||||
in_reply_to: str = None,
|
in_reply_to: str = None,
|
||||||
in_reply_to_atom_uri: str = None,
|
in_reply_to_atom_uri: str = None,
|
||||||
|
@ -2574,8 +2576,9 @@ def send_post_via_server(signing_priv_key_pem: str, project_version: str,
|
||||||
image_description, city,
|
image_description, city,
|
||||||
False, is_article, in_reply_to,
|
False, is_article, in_reply_to,
|
||||||
in_reply_to_atom_uri, subject,
|
in_reply_to_atom_uri, subject,
|
||||||
False, None, None, None, None, None,
|
False,
|
||||||
None, None, None,
|
event_date, event_time, location,
|
||||||
|
None, None, None, None, None,
|
||||||
None, None, None, None, None, system_language,
|
None, None, None, None, None, system_language,
|
||||||
conversation_id, low_bandwidth,
|
conversation_id, low_bandwidth,
|
||||||
content_license_url, languages_understood)
|
content_license_url, languages_understood)
|
||||||
|
|
100
session.py
100
session.py
|
@ -102,10 +102,13 @@ def _get_json_request(session, url: str, domain_full: str, session_headers: {},
|
||||||
elif result.status_code == 410:
|
elif result.status_code == 410:
|
||||||
print('WARN: get_json no longer available url: ' + url)
|
print('WARN: get_json no longer available url: ' + url)
|
||||||
else:
|
else:
|
||||||
|
session_headers2 = session_headers.copy()
|
||||||
|
if session_headers2.get('Authorization'):
|
||||||
|
session_headers2['Authorization'] = 'REDACTED'
|
||||||
print('WARN: get_json url: ' + url +
|
print('WARN: get_json url: ' + url +
|
||||||
' failed with error code ' +
|
' failed with error code ' +
|
||||||
str(result.status_code) +
|
str(result.status_code) +
|
||||||
' headers: ' + str(session_headers))
|
' headers: ' + str(session_headers2))
|
||||||
if return_json:
|
if return_json:
|
||||||
return result.json()
|
return result.json()
|
||||||
return result.content
|
return result.content
|
||||||
|
@ -210,7 +213,7 @@ def _get_json_signed(session, url: str, domain_full: str, session_headers: {},
|
||||||
|
|
||||||
def get_json(signing_priv_key_pem: str,
|
def get_json(signing_priv_key_pem: str,
|
||||||
session, url: str, headers: {}, params: {}, debug: bool,
|
session, url: str, headers: {}, params: {}, debug: bool,
|
||||||
version: str = '1.3.0', http_prefix: str = 'https',
|
version: str = __version__, http_prefix: str = 'https',
|
||||||
domain: str = 'testdomain',
|
domain: str = 'testdomain',
|
||||||
timeout_sec: int = 20, quiet: bool = False) -> {}:
|
timeout_sec: int = 20, quiet: bool = False) -> {}:
|
||||||
if not isinstance(url, str):
|
if not isinstance(url, str):
|
||||||
|
@ -248,7 +251,7 @@ def get_json(signing_priv_key_pem: str,
|
||||||
|
|
||||||
def get_vcard(xml_format: bool,
|
def get_vcard(xml_format: bool,
|
||||||
session, url: str, params: {}, debug: bool,
|
session, url: str, params: {}, debug: bool,
|
||||||
version: str = '1.3.0', http_prefix: str = 'https',
|
version: str = __version__, http_prefix: str = 'https',
|
||||||
domain: str = 'testdomain',
|
domain: str = 'testdomain',
|
||||||
timeout_sec: int = 20, quiet: bool = False) -> {}:
|
timeout_sec: int = 20, quiet: bool = False) -> {}:
|
||||||
if not isinstance(url, str):
|
if not isinstance(url, str):
|
||||||
|
@ -292,10 +295,13 @@ def get_vcard(xml_format: bool,
|
||||||
elif result.status_code == 410:
|
elif result.status_code == 410:
|
||||||
print('WARN: get_vcard no longer available url: ' + url)
|
print('WARN: get_vcard no longer available url: ' + url)
|
||||||
else:
|
else:
|
||||||
|
session_headers2 = session_headers.copy()
|
||||||
|
if session_headers2.get('Authorization'):
|
||||||
|
session_headers2['Authorization'] = 'REDACTED'
|
||||||
print('WARN: get_vcard url: ' + url +
|
print('WARN: get_vcard url: ' + url +
|
||||||
' failed with error code ' +
|
' failed with error code ' +
|
||||||
str(result.status_code) +
|
str(result.status_code) +
|
||||||
' headers: ' + str(session_headers))
|
' headers: ' + str(session_headers2))
|
||||||
return result.content.decode('utf-8')
|
return result.content.decode('utf-8')
|
||||||
except requests.exceptions.RequestException as ex:
|
except requests.exceptions.RequestException as ex:
|
||||||
session_headers2 = session_headers.copy()
|
session_headers2 = session_headers.copy()
|
||||||
|
@ -323,7 +329,7 @@ def get_vcard(xml_format: bool,
|
||||||
|
|
||||||
def download_html(signing_priv_key_pem: str,
|
def download_html(signing_priv_key_pem: str,
|
||||||
session, url: str, headers: {}, params: {}, debug: bool,
|
session, url: str, headers: {}, params: {}, debug: bool,
|
||||||
version: str = '1.3.0', http_prefix: str = 'https',
|
version: str = __version__, http_prefix: str = 'https',
|
||||||
domain: str = 'testdomain',
|
domain: str = 'testdomain',
|
||||||
timeout_sec: int = 20, quiet: bool = False) -> {}:
|
timeout_sec: int = 20, quiet: bool = False) -> {}:
|
||||||
if not isinstance(url, str):
|
if not isinstance(url, str):
|
||||||
|
@ -664,3 +670,87 @@ def download_image_any_mime_type(session, url: str,
|
||||||
if 'image/' + m_type in content_type:
|
if 'image/' + m_type in content_type:
|
||||||
mime_type = 'image/' + m_type
|
mime_type = 'image/' + m_type
|
||||||
return result.content, mime_type
|
return result.content, mime_type
|
||||||
|
|
||||||
|
|
||||||
|
def get_method(method_name: str, xml_str: str,
|
||||||
|
session, url: str, params: {}, headers: {}, debug: bool,
|
||||||
|
version: str = __version__, http_prefix: str = 'https',
|
||||||
|
domain: str = 'testdomain',
|
||||||
|
timeout_sec: int = 20, quiet: bool = False) -> {}:
|
||||||
|
if method_name not in ("REPORT", "PUT", "PROPFIND"):
|
||||||
|
print("Unrecognized method: " + method_name)
|
||||||
|
return None
|
||||||
|
if not isinstance(url, str):
|
||||||
|
if debug and not quiet:
|
||||||
|
print('url: ' + str(url))
|
||||||
|
print('ERROR: get_method failed, url should be a string')
|
||||||
|
return None
|
||||||
|
if not headers:
|
||||||
|
headers = {
|
||||||
|
'Accept': 'application/xml'
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
headers['Accept'] = 'application/xml'
|
||||||
|
session_params = {}
|
||||||
|
session_headers = {}
|
||||||
|
if headers:
|
||||||
|
session_headers = headers
|
||||||
|
if params:
|
||||||
|
session_params = params
|
||||||
|
session_headers['User-Agent'] = 'Epicyon/' + version
|
||||||
|
if domain:
|
||||||
|
session_headers['User-Agent'] += \
|
||||||
|
'; +' + http_prefix + '://' + domain + '/'
|
||||||
|
if not session:
|
||||||
|
if not quiet:
|
||||||
|
print('WARN: get_method failed, ' +
|
||||||
|
'no session specified for get_vcard')
|
||||||
|
return None
|
||||||
|
|
||||||
|
if debug:
|
||||||
|
HTTPConnection.debuglevel = 1
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = session.request(method_name, url, headers=session_headers,
|
||||||
|
data=xml_str,
|
||||||
|
params=session_params, timeout=timeout_sec)
|
||||||
|
if result.status_code != 200 and result.status_code != 207:
|
||||||
|
if result.status_code == 401:
|
||||||
|
print("WARN: get_method " + url + ' rejected by secure mode')
|
||||||
|
elif result.status_code == 403:
|
||||||
|
print('WARN: get_method Forbidden url: ' + url)
|
||||||
|
elif result.status_code == 404:
|
||||||
|
print('WARN: get_method Not Found url: ' + url)
|
||||||
|
elif result.status_code == 410:
|
||||||
|
print('WARN: get_method no longer available url: ' + url)
|
||||||
|
else:
|
||||||
|
session_headers2 = session_headers.copy()
|
||||||
|
if session_headers2.get('Authorization'):
|
||||||
|
session_headers2['Authorization'] = 'REDACTED'
|
||||||
|
print('WARN: get_method url: ' + url +
|
||||||
|
' failed with error code ' +
|
||||||
|
str(result.status_code) +
|
||||||
|
' headers: ' + str(session_headers2))
|
||||||
|
return result.content.decode('utf-8')
|
||||||
|
except requests.exceptions.RequestException as ex:
|
||||||
|
session_headers2 = session_headers.copy()
|
||||||
|
if session_headers2.get('Authorization'):
|
||||||
|
session_headers2['Authorization'] = 'REDACTED'
|
||||||
|
if debug and not quiet:
|
||||||
|
print('EX: get_method failed, url: ' + str(url) + ', ' +
|
||||||
|
'headers: ' + str(session_headers2) + ', ' +
|
||||||
|
'params: ' + str(session_params) + ', ' + str(ex))
|
||||||
|
except ValueError as ex:
|
||||||
|
session_headers2 = session_headers.copy()
|
||||||
|
if session_headers2.get('Authorization'):
|
||||||
|
session_headers2['Authorization'] = 'REDACTED'
|
||||||
|
if debug and not quiet:
|
||||||
|
print('EX: get_method failed, url: ' + str(url) + ', ' +
|
||||||
|
'headers: ' + str(session_headers2) + ', ' +
|
||||||
|
'params: ' + str(session_params) + ', ' + str(ex))
|
||||||
|
except SocketError as ex:
|
||||||
|
if not quiet:
|
||||||
|
if ex.errno == errno.ECONNRESET:
|
||||||
|
print('EX: get_method failed, ' +
|
||||||
|
'connection was reset during get_vcard ' + str(ex))
|
||||||
|
return None
|
||||||
|
|
57
tests.py
57
tests.py
|
@ -176,6 +176,9 @@ from shares import send_share_via_server
|
||||||
from shares import get_shared_items_catalog_via_server
|
from shares import get_shared_items_catalog_via_server
|
||||||
from blocking import load_cw_lists
|
from blocking import load_cw_lists
|
||||||
from blocking import add_cw_from_lists
|
from blocking import add_cw_from_lists
|
||||||
|
from happening import dav_month_via_server
|
||||||
|
from happening import dav_day_via_server
|
||||||
|
|
||||||
|
|
||||||
TEST_SERVER_GROUP_RUNNING = False
|
TEST_SERVER_GROUP_RUNNING = False
|
||||||
TEST_SERVER_ALICE_RUNNING = False
|
TEST_SERVER_ALICE_RUNNING = False
|
||||||
|
@ -2946,6 +2949,13 @@ def test_client_to_server(base_dir: str):
|
||||||
|
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
|
# set bob to be following the calendar of alice
|
||||||
|
print('Bob follows the calendar of Alice')
|
||||||
|
following_cal_path = \
|
||||||
|
bob_dir + '/accounts/bob@' + bob_domain + '/followingCalendar.txt'
|
||||||
|
with open(following_cal_path, 'w+') as fp:
|
||||||
|
fp.write('alice@' + alice_domain + '\n')
|
||||||
|
|
||||||
print('\n\n*******************************************************')
|
print('\n\n*******************************************************')
|
||||||
print('EVENT: Alice sends to Bob via c2s')
|
print('EVENT: Alice sends to Bob via c2s')
|
||||||
|
|
||||||
|
@ -2981,6 +2991,12 @@ def test_client_to_server(base_dir: str):
|
||||||
if os.path.isfile(os.path.join(bob_outbox_path, name))]) == 0
|
if os.path.isfile(os.path.join(bob_outbox_path, name))]) == 0
|
||||||
print('EVENT: all inboxes and outboxes are empty')
|
print('EVENT: all inboxes and outboxes are empty')
|
||||||
signing_priv_key_pem = None
|
signing_priv_key_pem = None
|
||||||
|
test_date = datetime.datetime.now()
|
||||||
|
event_date = \
|
||||||
|
str(test_date.year) + '-' + str(test_date.month) + '-' + \
|
||||||
|
str(test_date.day)
|
||||||
|
event_time = '11:45'
|
||||||
|
location = "Kinshasa"
|
||||||
send_result = \
|
send_result = \
|
||||||
send_post_via_server(signing_priv_key_pem, __version__,
|
send_post_via_server(signing_priv_key_pem, __version__,
|
||||||
alice_dir, session_alice, 'alice', password,
|
alice_dir, session_alice, 'alice', password,
|
||||||
|
@ -2993,6 +3009,7 @@ def test_client_to_server(base_dir: str):
|
||||||
cached_webfingers, person_cache, is_article,
|
cached_webfingers, person_cache, is_article,
|
||||||
system_language, languages_understood,
|
system_language, languages_understood,
|
||||||
low_bandwidth, content_license_url,
|
low_bandwidth, content_license_url,
|
||||||
|
event_date, event_time, location,
|
||||||
True, None, None,
|
True, None, None,
|
||||||
conversation_id, None)
|
conversation_id, None)
|
||||||
print('send_result: ' + str(send_result))
|
print('send_result: ' + str(send_result))
|
||||||
|
@ -3028,6 +3045,17 @@ def test_client_to_server(base_dir: str):
|
||||||
if os.path.isfile(os.path.join(bob_outbox_path, name))]) == 0
|
if os.path.isfile(os.path.join(bob_outbox_path, name))]) == 0
|
||||||
|
|
||||||
print(">>> s2s post arrived in Bob's inbox")
|
print(">>> s2s post arrived in Bob's inbox")
|
||||||
|
|
||||||
|
calendar_path = bob_dir + '/accounts/bob@' + bob_domain + '/calendar'
|
||||||
|
if not os.path.isdir(calendar_path):
|
||||||
|
print('Missing calendar path: ' + calendar_path)
|
||||||
|
assert os.path.isdir(calendar_path)
|
||||||
|
assert os.path.isdir(calendar_path + '/' + str(test_date.year))
|
||||||
|
assert os.path.isfile(calendar_path + '/' + str(test_date.year) + '/' +
|
||||||
|
str(test_date.month) + '.txt')
|
||||||
|
print(">>> calendar entry created for s2s post which arrived at " +
|
||||||
|
"Bob's inbox")
|
||||||
|
|
||||||
print("c2s send success\n\n\n")
|
print("c2s send success\n\n\n")
|
||||||
|
|
||||||
print('\n\nEVENT: Getting message id for the post')
|
print('\n\nEVENT: Getting message id for the post')
|
||||||
|
@ -3147,6 +3175,35 @@ def test_client_to_server(base_dir: str):
|
||||||
show_test_boxes('bob', bob_inbox_path, bob_outbox_path)
|
show_test_boxes('bob', bob_inbox_path, bob_outbox_path)
|
||||||
assert len([name for name in os.listdir(alice_inbox_path)
|
assert len([name for name in os.listdir(alice_inbox_path)
|
||||||
if os.path.isfile(os.path.join(alice_inbox_path, name))]) == 0
|
if os.path.isfile(os.path.join(alice_inbox_path, name))]) == 0
|
||||||
|
|
||||||
|
print('\n\nEVENT: Bob checks his calendar via caldav')
|
||||||
|
# test caldav result for a month
|
||||||
|
result = \
|
||||||
|
dav_month_via_server(session_bob, http_prefix,
|
||||||
|
'bob', bob_domain, bob_port, True,
|
||||||
|
test_date.year, test_date.month,
|
||||||
|
'bobpass')
|
||||||
|
print('response: ' + str(result))
|
||||||
|
assert 'VCALENDAR' in str(result)
|
||||||
|
assert 'VEVENT' in str(result)
|
||||||
|
# test caldav result for a day
|
||||||
|
result = \
|
||||||
|
dav_day_via_server(session_bob, http_prefix,
|
||||||
|
'bob', bob_domain, bob_port, True,
|
||||||
|
test_date.year, test_date.month,
|
||||||
|
test_date.day, 'bobpass')
|
||||||
|
print('response: ' + str(result))
|
||||||
|
assert 'VCALENDAR' in str(result)
|
||||||
|
assert 'VEVENT' in str(result)
|
||||||
|
# test for incorrect caldav login
|
||||||
|
result = \
|
||||||
|
dav_day_via_server(session_bob, http_prefix,
|
||||||
|
'bob', bob_domain, bob_port, True,
|
||||||
|
test_date.year, test_date.month,
|
||||||
|
test_date.day, 'wrongpass')
|
||||||
|
assert 'VCALENDAR' not in str(result)
|
||||||
|
assert 'VEVENT' not in str(result)
|
||||||
|
|
||||||
print('\n\nEVENT: Bob likes the post')
|
print('\n\nEVENT: Bob likes the post')
|
||||||
send_like_via_server(bob_dir, session_bob,
|
send_like_via_server(bob_dir, session_bob,
|
||||||
'bob', 'bobpass',
|
'bob', 'bobpass',
|
||||||
|
|
|
@ -267,6 +267,7 @@ def html_calendar(person_cache: {}, css_cache: {}, translate: {},
|
||||||
"""
|
"""
|
||||||
domain = remove_domain_port(domain_full)
|
domain = remove_domain_port(domain_full)
|
||||||
|
|
||||||
|
text_match = ''
|
||||||
default_year = 1970
|
default_year = 1970
|
||||||
default_month = 0
|
default_month = 0
|
||||||
month_number = default_month
|
month_number = default_month
|
||||||
|
@ -320,11 +321,13 @@ def html_calendar(person_cache: {}, css_cache: {}, translate: {},
|
||||||
year, month_number,
|
year, month_number,
|
||||||
day_number,
|
day_number,
|
||||||
person_cache,
|
person_cache,
|
||||||
http_prefix)
|
http_prefix,
|
||||||
|
text_match)
|
||||||
day_events = None
|
day_events = None
|
||||||
events = \
|
events = \
|
||||||
get_todays_events(base_dir, nickname, domain,
|
get_todays_events(base_dir, nickname, domain,
|
||||||
year, month_number, day_number)
|
year, month_number, day_number,
|
||||||
|
text_match)
|
||||||
if events:
|
if events:
|
||||||
if events.get(str(day_number)):
|
if events.get(str(day_number)):
|
||||||
day_events = events[str(day_number)]
|
day_events = events[str(day_number)]
|
||||||
|
@ -337,10 +340,11 @@ def html_calendar(person_cache: {}, css_cache: {}, translate: {},
|
||||||
if icalendar:
|
if icalendar:
|
||||||
return get_month_events_icalendar(base_dir, nickname, domain,
|
return get_month_events_icalendar(base_dir, nickname, domain,
|
||||||
year, month_number, person_cache,
|
year, month_number, person_cache,
|
||||||
http_prefix)
|
http_prefix, text_match)
|
||||||
|
|
||||||
events = \
|
events = \
|
||||||
get_calendar_events(base_dir, nickname, domain, year, month_number)
|
get_calendar_events(base_dir, nickname, domain, year, month_number,
|
||||||
|
text_match)
|
||||||
|
|
||||||
prev_year = year
|
prev_year = year
|
||||||
prev_month_number = month_number - 1
|
prev_month_number = month_number - 1
|
||||||
|
|
|
@ -54,7 +54,9 @@ def _add_embedded_video_from_sites(translate: {}, content: str,
|
||||||
if '"' + video_site in content:
|
if '"' + video_site in content:
|
||||||
url = content.split('"' + video_site)[1]
|
url = content.split('"' + video_site)[1]
|
||||||
if '"' in url:
|
if '"' in url:
|
||||||
url = url.split('"')[0].replace('/watch?v=', '/embed/')
|
url = url.split('"')[0]
|
||||||
|
if '/channel/' not in url:
|
||||||
|
url = url.replace('/watch?v=', '/embed/')
|
||||||
if '&' in url:
|
if '&' in url:
|
||||||
url = url.split('&')[0]
|
url = url.split('&')[0]
|
||||||
if '?utm_' in url:
|
if '?utm_' in url:
|
||||||
|
@ -71,7 +73,9 @@ def _add_embedded_video_from_sites(translate: {}, content: str,
|
||||||
if '"' + video_site in content:
|
if '"' + video_site in content:
|
||||||
url = content.split('"' + video_site)[1]
|
url = content.split('"' + video_site)[1]
|
||||||
if '"' in url:
|
if '"' in url:
|
||||||
url = 'embed/' + url.split('"')[0]
|
url = url.split('"')[0]
|
||||||
|
if '/channel/' not in url:
|
||||||
|
url = 'embed/' + url
|
||||||
if '&' in url:
|
if '&' in url:
|
||||||
url = url.split('&')[0]
|
url = url.split('&')[0]
|
||||||
if '?utm_' in url:
|
if '?utm_' in url:
|
||||||
|
|
|
@ -316,6 +316,7 @@ def _webfinger_update_vcard(wf_json: {}, actor_json: {}) -> bool:
|
||||||
"""Updates the vcard link
|
"""Updates the vcard link
|
||||||
"""
|
"""
|
||||||
for link in wf_json['links']:
|
for link in wf_json['links']:
|
||||||
|
if link.get('type'):
|
||||||
if link['type'] == 'text/vcard':
|
if link['type'] == 'text/vcard':
|
||||||
return False
|
return False
|
||||||
wf_json['links'].append({
|
wf_json['links'].append({
|
||||||
|
|
Loading…
Reference in New Issue