From 57423db1e342b48c970b972a6f18e84e7a7b1a22 Mon Sep 17 00:00:00 2001 From: "Jannis M. Hoffmann" Date: Sun, 8 Dec 2024 16:15:37 +0100 Subject: update for mail-storage version 1.1.0 Now a keyset based pagination is used instead of an offset based one. This removes the dependency flask-paginate. URL arguments are taken from the request object in the displayheaders templates instead of passing them in manually. Not needed arguments for about render_template are removed. --- pyproject.toml | 1 - src/jwebmail/__init__.py | 2 +- .../de.jmhoffmann.jwebmail.mail-storage.varlink | 35 ++++++- src/jwebmail/model/read_mails.py | 43 +++++---- src/jwebmail/templates/_bot_nav.html | 56 +++++++++-- src/jwebmail/templates/_folders.html | 6 +- src/jwebmail/templates/_main_table.html | 6 +- src/jwebmail/templates/_top_nav.html | 38 +++++++- src/jwebmail/webmail.py | 105 ++++++++++++--------- 9 files changed, 212 insertions(+), 80 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index a3f3d37..c611154 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,6 @@ dependencies = [ "Flask-Babel", "Flask-Login", "Flask-WTF", - "flask-paginate", "email-validator", "varlink", ] diff --git a/src/jwebmail/__init__.py b/src/jwebmail/__init__.py index 0a52677..8b98e7a 100644 --- a/src/jwebmail/__init__.py +++ b/src/jwebmail/__init__.py @@ -36,7 +36,7 @@ else: toml_read_file = dict(load=toml_load, text=True) -__version__ = "2.7.0.dev1" +__version__ = "2.8.0.dev0" csrf = CSRFProtect() diff --git a/src/jwebmail/model/de.jmhoffmann.jwebmail.mail-storage.varlink b/src/jwebmail/model/de.jmhoffmann.jwebmail.mail-storage.varlink index 3be999b..850ff19 100644 --- a/src/jwebmail/model/de.jmhoffmann.jwebmail.mail-storage.varlink +++ b/src/jwebmail/model/de.jmhoffmann.jwebmail.mail-storage.varlink @@ -58,23 +58,54 @@ type MIMEPart ( body: MailBody ) +# sorting by subject is deprecated type Sort ( direction: (asc, desc), - parameter: (date, size, sender) + parameter: (date, size, sender, subject) +) + +type Bound ( + param: string, + id: string ) method Init(unix_user: string, mailbox_path: string) -> () + +# deprecated: use ListSearch instead method List(folder: string, start: int, end: int, sort: Sort) -> (mail_heads: []ListMailHeader) + method Stats(folder: string) -> (mail_count: int, unread_count: int, byte_size: int) + method Show(folder: string, mid: string) -> (mail: Mail) -method Raw(folder: string, mid: string, path: ?string) -> (header: MIMEHeader, body: string) # body is base64 encoded + +# body is base64 encoded +method Raw(folder: string, mid: string, path: ?string) -> (header: MIMEHeader, body: string) + +# deprecated: use ListSearch instead method Search(folder: string, pattern: string) -> (found: []ListMailHeader) + method Folders() -> (folders: []string) + method Move(mid: string, from_folder: string, to_folder: string) -> () + method Remove(folder: string, mid: string) -> () + method AddFolder(name: string) -> (status: (created, skiped)) +method ListSearch( + folder: string, + bound: ?Bound, + direction: (after, before), + limit: int, + sort: Sort, + search: ?string +) -> ( + mail_heads: []ListMailHeader, + first: bool, + last: bool +) + error NotInitialized() error InvalidFolder(folder: string) diff --git a/src/jwebmail/model/read_mails.py b/src/jwebmail/model/read_mails.py index 8a19224..b2e1191 100644 --- a/src/jwebmail/model/read_mails.py +++ b/src/jwebmail/model/read_mails.py @@ -27,7 +27,7 @@ class QMailAuthuser: self._client = None self._connection = None - def read_headers_for(self, folder, start, end, sort): + def list_search(self, folder, bound, after, limit, sort, search): sort_val = dict() if sort[0] == "!": sort = sort[1:] @@ -41,17 +41,32 @@ class QMailAuthuser: case _: raise ValueError(f"invalid sort parameter {sort!r}") - req = self._connection.List(folder=folder, start=start, end=end, sort=sort_val) - return [ - { - "message_handle": lmh["mid"], - "byte_size": lmh["byte_size"], - "unread": lmh["unread"], - "date_received": lmh["rec_date"], - "head": self._mail_header(lmh["header"]), - } - for lmh in req["mail_heads"] - ] + if bound is not None: + param, mid = bound.split("_", 1) + bound = {"param": param, "id": mid} + + req = self._connection.ListSearch( + folder=folder, + bound=bound, + direction="after" if after else "before", + limit=limit, + sort=sort_val, + search=search, + ) + return ( + [ + { + "message_handle": lmh["mid"], + "byte_size": lmh["byte_size"], + "unread": lmh["unread"], + "date_received": lmh["rec_date"], + "head": self._mail_header(lmh["header"]), + } + for lmh in req["mail_heads"] + ], + req["first"], + req["last"], + ) def count(self, folder): resp = self._connection.Stats(folder=folder) @@ -75,10 +90,6 @@ class QMailAuthuser: "body": b64decode(resp["body"]), } - def search(self, pattern, folder): - resp = self._connection.Search(folder=folder, pattern=pattern) - return resp - def folders(self): resp = self._connection.Folders() return list(resp["folders"]) + [""] diff --git a/src/jwebmail/templates/_bot_nav.html b/src/jwebmail/templates/_bot_nav.html index 2634151..bd9e05a 100644 --- a/src/jwebmail/templates/_bot_nav.html +++ b/src/jwebmail/templates/_bot_nav.html @@ -1,7 +1,43 @@
-
- {{ pgn.links }} +
+
@@ -9,9 +45,11 @@ {% if mail_folders|length > 1 %}
- - - + + + + +
@@ -35,9 +73,11 @@ method=POST class="is-pulled-left ml-2"> - - - + + + + +
diff --git a/src/jwebmail/templates/_folders.html b/src/jwebmail/templates/_folders.html index fc4c21d..884188b 100644 --- a/src/jwebmail/templates/_folders.html +++ b/src/jwebmail/templates/_folders.html @@ -5,7 +5,7 @@