Compare commits

..

1 Commits

Author SHA1 Message Date
holger krekel
19bbe24f07 be fine with 9 chars for password already 2023-12-07 17:10:41 +01:00
18 changed files with 90 additions and 206 deletions

View File

@@ -51,28 +51,6 @@ The `deploy.sh` script deploys
All files are generated by the according markdown `.md` file in the `www` directory.
### Refining the web pages
The `scripts/webdev.sh` script supports live development of the chatmail web presence:
```
scripts/init.sh # to locally initialize python virtual environments etc.
scripts/webdev.sh
```
- uses the `www/src/page-layout.html` file for producing html documents
from `www/src/*.md` files.
- continously builds the web presence reading files from `www/src` directory
and generating html files and copying assets to the `www/build` directory.
- Starts a browser window automatically where you can "refresh" as needed.
Note that this script is not needed for running `scripts/deploy.sh"
which deploys the whole chatmail setup remotely.
The code that generates the web pages is identical
which means that `webdev.sh` gives a pretty good preview.
### Ports
Postfix listens on ports 25 (smtp) and 587 (submission) and 465 (submissions).

View File

@@ -3,6 +3,7 @@ Chat Mail pyinfra deploy.
"""
import importlib.resources
import configparser
import textwrap
from pathlib import Path
from pyinfra import host
@@ -10,6 +11,11 @@ from pyinfra.operations import apt, files, server, systemd
from pyinfra.facts.files import File
from pyinfra.facts.systemd import SystemdEnabled
from .acmetool import deploy_acmetool
import markdown
from jinja2 import Template
from .genqr import gen_qr_png_data
def _install_chatmaild() -> None:
@@ -319,6 +325,67 @@ def get_ini_settings(mail_domain, inipath):
return settings
def build_htmlj2_from_markdown(source):
assert source.exists(), source
template_content = open(source).read()
if source.stem == "privacy":
title = "privacy {{ config.mail_domain }}"
elif source.stem == "index":
title = "home {{ config.mail_domain }}"
elif source.stem == "info":
title = "info {{ config.mail_domain }}"
html = markdown.markdown(template_content)
html = (
textwrap.dedent(
f"""\
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>{title}</title>
<link rel="stylesheet" href="./water.css">
</head>
<body>
"""
)
+ html
+ "\n"
+ textwrap.dedent(
"""\
<footer>
<a href="index.html">home</a> |
<a href="info.html">more info</a> |
<a href="privacy.html">privacy</a> |
<a href="https://github.com/deltachat/chatmail">-> public development </a>
</footer>
</body>"""
)
)
target_path = source.with_name(source.stem + ".html.j2")
with open(target_path, "w") as f:
f.write(html)
print(f"wrote {target_path}")
return target_path
def build_webpages(www_path, config):
mail_domain = config["mail_domain"]
qr_data = gen_qr_png_data(mail_domain).read()
www_path.joinpath(f"qr-chatmail-invite-{mail_domain}.png").write_bytes(qr_data)
for path in www_path.iterdir():
if path.suffix == ".md":
path = build_htmlj2_from_markdown(path)
if path.suffix == ".j2":
target = path.with_name(path.name[:-3])
template = Template(path.read_text())
with target.open("w") as f:
f.write(template.render(config=config))
def deploy_chatmail(mail_domain: str, mail_server: str, dkim_selector: str) -> None:
"""Deploy a chat-mail instance.
@@ -326,7 +393,6 @@ def deploy_chatmail(mail_domain: str, mail_server: str, dkim_selector: str) -> N
:param mail_server: the DNS name under which your mail server is reachable
:param dkim_selector:
"""
from .www import build_webpages
apt.update(name="apt update", cache_time=24 * 3600)
server.group(name="Create vmail group", group="vmail", system=True)
@@ -376,10 +442,8 @@ def deploy_chatmail(mail_domain: str, mail_server: str, dkim_selector: str) -> N
config = get_ini_settings(mail_domain, chatmail_ini)
www_path = pkg_root.joinpath("../../../www").resolve()
build_dir = www_path.joinpath("build")
src_dir = www_path.joinpath("src")
build_webpages(src_dir, build_dir, config)
files.rsync(f"{build_dir}/", "/var/www/html", flags=["-avz"])
build_webpages(www_path, config)
files.rsync(f"{www_path}/", "/var/www/html", flags=["-avz"])
_install_chatmaild()
debug = False

View File

@@ -49,10 +49,10 @@ def gen_qr(maildomain, url):
size = width = 384
qr_padding = 6
text_height = font_size * num_lines
height = size + text_height
height = size + text_height + qr_padding * 2
image = Image.new("RGBA", (width, height), "white")
qr_final_size = width
qr_final_size = width - (qr_padding * 2)
if num_lines:
draw = ImageDraw.Draw(image)

View File

@@ -1,110 +0,0 @@
import importlib.resources
import webbrowser
import hashlib
import time
import traceback
import markdown
from jinja2 import Template
from .genqr import gen_qr_png_data
from deploy_chatmail import get_ini_settings
def snapshot_dir_stats(somedir):
d = {}
for path in somedir.iterdir():
if path.is_file() and path.name[0] != "." and path.suffix != ".swp":
mtime = path.stat().st_mtime
hash = hashlib.md5(path.read_bytes()).hexdigest()
d[path] = (mtime, hash)
return d
def prepare_template(source):
assert source.exists(), source
render_vars = {}
render_vars["pagename"] = "home" if source.stem == "index" else source.stem
render_vars["markdown_html"] = markdown.markdown(source.read_text())
page_layout = source.with_name("page-layout.html").read_text()
return render_vars, page_layout
def build_webpages(src_dir, build_dir, config):
try:
_build_webpages(src_dir, build_dir, config)
except Exception:
print(traceback.format_exc())
def _build_webpages(src_dir, build_dir, config):
mail_domain = config["mail_domain"]
assert src_dir.exists(), src_dir
if not build_dir.exists():
build_dir.mkdir()
qr_path = build_dir.joinpath(f"qr-chatmail-invite-{mail_domain}.png")
qr_path.write_bytes(gen_qr_png_data(mail_domain).read())
for path in src_dir.iterdir():
if path.suffix == ".md":
render_vars, content = prepare_template(path)
target = build_dir.joinpath(path.stem + ".html")
# recursive jinja2 rendering
while 1:
new = Template(content).render(config=config, **render_vars)
if new == content:
break
content = new
with target.open("w") as f:
f.write(content)
elif path.name != "page-layout.html":
target = build_dir.joinpath(path.name)
target.write_bytes(path.read_bytes())
return build_dir
def main():
chatmail_domain = "example.testrun.org"
path = importlib.resources.files(__package__)
reporoot = path.joinpath("../../../").resolve()
inipath = reporoot.joinpath("chatmail.ini")
config = get_ini_settings(chatmail_domain, inipath)
config["webdev"] = True
www_path = reporoot.joinpath("www")
src_path = www_path.joinpath("src")
stats = None
build_dir = www_path.joinpath("build")
src_dir = www_path.joinpath("src")
index_path = build_dir.joinpath("index.html")
# start web page generation, open a browser and wait for changes
build_webpages(src_dir, build_dir, config)
webbrowser.open(str(index_path))
stats = snapshot_dir_stats(src_path)
print(f"\nOpened URL: file://{index_path.resolve()}\n")
print(f"watching {src_path} directory for changes")
changenum = 0
for count in range(0, 1000000):
newstats = snapshot_dir_stats(src_path)
if newstats == stats and count % 60 != 0:
count += 1
time.sleep(1.0)
continue
for key in newstats:
if stats[key] != newstats[key]:
print(f"*** CHANGED: {key}")
changenum += 1
stats = newstats
build_webpages(src_dir, build_dir, config)
print(f"[{changenum}] regenerated web pages at: {index_path}")
print(f"URL: file://{index_path.resolve()}\n\n")
count = 0
if __name__ == "__main__":
main()

View File

@@ -3,6 +3,6 @@ set -e
python3 -m venv venv
pip=venv/bin/pip
$pip install pyinfra pytest build 'setuptools>=68' tox
$pip install pyinfra pytest build 'setuptools>=68' tox deltachat
$pip install -e deploy-chatmail
$pip install -e chatmaild

View File

@@ -1,9 +0,0 @@
#!/usr/bin/env bash
echo -----------------------------------------
echo starting local webdev
echo -----------------------------------------
venv/bin/python3 -m deploy_chatmail.www

View File

@@ -3,7 +3,6 @@ import json
import chatmaild
from chatmaild.newemail import create_newemail_dict, print_new_account
def test_create_newemail_dict():
ac1 = create_newemail_dict(domain="example.org")
assert "@" in ac1["email"]

View File

@@ -278,13 +278,13 @@ class ChatmailTestProcess:
@pytest.fixture
def cmfactory(request, gencreds, tmpdir, maildomain):
def cmfactory(request, gencreds, tmpdir, data, maildomain):
# cloned from deltachat.testplugin.amfactory
pytest.importorskip("deltachat")
from deltachat.testplugin import ACFactory
testproc = ChatmailTestProcess(request.config, maildomain, gencreds)
am = ACFactory(request=request, tmpdir=tmpdir, testprocess=testproc, data=None)
am = ACFactory(request=request, tmpdir=tmpdir, testprocess=testproc, data=data)
# nb. a bit hacky
# would probably be better if deltachat's test machinery grows native support
@@ -326,18 +326,6 @@ class Remote:
break
@pytest.fixture
def lp(request):
class LP:
def sec(self, msg):
print(f"---- {msg} ----")
def indent(self, msg):
print(f" {msg}")
return LP()
@pytest.fixture
def maildata(request, gencreds):
datadir = conftestdir.joinpath("mail-data")

View File

@@ -1,3 +1,5 @@
from deploy_chatmail.genqr import gen_qr_png_data

View File

@@ -1,11 +1,19 @@
import textwrap
import importlib.resources
from deploy_chatmail.www import build_webpages
from deploy_chatmail import get_ini_settings
from deploy_chatmail import build_htmlj2_from_markdown, get_ini_settings
def create_ini(inipath):
def test_markdown(tmp_path):
path = tmp_path.joinpath("privacy.md")
path.write_text("# privacy policy")
build_htmlj2_from_markdown(path)
output = path.with_name("privacy.html.j2")
assert output.exists()
print(output.read_text())
def test_get_settings(tmp_path):
inipath = tmp_path.joinpath("chatmail.ini")
inipath.write_text(
textwrap.dedent(
"""\
@@ -22,26 +30,10 @@ def create_ini(inipath):
"""
)
)
def test_build_webpages(tmp_path):
pkgroot = importlib.resources.files("deploy_chatmail")
src_dir = pkgroot.joinpath("../../../www/src").resolve()
assert src_dir.exists(), src_dir
inipath = tmp_path.joinpath("chatmail.ini")
create_ini(inipath)
config = get_ini_settings("example.org", inipath)
build_dir = tmp_path.joinpath("build")
build_webpages(src_dir, build_dir, config)
def test_get_settings(tmp_path):
inipath = tmp_path.joinpath("chatmail.ini")
create_ini(inipath)
d = get_ini_settings("x.testrun.org", inipath)
assert d["privacy_postal"] == "address-line1\naddress-line2"
assert d["privacy_mail"] == "privacy@example.org"
assert d["privacy_pdo"] == "address-line3"
assert d["mail_domain"] == "x.testrun.org"

View File

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 67 KiB

View File

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

View File

@@ -1,20 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
{% if config.webdev %}
<meta http-equiv="refresh" content="3">
{% endif %}
<title>{{ config.mail_domain }} {{ pagename }}</title>
<link rel="stylesheet" href="./water.css">
</head>
<body>
{{ markdown_html }}
<footer>
<a href="index.html">home</a> |
<a href="info.html">more info</a> |
<a href="privacy.html">privacy</a> |
<a href="https://github.com/deltachat/chatmail">-> public development </a>
</footer>
</body>
</html>