From 30c4b82bad686e2885222492f325c71d733c1260 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Thu, 1 Dec 2022 00:25:15 +0100 Subject: Documentation and cleanup. --- mu4web/main.py | 81 ++++++++++++++++++++++++++++++---------------------------- mu4web/mu.py | 5 ++-- 2 files changed, 45 insertions(+), 41 deletions(-) diff --git a/mu4web/main.py b/mu4web/main.py index a35d7c4..19fb279 100644 --- a/mu4web/main.py +++ b/mu4web/main.py @@ -45,15 +45,18 @@ login_manager = LoginManager() def mailto(addr: str) -> HTML: + """Constructs a mailto anchor element.""" return ('a', {'href': f'mailto:{addr}'}, addr) def format_email(addr: Address) -> list[HTML]: + """Format an email address suitable for the headers of the message view.""" mail_addr = f'{addr.username}@{addr.domain}' return [addr.display_name, ' <', mailto(mail_addr), '>'] def header_format(key: str, value) -> HTML: + """Format email headers to HTML.""" if key in ['to', 'cc', 'bcc']: return ('ul', *[('li', *format_email(addr)) for addr in value.addresses]) @@ -169,7 +172,7 @@ def page_base(title: Optional[str] = None, ('menu', ('li', ('a', {'href': 'https://www.djcbsoftware.nl/code/mu/'}, 'mu')), ('li', ('a', {'href': 'https://git.hornquist.se/mu4web'}, 'Source')), - )))) + )))) def response_for(id: str, username: Optional[str] = None) -> str: @@ -193,7 +196,7 @@ def response_for(id: str, username: Optional[str] = None) -> str: all_heads = [] for key, value in mail.items(): all_heads += [('dt', key.title()), - ('dd', value)] + ('dd', value)] full_headers = ('details', ('summary', 'Alla mailhuvuden'), @@ -204,7 +207,7 @@ def response_for(id: str, username: Optional[str] = None) -> str: else: title = 'Mail' - body: HTML = [] + body: list[HTML] = [] # Manual walk to preserve attachement index for idx, at in enumerate(mail.walk()): # body.append(('h2', at.get_content_type())) @@ -230,13 +233,13 @@ def response_for(id: str, username: Optional[str] = None) -> str: tree, idx = attachement_tree(id, mail) - main_body = [('dl', *head), - full_headers, - ('hr',), - ('main', body), - ('hr',), - ('ul', tree), - ] + main_body: list[HTML] = [('dl', *head), + full_headers, + ('hr',), + ('main', body), + ('hr',), + ('ul', tree), + ] html_str = render_document(page_base(title=title, body=main_body)) @@ -248,7 +251,7 @@ def search_field(q: str) -> HTML: 'action': '/search', 'method': 'GET'}, ('label', {'for': 'search'}, - 'Mu Search Query'), + 'Sökförfrågan till Mu'), ('input', {'id': 'search', 'type': 'text', 'placeholder': 'Sök...', @@ -274,7 +277,6 @@ def search_result(q, by, reverse) -> HTML: rowdata.append(('td', ('a', {'href': '/?id=' + row['msgid']}, data))) body.append(('tr', rowdata)) - if len(rows) == 0: return "No results" else: @@ -287,7 +289,7 @@ def search_result(q, by, reverse) -> HTML: ('tbody', body))) -def search_page(q, by): +def search_page(q: str, by: Optional[mu.Sortfield] = None) -> str: main_body = [search_field(q)] if q: @@ -297,38 +299,33 @@ def search_page(q, by): body=main_body)) -def mu_info(): - d = mu.info() - rows = [] - for key, value in d.items(): - rows.append(('tr', - ('td', key), - ('td', value))) - return ('table', ('tbody', rows)) +def find_maildirs(basedir) -> dict[str, list[str]]: + """ + Find all maildirs located under basedir. + A maildir is defined as any directory which contains a `cur` + directory. -def find_maildirs(basedir) -> dict[str, list[str]]: + TODO Currently all returns are grouped by their first component, which + fails for directories directly in the root. + """ cmd = subprocess.run(['find', basedir, '-type', 'd', '-name', 'cur', '-print0'], capture_output=True) - groups = {} + groups: dict[str, list[str]] = {} # Group by first component for entry in cmd.stdout.split(b'\0'): dir = os.path.split(entry)[0][len(basedir) + 1:].decode('UTF-8') if not dir: continue parts = dir.split(os.path.sep) - groups.setdefault(parts[0], []).append(parts[1:]) + groups.setdefault(parts[0], []).append(os.path.sep.join(parts[1:])) return groups -def index_page(): - ids = [ - 'CAEzixGsw-4zJ8_ejK_vDgmcQ9s-MbBc-ho+HL4arV4a+ghOOPg@mail.gmail.com', - 'CA+pcBt-gLb0GtbFOjJ5_7Q_WXtqApVPQ9w-3O7GH=VqCEQat6g@mail.gmail.com', - ] +def index_page(): data = mu.info() groups = find_maildirs(data['maildir']) @@ -341,11 +338,14 @@ def index_page(): ('ul', [('li', ('a', {'href': 'search?' + urlencode({'q': f'maildir:"/{key}/{v}"'})}, v)) - for v in sorted(os.path.sep.join(value) for value in values)])))) - - - body = [('div', mu_info()), - ('din', ('ul', entries)), + for v in sorted(values)])))) + rows = [] + for key, value in data.items(): + rows.append(('tr', + ('td', key), + ('td', value))) + body = [('div', ('table', ('tbody', rows))), + ('div', ('ul', entries)), ] return render_document(page_base(title='Mail index', @@ -388,7 +388,8 @@ def multipart_page(msg_id: str, """ Build HTML response for a multi-part attachement. - Multi part attachements are simply containers, and can't directly be opened. Instead, build a tree of all components. + Multi part attachements are simply containers, and can't directly + be opened. Instead, build a tree of all components. [Parameters] msg_id - Message ID of the mail in question @@ -397,10 +398,10 @@ def multipart_page(msg_id: str, Needed for links to work. """ tree, idx = attachement_tree(msg_id, attachement, attachement_idx) - body = [('a', {'href': '/?' + urlencode({'id': msg_id})}, - 'Återvänd till brev'), - ('ul', tree), - ] + body: list[HTML] = [('a', {'href': '/?' + urlencode({'id': msg_id})}, + 'Återvänd till brev'), + ('ul', tree), + ] return render_document(page_base(title='Multipart', body=body)) @@ -418,6 +419,7 @@ def attachement_response(attachement: EmailMessage): return response + @app.route('/part') @login_required def attachement_part_page(): @@ -431,6 +433,7 @@ def attachement_part_page(): else: return attachement_response(attachement) + # TODO this page is really weird if you are already logged in @app.route('/login', methods=['GET']) def login_page_(): diff --git a/mu4web/mu.py b/mu4web/mu.py index c8b278e..094db6a 100644 --- a/mu4web/mu.py +++ b/mu4web/mu.py @@ -79,8 +79,9 @@ Sortfield = Union[Literal['cc'], Literal['v']] - -def search(query, sortfield: Optional[Sortfield] = 'subject', reverse: bool = False) -> list[dict[str, str]]: +def search(query: str, + sortfield: Optional[Sortfield] = 'subject', + reverse: bool = False) -> list[dict[str, str]]: """ [Parameters] query - Search query as per mu-find(1). -- cgit v1.2.3