[ini]
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
/temp/
|
||||
/build/
|
||||
**/__pycache__
|
417
source/data.json
Normal file
|
@ -0,0 +1,417 @@
|
|||
{
|
||||
"meta": {
|
||||
"author": "Christian Fraß",
|
||||
"date": "2024-07-11",
|
||||
"title": "Digitale Infrastruktur für DIE LINKE.",
|
||||
"contact": {
|
||||
"email_address": "christian.frass@dielinke-glauchau.de"
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"theory": [
|
||||
{
|
||||
"text": "Wie setzt man einen Web-Dienst mit ausgelagerter Anmeldung auf?",
|
||||
"image": "services-0"
|
||||
},
|
||||
{
|
||||
"text": "Zunächst wird eine Datenbank eingerichtet",
|
||||
"image": "services-1"
|
||||
},
|
||||
{
|
||||
"text": "Weiterhin wird ein Web-Server benötigt",
|
||||
"image": "services-2"
|
||||
},
|
||||
{
|
||||
"text": "Zudem soll ein Authentifizierungs-Dienst zum Einsatz kommen",
|
||||
"image": "services-3"
|
||||
},
|
||||
{
|
||||
"text": "… dieser benötigt in der Regel eine Datenbank-Anbindung",
|
||||
"image": "services-4"
|
||||
},
|
||||
{
|
||||
"text": "… und soll über den Web-Server von außen erreichbar sein",
|
||||
"image": "services-5"
|
||||
},
|
||||
{
|
||||
"text": "Der eigentliche Dienst …",
|
||||
"image": "services-6"
|
||||
},
|
||||
{
|
||||
"text": "… benötigt ebenfalls eine Datenbank-Anbindung",
|
||||
"image": "services-7"
|
||||
},
|
||||
{
|
||||
"text": "… soll den Authentifizierungs-Dienst nutzen",
|
||||
"image": "services-8"
|
||||
},
|
||||
{
|
||||
"text": "… und über den Web-Server angesprochen werden",
|
||||
"image": "services-9"
|
||||
}
|
||||
],
|
||||
"practice": {
|
||||
"example": {
|
||||
"link": "https://linke.sx",
|
||||
"label": "linke.sx"
|
||||
},
|
||||
"technologies": {
|
||||
"pool": {
|
||||
"debian": {
|
||||
"name": "Debian GNU/Linux",
|
||||
"link": "https://www.debian.org/",
|
||||
"icon": null,
|
||||
"desc": "Betriebssystem"
|
||||
},
|
||||
"ansible": {
|
||||
"name": "Ansible",
|
||||
"link": "https://www.ansible.com/",
|
||||
"icon": null,
|
||||
"desc": "IAC-Plattform"
|
||||
},
|
||||
"keepassxc": {
|
||||
"name": "KeePassXC",
|
||||
"link": "https://keepassxc.org/",
|
||||
"icon": null,
|
||||
"desc": "Passwort-Verwaltung"
|
||||
},
|
||||
"letsencrypt": {
|
||||
"name": "Let's Encrypt",
|
||||
"link": "https://letsencrypt.org/",
|
||||
"icon": null,
|
||||
"desc": "TLS-Zertifikats-Erstellung"
|
||||
},
|
||||
"inwx": {
|
||||
"name": "INWX",
|
||||
"link": "https://www.inwx.de/",
|
||||
"icon": null,
|
||||
"desc": "Domänen-Registrar"
|
||||
}
|
||||
},
|
||||
"order": [
|
||||
"debian",
|
||||
"ansible",
|
||||
"keepassxc",
|
||||
"inwx",
|
||||
"letsencrypt"
|
||||
]
|
||||
},
|
||||
"basics": {
|
||||
"pool": {
|
||||
"postgresql": {
|
||||
"name": "PostgreSQL",
|
||||
"link": "https://www.postgresql.org/",
|
||||
"icon": null,
|
||||
"desc": "Datenbank-Server"
|
||||
},
|
||||
"nginx": {
|
||||
"name": "nginx",
|
||||
"link": "https://nginx.org/",
|
||||
"icon": null,
|
||||
"desc": "Web-Server und Lastenverteiler"
|
||||
},
|
||||
"authelia": {
|
||||
"name": "Authelia",
|
||||
"link": "https://www.authelia.com/",
|
||||
"icon": null,
|
||||
"desc": "Auth-Server"
|
||||
}
|
||||
},
|
||||
"order": [
|
||||
"postgresql",
|
||||
"nginx",
|
||||
"authelia"
|
||||
]
|
||||
},
|
||||
"concrete_present": {
|
||||
"pool": {
|
||||
"synapse": {
|
||||
"name": "Synapse",
|
||||
"link": "https://github.com/element-hq/synapse",
|
||||
"icon": "https://matrix.org/images/matrix-favicon.svg",
|
||||
"desc": "Chat-Server"
|
||||
},
|
||||
"element": {
|
||||
"name": "Element",
|
||||
"link": "https://element.io/",
|
||||
"icon": "https://element.io/images/webclip.png",
|
||||
"desc": "Chat-Client für Browser"
|
||||
},
|
||||
"hedgedoc": {
|
||||
"name": "Hedgedoc",
|
||||
"link": "https://hedgedoc.org/",
|
||||
"icon": "https://informatik-box.de/images/hedgedoc.png",
|
||||
"desc": "Notizen"
|
||||
},
|
||||
"gitlab": {
|
||||
"name": "GitLab",
|
||||
"link": "https://about.gitlab.com/",
|
||||
"icon": "https://about.gitlab.com/nuxt-images/ico/favicon-192x192.png",
|
||||
"desc": "Code-Management und Aufgabenverwaltung",
|
||||
"stat": "present"
|
||||
},
|
||||
"forgejo": {
|
||||
"name": "Forgejo",
|
||||
"link": "https://forgejo.org/",
|
||||
"icon": "https://forgejo.org/favicon.png",
|
||||
"desc": "Code-Management und Aufgabenverwaltung"
|
||||
},
|
||||
"vikunja": {
|
||||
"name": "Vikunja",
|
||||
"link": "https://vikunja.io/",
|
||||
"icon": "https://vikunja.io/favicon.svg",
|
||||
"desc": "Aufgabenverwaltung und Kalender"
|
||||
},
|
||||
"dokuwiki": {
|
||||
"name": "Dokuwiki",
|
||||
"link": "https://www.dokuwiki.org/dokuwiki",
|
||||
"icon": "https://www.dokuwiki.org/lib/tpl/dokuwiki/images/logo.png",
|
||||
"desc": "Wissensspeicher"
|
||||
},
|
||||
"owncloud": {
|
||||
"name": "ownCloud",
|
||||
"link": "https://owncloud.com/de/infinite-scale/",
|
||||
"icon": "https://owncloud.com/wp-content/themes/ownCloud/dist/assets/img/favicon/apple-touch-icon.png",
|
||||
"desc": "Datenablage"
|
||||
},
|
||||
"murmur": {
|
||||
"name": "Murmur",
|
||||
"link": "https://www.mumble.info/",
|
||||
"icon": "https://www.mumble.info/css/mumble.svg",
|
||||
"desc": "Audiokonferenzen (bislang ohne Authentifizierung)"
|
||||
}
|
||||
},
|
||||
"order": [
|
||||
"synapse",
|
||||
"element",
|
||||
"murmur",
|
||||
"hedgedoc",
|
||||
"dokuwiki",
|
||||
"owncloud",
|
||||
"vikunja",
|
||||
"gitlab",
|
||||
"forgejo"
|
||||
]
|
||||
},
|
||||
"concrete_planned": {
|
||||
"pool": {
|
||||
"bigbluebutton": {
|
||||
"name": "BigBlueButton",
|
||||
"link": "https://bigbluebutton.org/",
|
||||
"icon": null,
|
||||
"desc": "Videokonferenzen",
|
||||
"stat": "planned"
|
||||
},
|
||||
"mastodon": {
|
||||
"name": "Mastodon",
|
||||
"link": "https://joinmastodon.org",
|
||||
"icon": "https://creazilla-store.fra1.digitaloceanspaces.com/icons/3204993/logo-mastodon-icon-sm.png",
|
||||
"desc": "Microblogging",
|
||||
"stat": "planned"
|
||||
},
|
||||
"grav": {
|
||||
"name": "grav",
|
||||
"link": "https://getgrav.org/",
|
||||
"icon": "https://getgrav.org/user/themes/planetoid/images/favicon.png",
|
||||
"desc": "Web-Inhaltsverwaltung",
|
||||
"stat": "planned"
|
||||
},
|
||||
"dovecot": {
|
||||
"name": "Dovecot",
|
||||
"link": "https://doc.dovecot.org/",
|
||||
"icon": "https://w2.influxdata.com/wp-content/uploads/dovecot-logo.png",
|
||||
"desc": "E-Mail-Empfang",
|
||||
"stat": "planned"
|
||||
},
|
||||
"postfix": {
|
||||
"name": "Postfix",
|
||||
"link": "https://www.postfix.org/",
|
||||
"icon": "https://webhostinggeeks.com/howto/wp-content/uploads/2012/06/Posfix-Mail.jpg",
|
||||
"desc": "E-Mail-Versand",
|
||||
"stat": "planned"
|
||||
}
|
||||
},
|
||||
"order": [
|
||||
"postfix",
|
||||
"dovecot",
|
||||
"mastodon",
|
||||
"grav"
|
||||
]
|
||||
}
|
||||
},
|
||||
"alternatives": {
|
||||
"list": [
|
||||
"MS Exchange",
|
||||
"Google",
|
||||
"facebook",
|
||||
"WhatsApp/Telegram/Signal",
|
||||
"Dropbox",
|
||||
"Nextcloud",
|
||||
"Humhub",
|
||||
"Zetkin",
|
||||
"…"
|
||||
],
|
||||
"problems": [
|
||||
"zentralisiert",
|
||||
"proprietär",
|
||||
"datenschutzverletzend",
|
||||
"zwielichtig",
|
||||
"überladen",
|
||||
"unterladen",
|
||||
"kompliziert",
|
||||
"unflexibel",
|
||||
"kaputt"
|
||||
]
|
||||
}
|
||||
},
|
||||
"user_management": {
|
||||
"schema": [
|
||||
{
|
||||
"text": "Die Dienste stehen bereit, aber wer darf sie verwenden?",
|
||||
"image": "user_management-0"
|
||||
},
|
||||
{
|
||||
"text": "Espe als Nutzerverwaltung …",
|
||||
"image": "user_management-1"
|
||||
},
|
||||
{
|
||||
"text": "… hat einen typischen technischen Aufbau",
|
||||
"image": "user_management-2"
|
||||
},
|
||||
{
|
||||
"text": "… und kann den Authentifizierungs-Dienst füttern",
|
||||
"image": "user_management-3"
|
||||
},
|
||||
{
|
||||
"text": "MGL …",
|
||||
"image": "user_management-4"
|
||||
},
|
||||
{
|
||||
"text": "… ist über den Browser bedienbar",
|
||||
"image": "user_management-5"
|
||||
},
|
||||
{
|
||||
"text": "… hat anscheinend auch einen typischen technischen Aufbau",
|
||||
"image": "user_management-6"
|
||||
},
|
||||
{
|
||||
"text": "… und kann erweitert werden :)",
|
||||
"image": "user_management-7"
|
||||
},
|
||||
{
|
||||
"text": "… und damit als Quelle für Espe und den Authentifizierungs-Dienst dienen",
|
||||
"image": "user_management-8"
|
||||
}
|
||||
],
|
||||
"processes": {
|
||||
"entry": [
|
||||
{
|
||||
"text": "Bei Eintritt legt ein Mitgliederbeauftragter einen Datensatz in MGL an",
|
||||
"image": "user_management-9"
|
||||
},
|
||||
{
|
||||
"text": "Datensatz landet in MGL-BE/MGL-DB",
|
||||
"image": "user_management-10"
|
||||
},
|
||||
{
|
||||
"text": "Syncer liest Mitglieder aus und gleicht in Richtung Espe ab",
|
||||
"image": "user_management-11"
|
||||
},
|
||||
{
|
||||
"text": "Espe erzeugt für jeden neuen Nutzerdatensatz ein Passwort und sendet E-Mail",
|
||||
"image": "user_management-12"
|
||||
},
|
||||
{
|
||||
"text": "… und schickt die neue Nutzerliste an den Authentifizierungs-Dienst",
|
||||
"image": "user_management-13"
|
||||
}
|
||||
]
|
||||
},
|
||||
"example": {
|
||||
"link": "https://zackeneule.linke.sx/",
|
||||
"label": "zackeneule.linke.sx",
|
||||
"remark": " (keine MGL-Anbindung)"
|
||||
}
|
||||
},
|
||||
"realization": {
|
||||
"todos_technical": [
|
||||
{
|
||||
"name": "Entwickler gewinnen",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "Penetrationstests durchführen",
|
||||
"link": "https://de.m.wikipedia.org/wiki/Penetrationstest_(Informatik)"
|
||||
},
|
||||
{
|
||||
"name": "Lastverteilung vorsehen",
|
||||
"link": "https://de.m.wikipedia.org/wiki/Lastverteilung_(Informatik)"
|
||||
},
|
||||
{
|
||||
"name": "Datensicherung einrichten",
|
||||
"link": "https://de.m.wikipedia.org/wiki/Datensicherung"
|
||||
},
|
||||
{
|
||||
"name": "Überwachung einrichten",
|
||||
"link": "https://de.m.wikipedia.org/wiki/Monitoring"
|
||||
}
|
||||
],
|
||||
"todos_social": [
|
||||
{
|
||||
"name": "Kräfte bündeln",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "Tester gewinnen",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "Admins gewinnen",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "Überzeugungsarbeit leisten",
|
||||
"link": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
"name": "Ansible-Rollen für Dienste",
|
||||
"link": "https://gitlab.die-linke.cloud/misc/ansible-base"
|
||||
},
|
||||
{
|
||||
"name": "Infrastruktur-Definition für LAG Netzpolitik Sachsen",
|
||||
"link": "https://gitlab.die-linke.cloud/misc/infrastructure"
|
||||
},
|
||||
{
|
||||
"name": "Espe | Datenmodell",
|
||||
"link": "https://gitlab.die-linke.cloud/espe/datamodel"
|
||||
},
|
||||
{
|
||||
"name": "Espe | Backend",
|
||||
"link": "https://gitlab.die-linke.cloud/espe/backend"
|
||||
},
|
||||
{
|
||||
"name": "Espe | Frontend | Web",
|
||||
"link": "https://gitlab.die-linke.cloud/espe/frontend-zackeneule"
|
||||
},
|
||||
{
|
||||
"name": "Espe | Frontend | CLI",
|
||||
"link": "https://gitlab.die-linke.cloud/espe/frontend-mondvogel"
|
||||
},
|
||||
{
|
||||
"name": "Espe | Ansible-Rollen",
|
||||
"link": "https://gitlab.die-linke.cloud/espe/infrastructure"
|
||||
},
|
||||
{
|
||||
"name": "MGL-CLI-Client",
|
||||
"link": "https://gitlab.die-linke.cloud/misc/mgl-cli"
|
||||
},
|
||||
{
|
||||
"name": "MGL-Espe-Syncer",
|
||||
"link": "https://gitlab.die-linke.cloud/misc/mgl-espe-syncer"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
619
source/graphs
Executable file
|
@ -0,0 +1,619 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import os as _os
|
||||
import sys as _sys
|
||||
import json as _json
|
||||
import argparse as _argparse
|
||||
|
||||
from lib import *
|
||||
|
||||
|
||||
def hue_regular():
|
||||
return 0.4
|
||||
|
||||
|
||||
def hue_highlight():
|
||||
return 0.0
|
||||
|
||||
|
||||
def style(level, step):
|
||||
return ("invis" if (step < level) else "filled")
|
||||
|
||||
|
||||
def style_new(predicate):
|
||||
return (
|
||||
"filled"
|
||||
if predicate() else
|
||||
"invis"
|
||||
)
|
||||
|
||||
|
||||
def highlight(predicate):
|
||||
return (
|
||||
{
|
||||
"fillcolor": ("%.4f+0.75+0.5" % (hue_highlight(), )),
|
||||
"color": ("%.4f+0.75+0.5" % (hue_highlight(), )),
|
||||
}
|
||||
if predicate() else
|
||||
{
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def render(input_, data, format_, path_output):
|
||||
path_temp = "/tmp/graph.gv"
|
||||
_os.makedirs(_os.path.dirname(path_temp), exist_ok = True)
|
||||
file_write(
|
||||
path_temp,
|
||||
string_coin(
|
||||
input_,
|
||||
data
|
||||
)
|
||||
)
|
||||
_os.makedirs(_os.path.dirname(path_output), exist_ok = True)
|
||||
_os.system(
|
||||
string_coin(
|
||||
"cat {{path_source}} | dot -T {{format}} > {{path_output}}",
|
||||
{
|
||||
"path_source": path_temp,
|
||||
"path_output": path_output,
|
||||
"format": format_,
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def attributes_subgraph():
|
||||
return {
|
||||
"fontname": "monospace",
|
||||
"fontcolor": ("%.4f+0+1" % (hue_regular(), )),
|
||||
"color": ("%.4f+0.25+0.25" % (hue_regular(), )),
|
||||
"fillcolor": ("%.4f+0.25+0.25" % (hue_regular(), )),
|
||||
}
|
||||
|
||||
|
||||
def dot_macro_services(conf):
|
||||
return dot_graph(
|
||||
{
|
||||
"name": "services",
|
||||
"settings": {
|
||||
"graph": {
|
||||
"layout": "dot",
|
||||
"rankdir": "BT",
|
||||
"bgcolor": "0.4+0+0.125",
|
||||
},
|
||||
"node": {
|
||||
"fontname": "monospace",
|
||||
"shape": "hexagon",
|
||||
"style": "filled",
|
||||
"fillcolor": "0.4+0.75+0.5",
|
||||
"color": "0.4+0.75+0.5",
|
||||
"fontcolor": "0.4+0+1",
|
||||
},
|
||||
"edge": {
|
||||
"fontname": "monospace",
|
||||
"color": "0.4+0+0.75",
|
||||
}
|
||||
},
|
||||
"nodes": [
|
||||
{
|
||||
"name": "node_db",
|
||||
"attributes": {
|
||||
"label": "DB-Server",
|
||||
"style": style_new(lambda: (conf["step"] >= 1)),
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "node_web",
|
||||
"attributes": {
|
||||
"label": "Web-Server",
|
||||
"style": style_new(lambda: (conf["step"] >= 2)),
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "node_auth",
|
||||
"attributes": {
|
||||
"label": "Auth-Server",
|
||||
"style": style_new(lambda: (conf["step"] >= 3)),
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "node_db_for_auth",
|
||||
"attributes": {
|
||||
"label": "DB-Modul\nfür\nAuth-Server",
|
||||
"style": style_new(lambda: (conf["step"] >= 4)),
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "node_auth_and_web",
|
||||
"attributes": {
|
||||
"label": "Web-Modul\nfür\nAuth-Server",
|
||||
"style": style_new(lambda: (conf["step"] >= 5)),
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "node_service",
|
||||
"attributes": {
|
||||
"label": "Dienst",
|
||||
"style": style_new(lambda: (conf["step"] >= 6)),
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "node_db_for_service",
|
||||
"attributes": {
|
||||
"label": "DB-Modul\nfür\nDienst",
|
||||
"style": style_new(lambda: (conf["step"] >= 7)),
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "node_auth_for_service",
|
||||
"attributes": {
|
||||
"label": "Auth-Modul\nfür\nDienst",
|
||||
"style": style_new(lambda: (conf["step"] >= 8)),
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "node_service_and_web",
|
||||
"attributes": {
|
||||
"label": "Web-Modul\nfür\nDienst",
|
||||
"style": style_new(lambda: (conf["step"] >= 9)),
|
||||
},
|
||||
},
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"name_from": "node_db",
|
||||
"name_to": "node_db_for_auth",
|
||||
"attributes": {
|
||||
"style": style_new(lambda: (conf["step"] >= 4)),
|
||||
},
|
||||
},
|
||||
{
|
||||
"name_from": "node_db_for_auth",
|
||||
"name_to": "node_auth",
|
||||
"attributes": {
|
||||
"style": style_new(lambda: (conf["step"] >= 4)),
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
"name_from": "node_auth",
|
||||
"name_to": "node_auth_and_web",
|
||||
"attributes": {
|
||||
"style": style_new(lambda: (conf["step"] >= 5)),
|
||||
},
|
||||
},
|
||||
{
|
||||
"name_from": "node_web",
|
||||
"name_to": "node_auth_and_web",
|
||||
"attributes": {
|
||||
"style": style_new(lambda: (conf["step"] >= 5)),
|
||||
},
|
||||
},
|
||||
{
|
||||
"name_from": "node_db",
|
||||
"name_to": "node_db_for_service",
|
||||
"attributes": {
|
||||
"style": style_new(lambda: (conf["step"] >= 7)),
|
||||
},
|
||||
},
|
||||
{
|
||||
"name_from": "node_db_for_service",
|
||||
"name_to": "node_service",
|
||||
"attributes": {
|
||||
"style": style_new(lambda: (conf["step"] >= 7)),
|
||||
},
|
||||
},
|
||||
{
|
||||
"name_from": "node_auth",
|
||||
"name_to": "node_auth_for_service",
|
||||
"attributes": {
|
||||
"style": style_new(lambda: (conf["step"] >= 8)),
|
||||
},
|
||||
},
|
||||
{
|
||||
"name_from": "node_auth_for_service",
|
||||
"name_to": "node_service",
|
||||
"attributes": {
|
||||
"style": style_new(lambda: (conf["step"] >= 8)),
|
||||
},
|
||||
},
|
||||
{
|
||||
"name_from": "node_service",
|
||||
"name_to": "node_service_and_web",
|
||||
"attributes": {
|
||||
"style": style_new(lambda: (conf["step"] >= 9)),
|
||||
},
|
||||
},
|
||||
{
|
||||
"name_from": "node_web",
|
||||
"name_to": "node_service_and_web",
|
||||
"attributes": {
|
||||
"style": style_new(lambda: (conf["step"] >= 9)),
|
||||
},
|
||||
},
|
||||
],
|
||||
"subgraphs": [
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def dot_macro_user_management(conf):
|
||||
return dot_graph(
|
||||
{
|
||||
"name": "user_management",
|
||||
"settings": {
|
||||
"graph": {
|
||||
"layout": "dot",
|
||||
"rankdir": "BT",
|
||||
"bgcolor": "0.4+0+0.125",
|
||||
},
|
||||
"node": {
|
||||
"fontname": "monospace",
|
||||
"shape": "hexagon",
|
||||
"style": "filled",
|
||||
"fillcolor": "0.4+0.75+0.5",
|
||||
"color": "0.4+0.75+0.5",
|
||||
"fontcolor": "0.4+0+1",
|
||||
},
|
||||
"edge": {
|
||||
"fontname": "monospace",
|
||||
"color": "0.4+0+0.75",
|
||||
}
|
||||
},
|
||||
"nodes": [
|
||||
{
|
||||
"name": "node_9",
|
||||
"attributes": (
|
||||
{
|
||||
"label": "Syncer",
|
||||
"style": style_new(lambda: (conf["step"] >= 8)),
|
||||
}
|
||||
|
|
||||
highlight(lambda: (conf["step"] == 11))
|
||||
)
|
||||
},
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"name_from": "node_6",
|
||||
"name_to": "node_11",
|
||||
"attributes": {
|
||||
"style": style_new(lambda: (conf["step"] >= 3)),
|
||||
}
|
||||
},
|
||||
{
|
||||
"name_from": "node_4",
|
||||
"name_to": "node_9",
|
||||
"attributes": {
|
||||
"dir": "forward",
|
||||
"style": style_new(lambda: (conf["step"] >= 8)),
|
||||
}
|
||||
},
|
||||
{
|
||||
"name_from": "node_8",
|
||||
"name_to": "node_9",
|
||||
"attributes": {
|
||||
"dir": "both",
|
||||
"style": style_new(lambda: (conf["step"] >= 8)),
|
||||
}
|
||||
},
|
||||
],
|
||||
"subgraphs": [
|
||||
{
|
||||
"name": "3",
|
||||
"attributes": (
|
||||
attributes_subgraph()
|
||||
|
|
||||
{
|
||||
"label": "MGL",
|
||||
"style": style_new(lambda: (conf["step"] >= 4)),
|
||||
}
|
||||
),
|
||||
"nodes": [
|
||||
{
|
||||
"name": "node_1",
|
||||
"attributes": (
|
||||
{
|
||||
"label": "MGL-DB",
|
||||
"style": style_new(lambda: (conf["step"] >= 6)),
|
||||
}
|
||||
|
|
||||
highlight(lambda: (conf["step"] == 10))
|
||||
)
|
||||
},
|
||||
{
|
||||
"name": "node_2",
|
||||
"attributes": (
|
||||
{
|
||||
"label": "MGL-BE",
|
||||
"style": style_new(lambda: (conf["step"] >= 6)),
|
||||
}
|
||||
|
|
||||
highlight(lambda: (conf["step"] == 10))
|
||||
)
|
||||
},
|
||||
{
|
||||
"name": "node_3",
|
||||
"attributes": (
|
||||
{
|
||||
"label": "MGL-FE-Web",
|
||||
"style": style_new(lambda: (conf["step"] >= 5)),
|
||||
}
|
||||
|
|
||||
highlight(lambda: (conf["step"] == 9))
|
||||
)
|
||||
},
|
||||
{
|
||||
"name": "node_4",
|
||||
"attributes": (
|
||||
{
|
||||
"label": "MGL-FE-CLI",
|
||||
"style": style_new(lambda: (conf["step"] >= 7)),
|
||||
}
|
||||
|
|
||||
highlight(lambda: (conf["step"] == 11))
|
||||
)
|
||||
},
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"name_from": "node_1",
|
||||
"name_to": "node_2",
|
||||
"attributes": {
|
||||
"dir": "both",
|
||||
"style": style_new(lambda: (conf["step"] >= 6)),
|
||||
}
|
||||
},
|
||||
{
|
||||
"name_from": "node_2",
|
||||
"name_to": "node_3",
|
||||
"attributes": {
|
||||
"dir": "both",
|
||||
"style": style_new(lambda: (conf["step"] >= 6)),
|
||||
}
|
||||
},
|
||||
{
|
||||
"name_from": "node_2",
|
||||
"name_to": "node_4",
|
||||
"attributes": {
|
||||
"dir": "forward",
|
||||
"style": style_new(lambda: (conf["step"] >= 7)),
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "2",
|
||||
"attributes": (
|
||||
attributes_subgraph()
|
||||
|
|
||||
{
|
||||
"label": "Espe",
|
||||
"style": style_new(lambda: (conf["step"] >= 1)),
|
||||
}
|
||||
),
|
||||
"nodes": [
|
||||
{
|
||||
"name": "node_5",
|
||||
"attributes": (
|
||||
{
|
||||
"label": "Espe-DB",
|
||||
"style": style_new(lambda: (conf["step"] >= 2)),
|
||||
}
|
||||
|
|
||||
highlight(lambda: (conf["step"] == 12))
|
||||
)
|
||||
},
|
||||
{
|
||||
"name": "node_6",
|
||||
"attributes": (
|
||||
{
|
||||
"label": "Espe-BE",
|
||||
"style": style_new(lambda: (conf["step"] >= 2)),
|
||||
}
|
||||
|
|
||||
highlight(lambda: (conf["step"] == 12))
|
||||
)
|
||||
},
|
||||
{
|
||||
"name": "node_8",
|
||||
"attributes": (
|
||||
{
|
||||
"label": "Espe-FE-CLI",
|
||||
"style": style_new(lambda: (conf["step"] >= 2)),
|
||||
}
|
||||
|
|
||||
highlight(lambda: (conf["step"] == 11))
|
||||
)
|
||||
},
|
||||
{
|
||||
"name": "node_7",
|
||||
"attributes": (
|
||||
{
|
||||
"label": "Espe-FE-Web",
|
||||
"style": style_new(lambda: (conf["step"] >= 2)),
|
||||
}
|
||||
)
|
||||
},
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"name_from": "node_5",
|
||||
"name_to": "node_6",
|
||||
"attributes": {
|
||||
"dir": "both",
|
||||
"style": style_new(lambda: (conf["step"] >= 2)),
|
||||
}
|
||||
},
|
||||
{
|
||||
"name_from": "node_6",
|
||||
"name_to": "node_7",
|
||||
"attributes": {
|
||||
"dir": "both",
|
||||
"style": style_new(lambda: (conf["step"] >= 2)),
|
||||
}
|
||||
},
|
||||
{
|
||||
"name_from": "node_6",
|
||||
"name_to": "node_8",
|
||||
"attributes": {
|
||||
"dir": "both",
|
||||
"style": style_new(lambda: (conf["step"] >= 2)),
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "1",
|
||||
"attributes": (
|
||||
attributes_subgraph()
|
||||
|
|
||||
{
|
||||
"label": "Dienste",
|
||||
"style": style_new(lambda: (conf["step"] >= 0)),
|
||||
}
|
||||
),
|
||||
"nodes": [
|
||||
{
|
||||
"name": "node_10",
|
||||
"attributes": {
|
||||
"label": "…",
|
||||
"style": style_new(lambda: (conf["step"] >= 0)),
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "node_11",
|
||||
"attributes": (
|
||||
{
|
||||
"label": "Auth-Server",
|
||||
"style": style_new(lambda: (conf["step"] >= 0)),
|
||||
}
|
||||
|
|
||||
highlight(lambda: (conf["step"] == 13))
|
||||
)
|
||||
},
|
||||
{
|
||||
"name": "node_12",
|
||||
"attributes": {
|
||||
"label": "…",
|
||||
"style": style_new(lambda: (conf["step"] >= 0)),
|
||||
}
|
||||
},
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"name_from": "node_10",
|
||||
"name_to": "node_11",
|
||||
"attributes": {
|
||||
"dir": "both",
|
||||
"style": style_new(lambda: (conf["step"] >= 0)),
|
||||
}
|
||||
},
|
||||
{
|
||||
"name_from": "node_11",
|
||||
"name_to": "node_12",
|
||||
"attributes": {
|
||||
"dir": "both",
|
||||
"style": style_new(lambda: (conf["step"] >= 0)),
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
## consts
|
||||
dir_source = "source"
|
||||
|
||||
## args
|
||||
argument_parser = _argparse.ArgumentParser(
|
||||
)
|
||||
argument_parser.add_argument(
|
||||
"-f",
|
||||
"--format",
|
||||
type = str,
|
||||
choices = ["svg","png"],
|
||||
dest = "format",
|
||||
metavar = "<format>",
|
||||
default = "svg"
|
||||
)
|
||||
argument_parser.add_argument(
|
||||
"-n",
|
||||
"--no-extension",
|
||||
action = "store_true",
|
||||
dest = "no_extension",
|
||||
default = False,
|
||||
)
|
||||
argument_parser.add_argument(
|
||||
"-o",
|
||||
"--output-directory",
|
||||
type = str,
|
||||
dest = "output_directory",
|
||||
metavar = "<output-directory>",
|
||||
default = "temp"
|
||||
)
|
||||
args = argument_parser.parse_args()
|
||||
|
||||
## exec
|
||||
### excc:services
|
||||
if True:
|
||||
size = 10
|
||||
for step in range(size):
|
||||
render(
|
||||
dot_macro_services(
|
||||
{
|
||||
"step": step,
|
||||
}
|
||||
),
|
||||
{},
|
||||
args.format,
|
||||
string_coin(
|
||||
"{{directory}}/{{name}}-{{step}}{{extension}}",
|
||||
{
|
||||
"name": "services",
|
||||
"directory": args.output_directory,
|
||||
"step": ("%u" % step),
|
||||
"extension": (
|
||||
""
|
||||
if args.no_extension else
|
||||
("." + args.format)
|
||||
),
|
||||
}
|
||||
)
|
||||
)
|
||||
### exec:syncing
|
||||
if True:
|
||||
size = 14
|
||||
for step in range(size):
|
||||
render(
|
||||
dot_macro_user_management(
|
||||
{
|
||||
"step": step,
|
||||
}
|
||||
),
|
||||
{},
|
||||
args.format,
|
||||
string_coin(
|
||||
"{{directory}}/{{name}}-{{step}}{{extension}}",
|
||||
{
|
||||
"name": "user_management",
|
||||
"directory": args.output_directory,
|
||||
"step": ("%u" % step),
|
||||
"extension": (
|
||||
""
|
||||
if args.no_extension else
|
||||
("." + args.format)
|
||||
),
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
main()
|
||||
|
199
source/lib.py
Normal file
|
@ -0,0 +1,199 @@
|
|||
import os as _os
|
||||
|
||||
|
||||
def convey(x, fs):
|
||||
y = x
|
||||
for f in fs:
|
||||
y = f(y)
|
||||
return y
|
||||
|
||||
|
||||
def string_coin(template, arguments, options = None):
|
||||
options = (
|
||||
{
|
||||
"open": "{{",
|
||||
"close": "}}",
|
||||
}
|
||||
|
|
||||
(options or {})
|
||||
)
|
||||
result = template
|
||||
for (key, value, ) in arguments.items():
|
||||
if (value is None):
|
||||
pass
|
||||
else:
|
||||
result = result.replace(
|
||||
(
|
||||
"%s%s%s"
|
||||
% (
|
||||
options["open"],
|
||||
key,
|
||||
options["close"],
|
||||
)
|
||||
),
|
||||
value
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
def file_read(path):
|
||||
handle = open(path, "r")
|
||||
content = handle.read()
|
||||
handle.close()
|
||||
return content
|
||||
|
||||
|
||||
def file_write(path, content):
|
||||
_os.makedirs(_os.path.dirname(path), exist_ok = True)
|
||||
handle = open(path, "w" if _os.path.exists(path) else "a")
|
||||
handle.write(content)
|
||||
handle.close()
|
||||
return None
|
||||
|
||||
|
||||
def dot_entry(head, attributes, options = None):
|
||||
options = (
|
||||
{
|
||||
"indentation": 0,
|
||||
}
|
||||
|
|
||||
(options or {})
|
||||
)
|
||||
return string_coin(
|
||||
"{{indentation}}{{head}} [{{attributes}}];\n",
|
||||
{
|
||||
"indentation": ("\t" * options["indentation"]),
|
||||
"head": head,
|
||||
"attributes": convey(
|
||||
attributes,
|
||||
[
|
||||
lambda x: x.items(),
|
||||
lambda x: map(
|
||||
lambda pair: string_coin(
|
||||
"{{key}}=\"{{value}}\"",
|
||||
{
|
||||
"key": pair[0],
|
||||
"value": pair[1]
|
||||
}
|
||||
),
|
||||
x
|
||||
),
|
||||
", ".join,
|
||||
]
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def dot_node(node, options = None):
|
||||
options = (
|
||||
{
|
||||
"indentation": 0,
|
||||
}
|
||||
|
|
||||
(options or {})
|
||||
)
|
||||
return dot_entry(
|
||||
string_coin("{{name}}", {"name": node["name"]}),
|
||||
node["attributes"],
|
||||
options
|
||||
)
|
||||
|
||||
|
||||
def dot_edge(edge, options = None):
|
||||
options = (
|
||||
{
|
||||
"indentation": 0,
|
||||
}
|
||||
|
|
||||
(options or {})
|
||||
)
|
||||
return dot_entry(
|
||||
string_coin("{{name_from}} -> {{name_to}}", {"name_from": edge["name_from"], "name_to": edge["name_to"]}),
|
||||
edge["attributes"],
|
||||
options
|
||||
)
|
||||
|
||||
|
||||
def dot_subgraph(subgraph, options = None):
|
||||
options = (
|
||||
{
|
||||
"indentation": 0,
|
||||
}
|
||||
|
|
||||
(options or {})
|
||||
)
|
||||
return string_coin(
|
||||
(
|
||||
"{{indentation}}subgraph cluster_{{name}}\n"
|
||||
+
|
||||
"{{indentation}}{\n"
|
||||
+
|
||||
"{{attributes}}\n"
|
||||
+
|
||||
"{{nodes}}\n"
|
||||
+
|
||||
"{{edges}}\n"
|
||||
+
|
||||
"{{indentation}}}\n"
|
||||
),
|
||||
{
|
||||
"indentation": ("\t" * options["indentation"]),
|
||||
"name": subgraph["name"],
|
||||
"attributes": convey(
|
||||
subgraph["attributes"],
|
||||
[
|
||||
lambda x: x.items(),
|
||||
lambda x: map(
|
||||
lambda pair: string_coin(
|
||||
"{{indentation}}{{key}}=\"{{value}}\";\n",
|
||||
{
|
||||
"indentation": ("\t" * (options["indentation"] + 1)),
|
||||
"key": pair[0],
|
||||
"value": pair[1]
|
||||
}
|
||||
),
|
||||
x
|
||||
),
|
||||
"".join,
|
||||
]
|
||||
),
|
||||
"nodes": "".join(map(lambda node: dot_node(node, {"indentation": (options["indentation"] + 1)}), subgraph["nodes"])),
|
||||
"edges": "".join(map(lambda edge: dot_edge(edge, {"indentation": (options["indentation"] + 1)}), subgraph["edges"])),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def dot_graph(graph):
|
||||
return string_coin(
|
||||
(
|
||||
"digraph {{name}}\n"
|
||||
+
|
||||
"{\n"
|
||||
+
|
||||
"{{settings_graph}}\n"
|
||||
+
|
||||
"{{settings_node}}\n"
|
||||
+
|
||||
"{{settings_edge}}\n"
|
||||
+
|
||||
"{{subgraphs}}\n"
|
||||
+
|
||||
"{{nodes}}\n"
|
||||
+
|
||||
"{{edges}}\n"
|
||||
+
|
||||
"}\n"
|
||||
),
|
||||
{
|
||||
"name": graph["name"],
|
||||
"settings_graph": dot_entry("graph", graph["settings"]["graph"], {"indentation": 1}),
|
||||
"settings_node": dot_entry("node", graph["settings"]["node"], {"indentation": 1}),
|
||||
"settings_edge": dot_entry("edge", graph["settings"]["edge"], {"indentation": 1}),
|
||||
"nodes": "".join(map(lambda node: dot_node(node, {"indentation": 1}), graph["nodes"])),
|
||||
"edges": "".join(map(lambda edge: dot_edge(edge, {"indentation": 1}), graph["edges"])),
|
||||
"subgraphs": "".join(map(lambda subgraph: dot_subgraph(subgraph, {"indentation": 1}), graph["subgraphs"])),
|
||||
}
|
||||
)
|
||||
|
||||
|
BIN
source/media/icons/ansible.png
Normal file
After Width: | Height: | Size: 9.4 KiB |
BIN
source/media/icons/authelia.png
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
source/media/icons/debian.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
source/media/icons/dokuwiki.png
Normal file
After Width: | Height: | Size: 83 KiB |
BIN
source/media/icons/dovecot.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
source/media/icons/element.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
source/media/icons/forgejo.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
source/media/icons/gitlab.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
source/media/icons/grav.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
source/media/icons/hedgedoc.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
source/media/icons/inwx.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
source/media/icons/keepassxc.png
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
source/media/icons/letsencrypt.png
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
source/media/icons/mastodon.png
Normal file
After Width: | Height: | Size: 7.3 KiB |
BIN
source/media/icons/murmur.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
source/media/icons/nginx.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
source/media/icons/owncloud.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
source/media/icons/postfix.png
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
source/media/icons/postgresql.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
source/media/icons/synapse.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
source/media/icons/vikunja.png
Normal file
After Width: | Height: | Size: 17 KiB |
9
source/tex/app.tex.tpl
Normal file
|
@ -0,0 +1,9 @@
|
|||
\begin{item}
|
||||
\href{<<link>>}
|
||||
{
|
||||
\includegraphics[width=0.025\textwidth]{media/icons/<<id>>}
|
||||
\
|
||||
\textbf{<<name>>}
|
||||
} — <<desc>>
|
||||
\end{item}
|
||||
|
190
source/tex/master.tex.tpl
Normal file
|
@ -0,0 +1,190 @@
|
|||
\documentclass[aspectratio=169]{beamer}
|
||||
|
||||
\usepackage{graphicx}
|
||||
\usepackage{svg}
|
||||
% \usepackage[ngerman]{babel}
|
||||
|
||||
\date{<<meta-date>>}
|
||||
\author{<<meta-author>>}
|
||||
\title{<<meta-title>>}
|
||||
|
||||
% \setmainlanguage{german}
|
||||
|
||||
\usetheme{Luebeck}
|
||||
% \usetheme{m}
|
||||
\usecolortheme{spruce}
|
||||
|
||||
|
||||
\begin{document}
|
||||
|
||||
\maketitle
|
||||
|
||||
\begin{frame}
|
||||
\tableofcontents
|
||||
\end{frame}
|
||||
|
||||
\begin{section}{Dienste}
|
||||
|
||||
\begin{frame}
|
||||
\sectionpage
|
||||
\end{frame}
|
||||
|
||||
\begin{subsection}{Theorie}
|
||||
|
||||
<<service-theory-frames>>
|
||||
|
||||
\end{subsection}
|
||||
|
||||
\begin{subsection}{Praxis}
|
||||
|
||||
\begin{frame}
|
||||
\frametitle{Beispiel}
|
||||
|
||||
Siehe \href{<<service-practice-example-link>>}{\texttt{<<service-practice-example-label>>}}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}
|
||||
\frametitle{Grundlegende Dientse}
|
||||
|
||||
\begin{itemize}
|
||||
<<service-practice-basics-items>>
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}
|
||||
\frametitle{Konkrete Dienste}
|
||||
|
||||
\begin{itemize}
|
||||
<<service-practice-existing-items>>
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}
|
||||
\frametitle{Geplante Dienste}
|
||||
|
||||
\begin{itemize}
|
||||
<<service-practice-future-items>>
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}
|
||||
\frametitle{Eingesetzte Technik}
|
||||
|
||||
\begin{itemize}
|
||||
<<service-practice-technologies-items>>
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\end{subsection}
|
||||
|
||||
\begin{subsection}{Alternativen}
|
||||
|
||||
\begin{frame}
|
||||
\frametitle{„Nimm doch einfach …“}
|
||||
|
||||
\begin{columns}
|
||||
\pause
|
||||
\begin{column}{0.5\textwidth}
|
||||
\begin{itemize}
|
||||
<<services-alternatives-list-items>>
|
||||
\end{itemize}
|
||||
\end{column}
|
||||
\pause
|
||||
\begin{column}{0.5\textwidth}
|
||||
\begin{itemize}
|
||||
<<services-alternatives-problems-items>>
|
||||
\end{itemize}
|
||||
\end{column}
|
||||
\end{columns}
|
||||
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}<presentation:0>
|
||||
\frametitle{„Aber es gibt doch noch …“}
|
||||
|
||||
\pause
|
||||
Du kennst ein System, was alles Gewünschte halbwegs sauber, sicher und bezahlbar abbildet? \\
|
||||
\pause
|
||||
\vspace{10mm}
|
||||
Na geil! Dann schick mir gerne eine Nachricht: \texttt{christian.frass@dielinke-glauchau.de} \\
|
||||
\pause
|
||||
\vspace{10mm}
|
||||
… aber rechne besser damit, dass ich es rösten oder ganz in der Luft zerreißen werde :)
|
||||
\end{frame}
|
||||
|
||||
\end{subsection}
|
||||
|
||||
\end{section}
|
||||
|
||||
\begin{section}{Nutzerverwaltung}
|
||||
|
||||
\begin{frame}
|
||||
\sectionpage
|
||||
\end{frame}
|
||||
|
||||
\begin{subsection}{Aufbau}
|
||||
<<user_management-schema-frames>>
|
||||
\end{subsection}
|
||||
|
||||
\begin{subsection}{Ablauf}
|
||||
|
||||
<<user_management-process-entry-frames>>
|
||||
|
||||
\end{subsection}
|
||||
|
||||
\begin{frame}
|
||||
\frametitle{Vorführung}
|
||||
|
||||
Siehe \href{<<user_management-example-link>>}{\texttt{<<user_management-example-label>>}} <<user_management-example-remark>>
|
||||
\end{frame}
|
||||
|
||||
\end{section}
|
||||
|
||||
\begin{section}{Umsetzung}
|
||||
|
||||
\begin{frame}
|
||||
\frametitle{Zu tun}
|
||||
|
||||
\begin{columns}
|
||||
\pause
|
||||
\begin{column}{0.5\textwidth}
|
||||
\textbf{technisch}
|
||||
\begin{itemize}
|
||||
<<todos-technical-items>>
|
||||
\end{itemize}
|
||||
\end{column}
|
||||
\pause
|
||||
\begin{column}{0.5\textwidth}
|
||||
\textbf{menschlich}
|
||||
\begin{itemize}
|
||||
<<todos-social-items>>
|
||||
\end{itemize}
|
||||
\end{column}
|
||||
\end{columns}
|
||||
\end{frame}
|
||||
|
||||
<<resources-frame>>
|
||||
|
||||
\end{section}
|
||||
|
||||
\begin{section}{Schluss}
|
||||
\begin{frame}
|
||||
\frametitle{Lust bekommen?}
|
||||
|
||||
\begin{itemize}
|
||||
\item{E-Mail an \href{mailto:<<meta-contact-email_address>>}{\texttt{<<meta-contact-email_address>>}}}
|
||||
\pause
|
||||
\item{Teilnahme in \texttt{\$\{gemeinsamer-kommunikations-kanal\}}?}
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}
|
||||
\begin{center}
|
||||
's'war's :)
|
||||
\end{center}
|
||||
\end{frame}
|
||||
|
||||
\end{section}
|
||||
|
||||
\end{document}
|
||||
|
6
source/tex/resource-item.tex.tpl
Normal file
|
@ -0,0 +1,6 @@
|
|||
\begin{item}
|
||||
\href{<<link>>}
|
||||
{
|
||||
<<name>>
|
||||
}
|
||||
\end{item}
|
8
source/tex/resources-frame.tex.tpl
Normal file
|
@ -0,0 +1,8 @@
|
|||
\begin{frame}
|
||||
\frametitle{Ressourcen}
|
||||
|
||||
\begin{itemize}
|
||||
<<resource-items>>
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
16
source/tex/service-theory-frame.tex.tpl
Normal file
|
@ -0,0 +1,16 @@
|
|||
\begin{frame}
|
||||
\frametitle{Theorie}
|
||||
\begin{columns}
|
||||
% \begin{column}{0.618\textwidth}
|
||||
\begin{column}{0.5\textwidth}
|
||||
\begin{center}
|
||||
\includesvg[inkscapelatex=false,height=0.8\textheight]{graphs/<<image>>}
|
||||
\end{center}
|
||||
\end{column}
|
||||
% \begin{column}{0.382\textwidth}
|
||||
\begin{column}{0.5\textwidth}
|
||||
<<text>>
|
||||
\end{column}
|
||||
\end{columns}
|
||||
\end{frame}
|
||||
|
4
source/tex/todo.tex.tpl
Normal file
|
@ -0,0 +1,4 @@
|
|||
\begin{item}
|
||||
\href{<<link>>}{<<name>>}
|
||||
\end{item}
|
||||
|
8
source/tex/user_management-frame.tex.tpl
Normal file
|
@ -0,0 +1,8 @@
|
|||
\begin{frame}
|
||||
\frametitle{<<title>>}
|
||||
\begin{figure}
|
||||
\includesvg[inkscapelatex=false,width=1.0\textwidth]{graphs/<<image>>}
|
||||
\end{figure}
|
||||
<<text>>
|
||||
\end{frame}
|
||||
|
56
tools/build
Executable file
|
@ -0,0 +1,56 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import os as _os
|
||||
import argparse as _argparse
|
||||
|
||||
|
||||
def main():
|
||||
## args
|
||||
argument_parser = _argparse.ArgumentParser(
|
||||
)
|
||||
argument_parser.add_argument(
|
||||
"-c",
|
||||
"--clear",
|
||||
action = "store_true",
|
||||
dest = "clear",
|
||||
default = False
|
||||
)
|
||||
argument_parser.add_argument(
|
||||
"-r",
|
||||
"--include-resources",
|
||||
action = "store_true",
|
||||
dest = "include_resources",
|
||||
default = False,
|
||||
)
|
||||
argument_parser.add_argument(
|
||||
"-v",
|
||||
"--verbose",
|
||||
action = "store_true",
|
||||
dest = "verbose",
|
||||
default = False,
|
||||
)
|
||||
argument_parser.add_argument(
|
||||
"-o",
|
||||
"--output-directory",
|
||||
type = str,
|
||||
dest = "output_directory",
|
||||
metavar = "<output-directory>",
|
||||
default = "build"
|
||||
)
|
||||
args = argument_parser.parse_args()
|
||||
|
||||
## exec
|
||||
make_args = []
|
||||
make_args.append("dir_build=%s" % args.output_directory)
|
||||
if args.include_resources:
|
||||
make_args.append("coin_args='-r'")
|
||||
if not args.verbose:
|
||||
make_args.append("latex_args='-interaction batchmode'")
|
||||
if args.clear:
|
||||
make_args.append("clear")
|
||||
make_args.append("all")
|
||||
_os.system("make -f tools/makefile %s" % " ".join(make_args))
|
||||
|
||||
|
||||
main()
|
||||
|
206
tools/coin
Executable file
|
@ -0,0 +1,206 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import sys as _sys
|
||||
import json as _json
|
||||
import argparse as _argparse
|
||||
|
||||
from lib import *
|
||||
|
||||
|
||||
_template_cache = {}
|
||||
|
||||
|
||||
def coin(template, arguments):
|
||||
return string_coin(
|
||||
template,
|
||||
arguments,
|
||||
{"open": "<<", "close": ">>"}
|
||||
)
|
||||
|
||||
|
||||
def render(template_name, arguments):
|
||||
global _template_cache
|
||||
if (not (template_name in _template_cache)):
|
||||
template_content = file_read("source/tex/%s.tex.tpl" % template_name)
|
||||
_template_cache[template_name] = template_content
|
||||
else:
|
||||
template_content = _template_cache[template_name]
|
||||
return coin(
|
||||
template_content,
|
||||
arguments
|
||||
)
|
||||
|
||||
|
||||
def macro_applist(node):
|
||||
return convey(
|
||||
node["order"],
|
||||
[
|
||||
lambda x: map(
|
||||
lambda y: render(
|
||||
"app",
|
||||
{
|
||||
"id": y,
|
||||
"name": node["pool"][y]["name"],
|
||||
"link": node["pool"][y]["link"],
|
||||
"icon": node["pool"][y]["icon"],
|
||||
"desc": node["pool"][y]["desc"],
|
||||
}
|
||||
),
|
||||
x
|
||||
),
|
||||
"".join,
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def macro_todolist(node):
|
||||
return convey(
|
||||
node,
|
||||
[
|
||||
lambda x: map(
|
||||
lambda entry: render(
|
||||
"todo",
|
||||
{
|
||||
"name": entry["name"],
|
||||
"link": entry["link"],
|
||||
}
|
||||
),
|
||||
x
|
||||
),
|
||||
"".join,
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
## args
|
||||
argument_parser = _argparse.ArgumentParser()
|
||||
argument_parser.add_argument(
|
||||
"-d",
|
||||
"--data-path",
|
||||
type = str,
|
||||
dest = "data_path",
|
||||
metavar = "<data-path>",
|
||||
default = "source/data.json",
|
||||
)
|
||||
argument_parser.add_argument(
|
||||
"-r",
|
||||
"--include-resources",
|
||||
action = "store_true",
|
||||
dest = "include_resources",
|
||||
default = False,
|
||||
)
|
||||
args = argument_parser.parse_args()
|
||||
|
||||
## exec
|
||||
data = _json.loads(file_read(args.data_path))
|
||||
_sys.stdout.write(
|
||||
render(
|
||||
"master",
|
||||
{
|
||||
"meta-date": data["meta"]["date"],
|
||||
"meta-author": data["meta"]["author"],
|
||||
"meta-title": data["meta"]["title"],
|
||||
"meta-contact-email_address": data["meta"]["contact"]["email_address"],
|
||||
"service-theory-frames": convey(
|
||||
data["services"]["theory"],
|
||||
[
|
||||
lambda x: map(
|
||||
lambda y: render(
|
||||
"service-theory-frame",
|
||||
y
|
||||
),
|
||||
x
|
||||
),
|
||||
"".join,
|
||||
]
|
||||
),
|
||||
"service-practice-example-link": data["services"]["practice"]["example"]["link"],
|
||||
"service-practice-example-label": data["services"]["practice"]["example"]["label"],
|
||||
"service-practice-technologies-items": macro_applist(data["services"]["practice"]["technologies"]),
|
||||
"service-practice-basics-items": macro_applist(data["services"]["practice"]["basics"]),
|
||||
"service-practice-existing-items": macro_applist(data["services"]["practice"]["concrete_present"]),
|
||||
"service-practice-future-items": macro_applist(data["services"]["practice"]["concrete_planned"]),
|
||||
"services-alternatives-list-items": convey(
|
||||
data["services"]["alternatives"]["list"],
|
||||
[
|
||||
lambda x: map(
|
||||
lambda entry: coin("\\item{<<entry>>}\n", {"entry": entry}),
|
||||
x
|
||||
),
|
||||
"".join,
|
||||
]
|
||||
),
|
||||
"services-alternatives-problems-items": convey(
|
||||
data["services"]["alternatives"]["problems"],
|
||||
[
|
||||
lambda x: map(
|
||||
lambda entry: coin("\\item{<<entry>>}\n", {"entry": entry}),
|
||||
x
|
||||
),
|
||||
"".join,
|
||||
]
|
||||
),
|
||||
"user_management-schema-frames": convey(
|
||||
data["user_management"]["schema"],
|
||||
[
|
||||
lambda x: map(
|
||||
lambda y: render(
|
||||
"user_management-frame",
|
||||
({"title": "Aufbau"} | y)
|
||||
),
|
||||
x
|
||||
),
|
||||
"".join,
|
||||
]
|
||||
),
|
||||
"user_management-process-entry-frames": convey(
|
||||
data["user_management"]["processes"]["entry"],
|
||||
[
|
||||
lambda x: map(
|
||||
lambda y: render(
|
||||
"user_management-frame",
|
||||
({"title": "Ablauf"} | y)
|
||||
),
|
||||
x
|
||||
),
|
||||
"".join,
|
||||
]
|
||||
),
|
||||
"user_management-example-link": data["user_management"]["example"]["link"],
|
||||
"user_management-example-label": data["user_management"]["example"]["label"],
|
||||
"user_management-example-remark": data["user_management"]["example"]["remark"],
|
||||
"resources-frame": (
|
||||
render(
|
||||
"resources-frame",
|
||||
{
|
||||
"resource-items": convey(
|
||||
data["resources"],
|
||||
[
|
||||
lambda x: map(
|
||||
lambda resource: render(
|
||||
"resource-item",
|
||||
{
|
||||
"name": resource["name"],
|
||||
"link": resource["link"],
|
||||
}
|
||||
),
|
||||
x
|
||||
),
|
||||
"".join,
|
||||
]
|
||||
),
|
||||
}
|
||||
)
|
||||
if args.include_resources else
|
||||
""
|
||||
),
|
||||
"todos-technical-items": macro_todolist(data["realization"]["todos_technical"]),
|
||||
"todos-social-items": macro_todolist(data["realization"]["todos_social"]),
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
main()
|
||||
|
8
tools/fetch
Executable file
|
@ -0,0 +1,8 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import json as _json
|
||||
|
||||
data = _json.loads(open("source/data.json").read())
|
||||
for pair in data["service"]["practice"]["pool"].items():
|
||||
print("# %s\ncurl -L %s -o source/media/icons/%s\n" % (pair[0], pair[1]["icon"], pair[0]))
|
||||
|
199
tools/lib.py
Normal file
|
@ -0,0 +1,199 @@
|
|||
import os as _os
|
||||
|
||||
|
||||
def convey(x, fs):
|
||||
y = x
|
||||
for f in fs:
|
||||
y = f(y)
|
||||
return y
|
||||
|
||||
|
||||
def string_coin(template, arguments, options = None):
|
||||
options = (
|
||||
{
|
||||
"open": "{{",
|
||||
"close": "}}",
|
||||
}
|
||||
|
|
||||
(options or {})
|
||||
)
|
||||
result = template
|
||||
for (key, value, ) in arguments.items():
|
||||
if (value is None):
|
||||
pass
|
||||
else:
|
||||
result = result.replace(
|
||||
(
|
||||
"%s%s%s"
|
||||
% (
|
||||
options["open"],
|
||||
key,
|
||||
options["close"],
|
||||
)
|
||||
),
|
||||
value
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
def file_read(path):
|
||||
handle = open(path, "r")
|
||||
content = handle.read()
|
||||
handle.close()
|
||||
return content
|
||||
|
||||
|
||||
def file_write(path, content):
|
||||
_os.makedirs(_os.path.dirname(path), exist_ok = True)
|
||||
handle = open(path, "w" if _os.path.exists(path) else "a")
|
||||
handle.write(content)
|
||||
handle.close()
|
||||
return None
|
||||
|
||||
|
||||
def dot_entry(head, attributes, options = None):
|
||||
options = (
|
||||
{
|
||||
"indentation": 0,
|
||||
}
|
||||
|
|
||||
(options or {})
|
||||
)
|
||||
return string_coin(
|
||||
"{{indentation}}{{head}} [{{attributes}}];\n",
|
||||
{
|
||||
"indentation": ("\t" * options["indentation"]),
|
||||
"head": head,
|
||||
"attributes": convey(
|
||||
attributes,
|
||||
[
|
||||
lambda x: x.items(),
|
||||
lambda x: map(
|
||||
lambda pair: string_coin(
|
||||
"{{key}}=\"{{value}}\"",
|
||||
{
|
||||
"key": pair[0],
|
||||
"value": pair[1]
|
||||
}
|
||||
),
|
||||
x
|
||||
),
|
||||
", ".join,
|
||||
]
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def dot_node(node, options = None):
|
||||
options = (
|
||||
{
|
||||
"indentation": 0,
|
||||
}
|
||||
|
|
||||
(options or {})
|
||||
)
|
||||
return dot_entry(
|
||||
string_coin("{{name}}", {"name": node["name"]}),
|
||||
node["attributes"],
|
||||
options
|
||||
)
|
||||
|
||||
|
||||
def dot_edge(edge, options = None):
|
||||
options = (
|
||||
{
|
||||
"indentation": 0,
|
||||
}
|
||||
|
|
||||
(options or {})
|
||||
)
|
||||
return dot_entry(
|
||||
string_coin("{{name_from}} -> {{name_to}}", {"name_from": edge["name_from"], "name_to": edge["name_to"]}),
|
||||
edge["attributes"],
|
||||
options
|
||||
)
|
||||
|
||||
|
||||
def dot_subgraph(subgraph, options = None):
|
||||
options = (
|
||||
{
|
||||
"indentation": 0,
|
||||
}
|
||||
|
|
||||
(options or {})
|
||||
)
|
||||
return string_coin(
|
||||
(
|
||||
"{{indentation}}subgraph cluster_{{name}}\n"
|
||||
+
|
||||
"{{indentation}}{\n"
|
||||
+
|
||||
"{{attributes}}\n"
|
||||
+
|
||||
"{{nodes}}\n"
|
||||
+
|
||||
"{{edges}}\n"
|
||||
+
|
||||
"{{indentation}}}\n"
|
||||
),
|
||||
{
|
||||
"indentation": ("\t" * options["indentation"]),
|
||||
"name": subgraph["name"],
|
||||
"attributes": convey(
|
||||
subgraph["attributes"],
|
||||
[
|
||||
lambda x: x.items(),
|
||||
lambda x: map(
|
||||
lambda pair: string_coin(
|
||||
"{{indentation}}{{key}}=\"{{value}}\";\n",
|
||||
{
|
||||
"indentation": ("\t" * (options["indentation"] + 1)),
|
||||
"key": pair[0],
|
||||
"value": pair[1]
|
||||
}
|
||||
),
|
||||
x
|
||||
),
|
||||
"".join,
|
||||
]
|
||||
),
|
||||
"nodes": "".join(map(lambda node: dot_node(node, {"indentation": (options["indentation"] + 1)}), subgraph["nodes"])),
|
||||
"edges": "".join(map(lambda edge: dot_edge(edge, {"indentation": (options["indentation"] + 1)}), subgraph["edges"])),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def dot_graph(graph):
|
||||
return string_coin(
|
||||
(
|
||||
"digraph {{name}}\n"
|
||||
+
|
||||
"{\n"
|
||||
+
|
||||
"{{settings_graph}}\n"
|
||||
+
|
||||
"{{settings_node}}\n"
|
||||
+
|
||||
"{{settings_edge}}\n"
|
||||
+
|
||||
"{{subgraphs}}\n"
|
||||
+
|
||||
"{{nodes}}\n"
|
||||
+
|
||||
"{{edges}}\n"
|
||||
+
|
||||
"}\n"
|
||||
),
|
||||
{
|
||||
"name": graph["name"],
|
||||
"settings_graph": dot_entry("graph", graph["settings"]["graph"], {"indentation": 1}),
|
||||
"settings_node": dot_entry("node", graph["settings"]["node"], {"indentation": 1}),
|
||||
"settings_edge": dot_entry("edge", graph["settings"]["edge"], {"indentation": 1}),
|
||||
"nodes": "".join(map(lambda node: dot_node(node, {"indentation": 1}), graph["nodes"])),
|
||||
"edges": "".join(map(lambda edge: dot_edge(edge, {"indentation": 1}), graph["edges"])),
|
||||
"subgraphs": "".join(map(lambda subgraph: dot_subgraph(subgraph, {"indentation": 1}), graph["subgraphs"])),
|
||||
}
|
||||
)
|
||||
|
||||
|
61
tools/makefile
Normal file
|
@ -0,0 +1,61 @@
|
|||
## consts/vars
|
||||
|
||||
dir_source := source
|
||||
dir_temp := temp
|
||||
dir_build := build
|
||||
coin_args :=
|
||||
latex_args :=
|
||||
|
||||
|
||||
## commands
|
||||
|
||||
cmd_log := echo "--"
|
||||
cmd_rm := rm --recursive --force
|
||||
cmd_mkdir := mkdir --parents
|
||||
cmd_cp := cp --recursive --update --verbose
|
||||
cmd_latex := xelatex -shell-escape ${latex_args}
|
||||
|
||||
|
||||
## rules
|
||||
|
||||
.PHONY: _default
|
||||
_default: all
|
||||
|
||||
.PHONY: all
|
||||
all: icons graphs ${dir_build}/infra.pdf
|
||||
|
||||
.PHONY: clear
|
||||
clear:
|
||||
@ ${cmd_log} "clearing …"
|
||||
@ ${cmd_rm} ${dir_temp} ${dir_build}
|
||||
|
||||
.PHONY: graphs
|
||||
graphs: ${dir_source}/graphs
|
||||
@ ${cmd_log} "graphs …"
|
||||
@ ${cmd_mkdir} ${dir_temp}/graphs
|
||||
@ ${dir_source}/graphs --output-directory=${dir_temp}/graphs --format=svg # --no-extension
|
||||
|
||||
.PHONY: icons
|
||||
icons:
|
||||
@ ${cmd_log} "icons …"
|
||||
@ ${cmd_mkdir} ${dir_temp}/media/icons
|
||||
@ ${cmd_cp} ${dir_source}/media/icons/* ${dir_temp}/media/icons/
|
||||
|
||||
${dir_temp}/infra.tex: \
|
||||
$(wildcard ${dir_source}/tex/*) \
|
||||
${dir_source}/data.json \
|
||||
$(wildcard ${dir_temp}/graphs/*) \
|
||||
tools/coin
|
||||
@ ${cmd_log} "coining …"
|
||||
@ tools/coin --data-path=${dir_source}/data.json ${coin_args} > ${dir_temp}/infra.tex
|
||||
|
||||
${dir_temp}/infra.pdf: ${dir_temp}/infra.tex
|
||||
@ ${cmd_log} "compiling …"
|
||||
@ cd ${dir_temp} && ${cmd_latex} infra.tex && cd - > /dev/null
|
||||
@ cd ${dir_temp} && ${cmd_latex} infra.tex && cd - > /dev/null
|
||||
|
||||
${dir_build}/infra.pdf: ${dir_temp}/infra.pdf
|
||||
@ ${cmd_log} "placing …"
|
||||
@ ${cmd_mkdir} ${dir_build}
|
||||
@ ${cmd_cp} ${dir_temp}/infra.pdf ${dir_build}/infra.pdf
|
||||
|