aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHugo Hörnquist <hugo@lysator.liu.se>2022-12-01 00:25:15 +0100
committerHugo Hörnquist <hugo@lysator.liu.se>2022-12-01 00:59:49 +0100
commit30c4b82bad686e2885222492f325c71d733c1260 (patch)
treef1d369bc2856f8038ca2e9018ad75daac29efb8c
parentSugest download for unknown filetypes. (diff)
downloadmu4web-30c4b82bad686e2885222492f325c71d733c1260.tar.gz
mu4web-30c4b82bad686e2885222492f325c71d733c1260.tar.xz
Documentation and cleanup.
-rw-r--r--mu4web/main.py81
-rw-r--r--mu4web/mu.py5
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).