Archiv der Kategorie: Schule

MRBS und report.php

Wer gerade auf der Suche ist nach einer Möglichkeit, normalen Benutzer:innen in MRBS zu erlauben, selbst Berichte zu erstellen – also die report.php aufzurufen: Das geht in der mrbs_auth.inc

133  
134     // These pages allow users to create and delete entries 
135     case 'check_slot.php':              // Ajax page used by edit_entry.php 
136     case 'del_entry.php': 
137     case 'edit_entry.php': 
138     case 'edit_entry_handler.php': 
139     case 'report.php':                 // diese Zeile ergänzen!
140       return (is_open_to_users()) ? 1 : 2; 
141       break; 
142  
143     // These pages only contain admin features 
144     case 'add.php':                     // Adds a room 
145     case 'del.php':                     // Deletes a room 
146     case 'del_entries.php':             // Ajax page for bulk deletion of entries 
147     case 'edit_area.php': 
148     case 'edit_area_handler.php': 
149     case 'edit_room_handler.php': 
150     case 'import.php': 
151     //case 'report.php':               // diese Zeile auskommentieren
152       $result = 2; 
153       break; 
154 

Und das war es auch schon.

Whiteboard

Lange war ich auf der Suche nach einem möglichst kooperativ verwendbaren Whiteboard und denke nun: ich würde fündig.

https://github.com/cracker0dks/whiteboard

Ist besonders schön im Firefox bedienbar, bietet auch „Ihr dürft nur gucken“-Links zum Teilen, lässt sich in Nextcloud integrieren und macht im Docker keinen Ärger.

Für die Schule ausgerollt und in die Nextcloud integriert – für die Community macht das Frank noch am Wochenende.

Bleibt der Traum von einer Tafel mit der Mächtigkeit von Mebis.

Horde GnuPG auf Ubuntu 18.04

Horde ist hier auf einem Ubuntu 18.04 Server installiert – mit Hilfe von PEAR.  Leider funktionierte eine ganze Zeit lang die PGP / GnuPG Schlüsselerstellung damit nicht mehr. Ich vermute inzwischen, weil der Commit hier

https://github.com/horde/Crypt/pull/2/commits/5f0c7e7b7a3dc7b6a8a3e9ba1e085be7a94d3477

nie Eingang in das Horde fand, das hier mittels PEAR aktuell gehalten wird.

Was nämlich funktioniert, ist, der Austausch von

/usr/share/php/Horde/Crypt/Pgp/Backend/Binary.php

mit der Binary.php von oben! Also

wget https://raw.githubusercontent.com/horde/Crypt/5f0c7e7b7a3dc7b6a8a3e9ba1e085be7a94d3477/lib/Horde/Crypt/Pgp/Backend/Binary.php
mv /usr/share/php/Horde/Crypt/Pgp/Backend/Binary.php /usr/share/php/Horde/Crypt/Pgp/Backend/Binary.php.bak
mv Binary.php /usr/share/php/Horde/Crypt/Pgp/Backend/Binary.php

und die Schlüsselerstellung funktioniert wieder.

Danke auch an kruedewagen und die weiterführenden Links dort, der mich auf die richtigen Gleise setzte, auch wenn dessen Lösung hier nicht funktionierte.

Debian Installbox

Um viele Laptops möglichst zügig mit einem Betriebssystem versorgen zu können, habe ich eine „Debian Installbox“ erzeugt. Diese basiert auf

https://salsa.debian.org/installer-team/netboot-assistant

und der Dank geht somit an andi für das Konzept, die Skripte und seine Unterstützung.

Meine eigenen Konfigurationsdateien habe ich ins Git gelegt:

https://codeberg.org/dowel/installbox

Eine fertige VM für Virtualbox kann mensch hier herunterladen:

https://cloud.kvfg.de/index.php/s/aXtJQxKccPCm8kX

Ein paar Erläuterungen dazu:

Host

Den Hostrechner mit zwei Netzwerkkarten versorgen. Die „nach Außen“ / Richtung Internet zeigende Netzwerkkarte sollte die langsamere der beiden sein. Nach „innen“ und damit in Richtung der zu installierenden Maschinen das schnellste nehmen, was rumliegt.

Die VM unter Debian Buster braucht nicht viel – die voreingestellten 4GB und 2 CPUs sollten reichen. Vermutlich reicht auch die Hälfte – die VM hat ja fast nix zu tun, außer Steuerbefehle zu schicken und Dateien auszuteilen. Der Host sollte das doppelte der VM an Ressourcen aufweisen. Hier klappt das auf Rechnern der „Isny-Klasse“ (Core i3 mit 8 GB RAM und SSD) ganz flott – so als Orientierung.

Adapter 1 zeigt in Richtung Internet und ist im Auslieferungszustand vermutlich noch als Bridge konfiguriert, weil das in meinem lokalen Netz praktischer war. Das Interface darf ruhig NATen. Im Bild oben ist das nicht so, weil ich dann vom VM-Host via SSH einfacher auf die VM komme.

Adapter 2 zeigt in Richtung der zu installierenden Maschinen und muss deswegen eine Netzwerkbrücke direkt auf das Interface im Host sein. Hier in der VM die Einstellungen in /etc/network/interfaces nur befummeln, wenn man die Folgen abschätzen kann – also dazu bereit ist, die Konfiguration zu überarbeiten. Voreingestellt ist hier die IP 192.168.0.10. Da fährt dann auch der TFTP-Server hoch und lauscht der dnsmasq auf Anfragen.

Am Host selbst hatte ich für diese zweite Karte keine IP gesetzt, was unter Arch gut funktionierte. Unter Debian funktionierte das überhaupt nicht. Da musste ich auf dem Host dem Interface eine 192.168.0.1 statisch verpassen, erst dann konnte die VM dort bridgen.

Dann noch eine Anmerkung zum Grafik-Controller: VBox will da inzwischen VMSVGA haben. Das führt in der Debian-VM hier (unter Arch) jedoch dazu, dass diese alle paar Sekunden eine Denkpause in der GUI einlegt. Mit VBoxVGA flutscht es in der VM weitaus besser. Muss man ausprobieren – tun sollte beides.

VM

Usermanagement

Es sind zwei Benutzer eingerichtet – installbox als Arbeitskonto (Passwort: muster) und kvfg (Passwort: kvfg) für die Erzeugung eines hübschen Homeverzeichnisses für die SuS, das dann auf die Laptops mit ausgerollt wird und somit schon alle sinnigen Einstellungen mitbringt. Da müsst ihr Euch halt einen eigenen backen – das Schulkürzel bietet sich als Benutzername wie auch als Passwort an.

Also: Als kvfg anmelden und alle Einstellungen so vornehmen, wie sie später die SuS an den Laptops vorfinden sollen. Z.B. kann hier das hässliche XFCE-Debian-Theme überarbeitet werden. Ich habe dann noch in Firefox ublock und decentraleyes installiert, die Suchmaschinenliste überarbeitet, Bookmarks eingefügt, die Startseite angepasst und auch Libreoffice für den Einsatz in den Fächern Deutsch, Englisch, Französisch und Spanisch inklusive Beispieldateien vorbereitet. Weiter habe ich Nextcloud „halb installiert“, damit den SuS das auch auffällt, wie sie von zu Hause aus geschickt arbeiten könnten. Dazu kommt – seit der letzten Version – auch ein Skript, das die Verbindung mit dem Schulnetzwerk herstellt (WLAN, Servermounts), sofern die SuS mal in der Schule arbeiten. So Sachen eben, die den Alltag für die SuS erleichtern.

Sobald das alles nach Wunsch aussieht ausloggen und als installbox wieder anmelden. Von diesem Konto aus als root das Homeverzeichnis von kvfg komplett in ein TAR packen. Das Skript build-skel.sh im Rootverzeichnis hilft dabei.

Die Laptops holen sich im Zuge der Installation das TAR-Archiv und entpacken das auf dem Laptop nach /home/kvfg, womit die Einstellungen auf den Geräten wie gewünscht gesetzt sind.

Wer sich einen eigenen Benutzer für die Schule gebacken hat, sollte also die Pfade und Namen in der preseed.cfg daraufhin überprüfen.

Hints

Die VM ist mit einem Apt-Cacher NG versorgt, der die gesamte Installation Stand 13.08.2020 10:00 Uhr auch offline abwickeln kann. Ihr könnt in der VM unter http://localhost:3142 nachsehen, wie viel an Download aus dem Netz ihr schon gespart habt – und außerdem geht es so einfach total flott.

In Zeile 81 hinter

d-i pkgsel/include string

der preseed.cfg sind die Pakete aufgeführt, die nachinstalliert werden. Da lassen sich leicht weitere ergänzen. Ich hab hier z.B. Gimp, VLC, Okular und Gwenview sowie Kate mit eingetragen, weil ich diese selbst gerne nutze – und weil sie auf den Clients in der Schule auch da sind. Dazu kamen dann noch Cheese für einen Test der Webcam und Nextcloud-Desktop für die Verbindung mit der Schulcloud usw usw usw …

Releases

2020-08-13

Initial release

2020-08-14

Paketliste ergänzt (Druckmöglichkeit), Splash-Screen, Softwarecenter

2020-08-17

Paketliste ergänzt (simple-scan), ublock im Firefox-ESR für die BBB Domains auf lehrerfortbildung-bw.de und die schulischen Domains deaktiviert

2020-08-18

KISS: Die Druckerpakete machen vermutlich keinen Sinn. Wenn die SuS keine Geräte haben und deswegen einen Laptop von der Schule erhalten, dann haben diese aller Wahrscheinlichkeit nach auch keinen Drucker rumstehen – und wenn doch, dann lernen sie was bei der Nachinstallation. Synaptics-Touchpad-Treiber kamen noch dazu – und die Repos wurden freundlicher eingestellt (contrib, non-free hinzugefügt).

2020-08-20

Das XFCE-Batteriestatus Icon hat noch gefehlt. Weiter habe ich, um den Überblick zu behalten, etckeeper und git auf den Laptops installiert [1]. So kann bei Tests vor Ort besser abgeschätzt werden, welche Anpassungen noch fehlen (z.B. Netzwerkverbindungen).

Die Verbindung mit dem Schulnetz wird nun via WPA2-Enterprise hergestellt. Deswegen wird in der Downloadversion der VM eine weitere Datei mit ausgerollt:

/var/lib/tftpboot/d-i/buster/schueler.nmconnection

In dieser sind die Credentials für die Verbindung mit dem Schulnetz „schueler“ mit drin (in der Downloadversion der VM nicht wirklich – aber den Teil muss mensch eh selbst an die Gegebenheiten in der Schule vor Ort anpassen).

Damit diese Configdatei an Ort und Stelle auf den Laptops ankommt, wurde dann die preseed.cfg überarbeitet, was wiederum im Git auf Codeberg (Link siehe oben) zu finden ist.

Damit evtl. Änderungen schnell eingepflegt werden können, die schueler.nmconnection in der VM nach /root legen. Dort liegt auch das Skriptchen build-skel.sh, das dann das Homeverzeichnis zusammen mit dieser Datei packt.

2020-08-24

Die VM hat nun Skripte an Bord, die auf den Laptops die Einrichtung individueller Verbindungen mit dem Schulnetzwerk (WPA2-Enterprise) unterstützen – inklusive mount der Servershares. Der Würgaround vom 20.08 mit einem Xtra-User ist somit nicht mehr nötig.

2020-08-25

Gut, wenn man noch einmal drüber schläft. Ich hatte die cifs-utils in der preseed.cfg vergessen.

Systempflege

2021-06-25

Fährt mensch die Installbox nach einigen Wochen / Monaten erneut hoch, dann passt der Kernel nicht mehr und die Fehlermeldung

Es wurden keine Kernel-Module gefunden. Dies liegt vermutlich an einem Unterschied zwischen dem hier verwendeten Kernel des Installers und dem Kernel, der im Debian-Archiv verfügbar ist […]

taucht auf. Hier scheint das folgende Vorgehen geholfen zu haben:

  1. Alle Pakete aus dem Apt-Cacher NG löschen
  2. lokales Update der Installbox durchführen
  3. di-netboot-assistant frisch machen:
di-netboot-assistant purge stable
di-netboot-assistant install stable
di-netboot-assistant fw-toggle stable
di-netboot-assistant rebuild-grub
di-netboot-assistant rebuild-menu

Irgendwo auf dem Weg zum Glück bog ich dabei falsch ab und erhielt bei der Partitionierung die Meldung, dass kein Root-Dateisystem angegeben worden sei. Ein Reboot der Installbox scheint das aber erledigt zu haben. Jetzt läuft die Installation wieder durch. Ursächlich ist wohl eher der Client selbst, dessen Festplatte nicht erkannt wurde. Hier half bei weiteren Versuchen ein Strg-Alt-F1 und dann die Auswahl von „Festplatten erkennen“. Klappt das, dann läuft die Installation auf Basis der preseed.cfg danach weiter.

Da ich jetzt am Spielen bin habe ich noch meine auf Debian 10 laufende Clonezilla VM ins oben angegebene Repo gelegt. Kurzbeschreibung:

Adapter 1 mit 080027358D91 zeigt in Richtung Internet (NAT)
Adapter 2 mit 080027129480 zeigt in Richtung Clients (Bridged)
# Benutzerkonten
root: muster
konto: muster

Adapter 1 wird vom NetworkManager verwaltet. Adapter 2 wird von ifupdown mit 192.168.0.10 versorgt. Auf dem Desktop befindet sich eine TXT Datei mit den wichtigsten Einstellungen und Befehlen. Clonezilla läuft hier so, dass Images erstellt und wieder ausgerollt werden können. Schon enthalten ist das Image aus der Installbox in /home/partimg/ … und das bau ich nun weiter aus und um.

2021-06-26 I

firmware-iwlwifi wird nun bei der Installation via Installbox auf den T450ern explizit benötigt. Das habe ich ergänzt  – auch in der preseed.cfg auf Codeberg. Das Installbox Image ist aktualisiert und frisch hochgeladen.

Die Clonezilla-Server Variante enthält nun zwei Images: Einmal das, was die Installbox auswirft (XFCE als Desktop) und zusätzlich noch ein Image mit KDE mit den folgenden, zusätzlich installierten und schon vorkonfigurierten Paketen:

kde-full breeze-gtk-theme thunderbird thunderbird-l10n-de keepassxc inkscape youtube-dl flatpak gnome-software-plugin-flatpak

2021-06-26 II

Die Installbox bietet nun beim Boot des Clients zwei Installationsoptionen an: Bullseye und Buster jeweils mit XFCE als Desktop.

Die Dokumentation dazu auf Codeberg ist aktualisiert.

In der nächsten Pflegestufe kommt der Clonezillaserver dran – mit XFCE und KDE Desktop für Bullseye.

Nextcloud … mal wieder

Ich warte ja immer gerne, bis die frischen NC Versionen einen gewissen Reifegrad erreichen, bevor ich diese einspiele. Beim Sprung von 17.x auf 18.x dachte ich, 18.0.3 müsste passen, erlebe hier aber eine kleine Hürde nach der anderen.

Ist Talk aktiviert, dann fliegt das Update via occ erst einmal komplett auf die Schnauze und meldet in schönem Rot:

Checking for update of app spreed in appstore
Checked for update of app "spreed" in appstore 
Repair error: Repair step 'OCA\Talk\Migration\FixNamespaceInDatabaseTables' is unknown
PHP Fatal error:  Cannot declare class OCA\Talk\Migration\Version8000Date20200331144101, because the name is already in use in /path/to/somedomain-tld/nextcloud/apps/spreed/lib/Migration/Version8000Date20200331144101.php on line 54

Das lässt sich beheben.

sudo -u www-data php occ app:disable "spreed"
Nextcloud or one of the apps require upgrade - only a limited number of commands are available
You may use your browser or the occ upgrade command to do the upgrade
No such app enabled: spreed

Die letzte Meldung – No such app enabled: spreed – ist irreführend. Ja – eine App „Spreed“ ist nicht eingeschaltet, aber Talk. Und app:disable „Talk“ führt zu nix. Außerdem wirft ja NC beim Update selbst mit Checked for update of app „spreed“ in appstore den Fehler. Anyway. Es hilft. Der Dank geht an freedox.

Alternative: Talk vor dem Upgrade abschalten und dann wieder anschalten, wenn das Update durchgelaufen ist. Erzeugt weniger Puls.

Danach dann

sudo -u www-data php occ upgrade

erneut ausführen, Wartungsmodus wieder abschalten und einloggen, um auf die nächsten Fehler unter nextcloud/index.php/settings/admin/overview blicken zu können. Diese lassen sich weitgehend beheben mit

sudo -u www-data php occ db:add-missing-indices

was allerdings immer noch ranzt ist die dumme Meldung zu

- core
	- INVALID_HASH
		- core/js/mimetypelist.js
	- EXTRA_FILE
		- core/img/filetypes/mindmap.svg

die bezüglich mimetypelist.js schlicht nicht stimmt und sich – je nach Installation – aus dem exakt gleichen Paket auch nicht reproduzieren lässt. Einmal wirft NC diesen Fehler, das andere mal nicht. Toll. Ich ignoriere das nun ebenso wie den Fehler zu mindmap.svg und hoffe auf die nächste Runde.

Nextcloud cannot modify header information

Das Problem mit zwei meiner Nextcloud-Installationen entstand nach dem Update von 16.0.5 auf 16.0.6: Nach dem Login im Browser wurden keine Dateien oder Ordner mehr angezeigt. Die Apache-Logs waren leer. Der Sync-Client funktionierte.

In den Nextcloud-Logs war das hier zu finden:

Cannot modify header information - headers already sent by (output started at /var/www/domain.tld/nextcloud/3rdparty/sabre/http/lib/Sapi.php:80) at /var/www/domain.tld/nextcloud/3rdparty/sabre/http/lib/Sapi.php#63

Diese Datei schien mir aber in Ordnung zu sein: ASCII als Codierung, keine whitespaces vor den ersten oder nach den letzten Einträgen.

Nach langem Hin und Her kam ich zu einer wenig eleganten Lösung: Zuerst wurde das Nextcloud Installationspaket erneut heruntergeladen und erneut an Ort und Stelle geschoben – inklusive sudo -u www-data php occ upgrade

Jetzt meckerte Nextcloud, dass die Datei mimetypelist.js den falschen Hash hätte – und weiterhin wurden weder Dateien noch Ordner angezeigt.

Also ersetzte ich die mimetypelist.js durch die Version aus dem git:

wget https://raw.githubusercontent.com/nextcloud/server/master/core/js/mimetypelist.js

und alles war wieder gut: kein Gemecker über falsche Hashes und alle Ordner und Dateien wurden brav angezeigt.

Bei beiden Nextcloud-Instanzen auf unterschiedlichen Servern die gleiche Lösung. Ich meine, dass ich serverspezifische Probleme somit ganz gut ausschließen kann. Whatever.

Nextcloud Talk mit Coturn auf CX11

Einen eigenen Coturn für Videochats über die eigene Nextcloud zu betreiben ist nicht schwer. Gute Anleitungen für den Einstieg sind im Netz zu haben. Lauscht der Coturn auf Port 443, ist man gleich noch die Routerprobleme bei den Nutzern los.

In der Annahme, dass man da nicht genug Ressourcen hinwerfen kann, stellte ich Coturn bei meinen ersten Gehversuchen eine VM unter KVM mit 4 CPUs und 8GB RAM zur Verfügung. Heute weiß ich, dass das overkill ist, wenn das System nur gelegentlich und dann meist nur von wenigen Menschen parallel benutzt wird.

Die Grafik oben ist ein Screenshot aus OMD und zeigt die CPU Auslastung während eines Videotelefonats zwischen zwei Personen auf einem CX11 bei Hetzner (2,96€ / Monat). Top zeigte eine CPU Auslastung von rund 7% – OMD ein wenig mehr. Aber festhalten lässt sich, dass für eine NC-Talk-Familieninstanz der CX11 ausreichend ist – und vermutlich sogar für eine Schule, weil es sehr selten dazu kommen dürfte, dass mehrere L gleichzeitig ihren S Nachhilfe via Talk geben.

Jetzt hängen vier Nextcloud Instanzen am CX11 – zwei private und zwei Kollegien. Mal sehen, was passiert.

Q2A mit LDAP gegen LD Server

Question 2 Answer ist eine nette PHP-MySQL-Alternative to askbot und bringt hier auch ein LDAP Auth-Plugin mit. Will man dieses nutzen, um gegen einen LD-Server zu authentifizieren, dann kann man die folgenden Einstellungen wählen, damit „es tut“:

q2a LDAP Einstellungen Teil 1

Selbstverständlich wäre hier für den Produktivbetrieb in unsicherer Umgebung LDAPs und Port 636 zu wählen.

q2a LDAP Einstellungen Teil 2

Ich bin zuerst nicht auf die Idee gekommen, hier AD auszuwählen und versucht zuerst mit OpenLDAP zum Ziel zu gelangen. Das wollte nicht klappen, so dass ich in einem Anfall von „mal gucken“ plötzlich wie oben gezeigt Erfolg hatte.

nextCloud 15 mit LDAPs an LD-Server und Automount von Tausch und Home

Weil es so ein unschönes Gefummel war, dokumentiere ich hier für mich (und auch andere Benutzer von LD / SBE) die Anbindung der nextCloud per LDAPs an den LD-Server, die dafür sorgt, dass beim Login der Benutzer gleich noch deren Tausch- und Homeverzeichnisse in die nextCloud gelupft werden. Dass dann bei uns noch Collabora CODE dazukommt rundet die Sache schön ab.

Siehe zu diesem Thema auch den Vorgängerartikel.

Kurz zum allgemeinen Setup: Eine VM mit Ubuntu 18.04 LTS werkelt intern auf einem Virtualisierungshost, der mit seinen Netzwerkkarten in den jeweils für ihn wichtigen VLANs hängt. Auf diesem bridgen die VMs direkt in die VLANs rein. In Richtung Internet steht vor diesem VM-Host eine PFSense als Firewall in den jeweils relevanten Netzen.

Die VM für nextCloud etc. hat zwei virtuelle Netzwerkkarten: Eine zeigt via grauem VLAN in Richtung PFSense (damit in Richtung Internet) und trägt die öffentliche IP des Servers. Die andere Netzwerkkarte hängt als Bridge im grünen VLAN und wird vom LD-Server direkt versorgt. Über diese zweite („grüne“) Netzwerkkarte hole ich mir per LDAPs die Benutzerdatenbank und führe den SMB/CIFS-Mount der Homeverzeichnisse aus.

Netzwerkdiagramm

LDAPs Anbindung

Das Paket php-ldap muss an Bord und konfiguriert sein.

Hinweis: Den Zertifikatscheck kann man im nC LDAP Modul ausschalten für die ersten Tests – oder direkt auf der VM in /etc/ldap/ldap.conf durch den Eintrag TLS_REQCERT allow. Nicht schön, aber zum Testen eine Fehlerquelle weniger.

Die Server-IP mit vorangestelltem ldaps:// und im Feld Port 636 eintragen. Die zwei folgenden Felder können für LD-Server leer gelassen werden.

Da das automatische Auslesen der Base DN bei mir nicht funktioniert hat, musste ich diese von Hand angeben. In meinem Fall: ou=users,dc=kvfg-schule,dc=de

Beim LD-Server liegen die User in ldUserAccount.

Die Loginattribute wählt das von mir hier verwendete nC 15 dann von selbst richtig aus.

DIe passende Objektklasse ist posixGroup.

Das würde nun reichen, um die Benutzer in nC rein zu lassen und auch, um das Tauschverzeichnis automatisch einzubinden, aber nicht, um die Homeverzeichnisse der User automatisch zu mounten. Das liegt daran, dass nC aus dem LDAP die UUID nimmt, um die nC-Benutzernamen zu erstellen. Wir brauchen aber für den Automount der Homes unserer Benutzer deren uid (das ist dann gleichzeitig der Benutzername des Users). Es gilt demnach, nC zu überreden, die UUID zu ignorieren und stattdessen die uid der LDAP-Benutzer zu verwenden.

Auf der Registerkarte Expert finden wir diese Möglichkeit. Bei Internal Username Attribute muss uid eingetragen werden.

Hinweis: Im Reiter Advanced gibt es die Möglichkeit, die von nC lokal erstellten Benutzerverzeichnisse (im Datenverzeichnis von nC) mit %uid benamen zu lassen, statt mit der UUID. Das geschieht durch die Einstellungen oben nun automatisch so. Man darf die Angabe auf keinen Fall doppelt machen (also im Reiter Advanced und im Reiter Expert). Die Fehlermeldungen, die man nach einem Doppeleintrag erhält, beziehen sich auf Homeverzeichnispfade, die nicht aus dem LDAP gelesen werden können. Nicht wirklich hilfreich.

Das Debugging ist wenig witzig. Was hilft, ist hier schon ausführlich beschrieben worden, weswegen ich mir diese Ausführungen heute sparen will. Was hier und heute dazu kommt: Es lohnt der regelmäßige Blick in die Datenbank von nC (z.B. über phpmyadmin). Da dürfen bei den Benutzern keine UUIDs auftauchen (das sind kryptische Kombinationen aus Zahlen und Buchstaben), sondern ausschließlich deren uids (also deren Benutzernamen). Hat das nicht geklappt, darf man von Vorne beginnen. Es empfiehlt sich deswegen, zuerst eine Basiskonfiguration anzulegen und diese zu sichern, die dann wieder eingespielt werden kann, wenn man sich in eine blöde Ecke konfiguriert hat. Das ebenfalls sehr nervige LDAP-Caching von nC lässt sich mit einem beherzten Restart des Apachen beeinflussen.

SMB/CIFS Mount

Die Pakete libsmbclient php-smbclient php-smb und auch die cifs-utils müssen installiert und konfiguriert sein. Letzteres nicht nur zum Testen, ob der SMB-Mount überhaupt funktioniert, sondern auch, weil die anderen Pakete ohne die cifs-utils nicht rund laufen werden.

Nachdem den Benutzern von nC die Verwendung von SMB/CIFS erlaubt wurde, die Einträge wie im Bild aus dem Adminaccount heraus vornehmen. Dabei den Folder Name und die IP des SMB-Servers den eigenen Gegebenheiten anpassen.

Nicht irritieren lassen, dass die „Böbbel“ beim Admin rot bleiben. Da der nC-Admin nicht aus dem LDAP kommt, sondern ein rein lokaler nC-Benutzer ist, muss der SMB-Mount hier auf die Nase fallen.

Die Einträge Login-creditials, saved in session sorgen bei den LDAP-Benutzern aber später dafür, dass die automatischen Mounts klappen. Das $user sorgt für die Ersetzung des Namens für das Home-Share durch den Benutzernamen (die uid), der beim Login in der nC angegeben wurde. Deswegen ja auch das Gefrickel mit dem LDAP oben!

Die Benutzer müssen nun nur noch aufpassen, dass sie sich nicht mit dem Desktop-Client automatisch das gesamte Verzeichnis Tausch/Schule syncen 🙂

Wie man sich per Docker noch ein Collabora CODE auf die VM mit der nC holt, ist an vielen anderen Stellen im Netz schon ausführlich beschrieben worden. Für den Alttag würde ich dann 6GB RAM und 4 CPUs für die VM empfehlen: CODE wie auch nC ziehen zusammen ziemlich an den Ressourcen.

Eines noch: Moodle 3.6 bringt die Möglichkeit zur Anbindung an eine nextCloud mit.

Summa summarum: Wer braucht da noch Ella? DIY and federation are the key!

WebUntis Scraper

Der Stundeplanrechner wirft die WebUntis HTML Dateien in ein WebDAVs Share. Dieses ist auf dem Moodle Server per Symlink in das Arbeitsverzeichnis des folgenden untisparser Skriptes eingebunden. Von dort wird das Ergebnis in ein File Repository des Lehrermoodles geschrieben und aus dem Kursraum „Schwarzes Brett“ (die Kommunikationsplattform der Schule) verlinkt. Das stellt sicher, dass nur Menschen, die a) am Moodle angemeldet und b) Mitglied des entsprechenden Kursraumes sind den Inhalt (hier: Vertretungsplan) einsehen können.

Mit geschlossenem Accordion

Accordion offen

Das muss leider so umständlich sein, weil ich keinen Weg gefunden habe, den WebDavs Ordner als solchen navigierbar im Kursraum so einzubinden, dass man diesen nicht auch von außerhalb des Moodles aufrufen könnte. Mir bleibt (sofern ich richtig liege) nix anderes über, als aus den X html Dateien, die WebUntis mir hinwirft, eine einzige zu bauen, die ich klar benamen und dann „verlinken“ kann. Dazu muss ich die vielen WebUntis HTML Dateien in ihre Bestandteile zerlegen. Ich brauche: Die Tabellen und die Zeitangaben.

Im Prinzip geht das mit beautifulsoup und Python. Meine Python-Kenntnisse sind jedoch leider noch rudimentärer als meine Bash-Kenntnisse … also muss  ein bash Skript her. Und HTML mit Bash nativ parsen  – nun: ich weiß, dass das Probleme macht. Das will man nicht.

Die Lösung ist pup, das ich in ein Bash-Skript einbinde.

Zur Information die Struktur der WebUntis Dateien in ihren Ordnern / Unterordnern:

Die zu erzeugende Output-Datei soll HTML sein und braucht dazu einen Kopf:

<html>
<head>
<title>Vertretungsplan</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta http-equiv="cache-control" content="max-age=0" />
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="expires" content="0">
<meta http-equiv="pragma" content="no-cache" />

<meta http-equiv="refresh" content="120" />
<style type="text/css">
body { margin-top: 20px; margin-left: 20px; margin-right: 20px;
background: #fff; color: #272727; font: 80% Arial, Helvetica, sans-serif; }
h1 { color: #ee7f00; font-size: 200%; font-weight: bold;}
h2 { color: #ee7f00; font-size: 175%;}
h1, h2 { margin: 0; padding: 25px 0px 5px 0px;}

 /* put your css here or copy from untishtml */
 
 /* Style the buttons that are used to open and close the accordion panel */
.accordion {
    background-color: #eee;
    color: #444;
    cursor: pointer;
    padding: 18px;
    width: 100%;
    text-align: left;
    border: none;
    outline: none;
    transition: 0.4s;
}

/* Add a background color to the button if it is clicked on (add the .active class with JS), and when you move the mouse over it (hover) */
.active, .accordion:hover {
    background-color: #ccc;
}

/* Style the accordion panel. Note: hidden by default */
.panel {
    padding: 0 18px;
    background-color: white;
    display: none;
    overflow: hidden;
} 


</style>
</head>
<body>

<script>
  window.onload=function(){
    var acc = document.getElementsByClassName("accordion");
    for (var i = 0; i < acc.length; i++) {
      acc[i].addEventListener("click", function() {
          this.classList.toggle("active");
          var panel = this.nextElementSibling;
          if (panel.style.display === "block") {
              panel.style.display = "none";
          } else {
              panel.style.display = "block";
          }
      });
    }
  };
</script>

<h1>KvFG Vertretungsplan nach Datum und Anzeigetafel</h1>
<p><strong>Es gilt der Plan auf den Anzeigetafeln im Haus bzw. auf den Aush&auml;ngen. Diese Datei ist immer nur Beta!</strong></p>

Siehe zum Code für das Accordion im Kopf und im „Kleister“: https://www.w3schools.com/howto/howto_js_accordion.asp  Leider hat das aber nicht gereicht. Zuerst muss gewartet werden, bis die gesamte Seite geladen ist, dann erst darf die for-Schleife beginnen. Also wird das Skript in den Footer gelegt oder gekapselt in:

window.onload=function(){
... }
/* thanx Janis for debugging */

Was einen Kopf hat, braucht auch einen Fuß:

<p></p>
<p>----</p>
<p>(C) dowel 2018 | UntisParser Version 0.1</p>
<p>Fehler sind immer m&oumlglich und sollten <a href="https://yourschoolsbugtracker.tld" target="_blank">im Bugtracker gemeldet werden</a>, damit diese behoben werden k&ouml;nnen. Wer keinen Bugreport (= Bericht) formulieren kann, muss schweigen.</p>
</body>
</html>

Und dann braucht es den „Kleister“, der die Arbeit macht und alles zusammenpackt. Nennen wir es untisparser.sh und legen es in das passende Verzeichnis auf dem Server:

#!/bin/bash
# UntisParser
# 
# Parse HTML Export Files created by WebUntis
# do "e pluribus unum" with a Bash script
# throw the output into a Moodle file repository
# and link the output from inside a Moodle Courseroom
# 
# You need the pup executable from https://github.com/ericchiang/pup
# 
# (C) dowel
# License: CC BY SA https://creativecommons.org/licenses/by-sa/4.0/deed.de
# Date: 2018-08-23
# Version 0.2
# ####

# def of some base vars
RUNT=$(date '+%Y-%m-%d %H:%M:%S')
RUNF="20 Minuten" # set this in cronjob
RELOAD="120 Sekunden" # see head_filename
WORKDIR="/path/untisparser"
PUPPATH="/path/bin"
HEAD_FILENAME="kopf.html" # asumed to be in workdir
FOOT_FILENAME="fuss.html" # asumed to be in workdir
OUTPUT_PATH="/path/moodledata/repository/anzeigebretter" # set this to your Moodle file repository
OUTPUT_FILENAME="output.html"

# headline def
LUL1H="Anzeige Lehrer/innen Teil 1 Linke Seite (Heute?)"
LUL2H="Anzeige Lehrer/innen Teil 2 Rechte Seite (Morgen?)"
SUS1H="Anzeige Sch&uuml;ler/innen Teil 1 Linke Seite (Heute?)"
SUS2H="Anzeige Sch&uuml;ler/innen Teil 2 Rechte Seite (Morgen?)"


# path stuff
# Where are the Untis files in the workdir?
L_SUBDIR="$WORKDIR/Lehrerbrett"
S_SUBDIR="$WORKDIR/Schuelerbrett"

# How many of the suckers are there?
COUNT_LF1=$(/usr/bin/find $L_SUBDIR/f1 -maxdepth 1 -name '*.htm' | /usr/bin/wc -l)
COUNT_LF2=$(/usr/bin/find $L_SUBDIR/f2 -maxdepth 1 -name '*.htm' | /usr/bin/wc -l)
COUNT_SF1=$(/usr/bin/find $S_SUBDIR/f1 -maxdepth 1 -name '*.htm' | /usr/bin/wc -l)
COUNT_SF2=$(/usr/bin/find $S_SUBDIR/f2 -maxdepth 1 -name '*.htm' | /usr/bin/wc -l)

# Warning jabber because we do not know how many old files there are
# and if cleaner.script has worked the way it should have
# we asume that it failed
WARNMESS="<p>
    --------------------------------------------------------------------------------------<br>
    Stand: $RUNT | Beachte: Das Skript l&auml;uft nur alle $RUNF und die Seite wird nach $RELOAD neu geladen!<br>
    Achte auf das Datum. Es kann sein, dass ab hier alte Dateien ausgelesen werden. Wenn das so ist, dann den Rest ignorieren.</br>
    <a href=\"#top\">Ganz nach oben</a> || LuL: <a href=\"#lul1\">Links</a> | <a href=\"#lul2\">Rechts</a> || SuS <a href=\"#sus1\">Links</a> | <a href=\"#sus2\">Rechts</a>
    </p>"

# create empty output file and fill it with html head and some simple navigation stuff
/bin/cat $WORKDIR/$HEAD_FILENAME > $OUTPUT_PATH/$OUTPUT_FILENAME
/bin/echo "<id=\"top\">" >> $OUTPUT_PATH/$OUTPUT_FILENAME
/bin/echo "<p><em>Links</em> ist meist <em>Heute</em> und <em>Rechts</em> ist meist <em>Morgen</em> - aber nicht immer.</p>" >> $OUTPUT_PATH/$OUTPUT_FILENAME
/bin/echo "<p>Anzeige Lehrer/innen: <a href=\"#lul1\">Links</a> | <a href=\"#lul2\">Rechts</a></p>" >> $OUTPUT_PATH/$OUTPUT_FILENAME
/bin/echo "<p>Anzeige Sch&uuml;ler/innen: <a href=\"#sus1\">Links</a> | <a href=\"#sus2\">Rechts</a></p>" >> $OUTPUT_PATH/$OUTPUT_FILENAME
/bin/echo "<p>Stand: $RUNT | Beachte: Das Skript l&auml;uft nur alle $RUNF!</p>" >> $OUTPUT_PATH/$OUTPUT_FILENAME
/bin/echo "<p></p>">> $OUTPUT_PATH/$OUTPUT_FILENAME

# ticker export
if [ -f $L_SUBDIR/ticker.htm ]
then
    /bin/echo "<h4>L Ticker</h4>" >> $OUTPUT_PATH/$OUTPUT_FILENAME
    $PUPPATH/pup --charset iso-8859-1 -f $L_SUBDIR/ticker.htm 'marquee text{}' >> $OUTPUT_PATH/$OUTPUT_FILENAME
fi

if [ -f $S_SUBDIR/ticker.htm ]
then
    /bin/echo "<h4>S Ticker</h4>" >> $OUTPUT_PATH/$OUTPUT_FILENAME
    $PUPPATH/pup --charset iso-8859-1 -f $S_SUBDIR/ticker.htm 'marquee text{}' >> $OUTPUT_PATH/$OUTPUT_FILENAME
fi

# Create teacher part of output file

/bin/echo "<h2 id=\"lul1\">$LUL1H</h2>" >> $OUTPUT_PATH/$OUTPUT_FILENAME
COUNT=1
MAXCOUNT=1
let MAXCOUNT=COUNT_LF1+1

# teacher links
while [ $COUNT -lt $MAXCOUNT ] ; do
    # padding
    NUM=$(printf %03d $COUNT)
    # Date extract to button
    /bin/echo "<button class=\"accordion\">" >> $OUTPUT_PATH/$OUTPUT_FILENAME
    $PUPPATH/pup --charset iso-8859-1 -f $L_SUBDIR/f1/subst_$NUM.htm 'div.mon_title' >> $OUTPUT_PATH/$OUTPUT_FILENAME
    /bin/echo "</button>" >> $OUTPUT_PATH/$OUTPUT_FILENAME
    /bin/echo "<div class=\"panel\">" >> $OUTPUT_PATH/$OUTPUT_FILENAME
    # Headline is set to H4
    /bin/echo "<h4>Lehrer/innen</h4>" >> $OUTPUT_PATH/$OUTPUT_FILENAME
    /bin/echo "<p></p>" >> $OUTPUT_PATH/$OUTPUT_FILENAME
    # Table extraction
    $PUPPATH/pup --charset iso-8859-1 -f $L_SUBDIR/f1/subst_$NUM.htm 'table' >> $OUTPUT_PATH/$OUTPUT_FILENAME
    /bin/echo "</div>" >> $OUTPUT_PATH/$OUTPUT_FILENAME
    # Warning 
    /bin/echo $WARNMESS >> $OUTPUT_PATH/$OUTPUT_FILENAME
    let COUNT=COUNT+1
done

# Reset for second part of LuL 

/bin/echo "<h2 id=\"lul2\">$LUL2H</h2>" >> $OUTPUT_PATH/$OUTPUT_FILENAME
COUNT=1
MAXCOUNT=1
let MAXCOUNT=COUNT_LF2+1

# teacher rechts
while [ $COUNT -lt $MAXCOUNT ] ; do
    # padding
    NUM=$(printf %03d $COUNT)
    # Date extract to button
    /bin/echo "<button class=\"accordion\">" >> $OUTPUT_PATH/$OUTPUT_FILENAME
    $PUPPATH/pup --charset iso-8859-1 -f $L_SUBDIR/f2/subst_$NUM.htm 'div.mon_title' >> $OUTPUT_PATH/$OUTPUT_FILENAME
    /bin/echo "</button>" >> $OUTPUT_PATH/$OUTPUT_FILENAME
    /bin/echo "<div class=\"panel\">" >> $OUTPUT_PATH/$OUTPUT_FILENAME
    # Headline is set to H4
    /bin/echo "<h4>Lehrer/innen</h4>" >> $OUTPUT_PATH/$OUTPUT_FILENAME
    /bin/echo "<p></p>" >> $OUTPUT_PATH/$OUTPUT_FILENAME
    # Table extraction
    $PUPPATH/pup --charset iso-8859-1 -f $L_SUBDIR/f2/subst_$NUM.htm 'table' >> $OUTPUT_PATH/$OUTPUT_FILENAME
    /bin/echo "</div>" >> $OUTPUT_PATH/$OUTPUT_FILENAME
    # Warning
    /bin/echo $WARNMESS >> $OUTPUT_PATH/$OUTPUT_FILENAME
    let COUNT=COUNT+1
done

# Create pupil part of output file
/bin/echo "<h2 id=\"sus1\">$SUS1H</H2>" >> $OUTPUT_PATH/$OUTPUT_FILENAME
COUNT=1
MAXCOUNT=1
let MAXCOUNT=COUNT_SF1+1


# pupil links
while [ $COUNT -lt $MAXCOUNT ] ; do
    # padding
    NUM=$(printf %03d $COUNT)
    # Date extract to button
    /bin/echo "<button class=\"accordion\">" >> $OUTPUT_PATH/$OUTPUT_FILENAME
    $PUPPATH/pup --charset iso-8859-1 -f $S_SUBDIR/f1/subst_$NUM.htm 'div.mon_title' >> $OUTPUT_PATH/$OUTPUT_FILENAME
    /bin/echo "</button>" >> $OUTPUT_PATH/$OUTPUT_FILENAME
    /bin/echo "<div class=\"panel\">" >> $OUTPUT_PATH/$OUTPUT_FILENAME
    # Headline is set to H4
    /bin/echo "<h4>Sch&uuml;ler/innen</h4>" >> $OUTPUT_PATH/$OUTPUT_FILENAME
    /bin/echo "<p></p>" >> $OUTPUT_PATH/$OUTPUT_FILENAME
    # Table extraction
    $PUPPATH/pup --charset iso-8859-1 -f $S_SUBDIR/f1/subst_$NUM.htm 'table' >> $OUTPUT_PATH/$OUTPUT_FILENAME
    /bin/echo "</div>" >> $OUTPUT_PATH/$OUTPUT_FILENAME
    # Warning
    /bin/echo $WARNMESS >> $OUTPUT_PATH/$OUTPUT_FILENAME
    let COUNT=COUNT+1
done

# Reset for second part of SuS 

/bin/echo "<h2 id=\"sus2\">$SUS2H</h2>" >> $OUTPUT_PATH/$OUTPUT_FILENAME
COUNT=1
MAXCOUNT=1
let MAXCOUNT=COUNT_SF2+1

# pupil rechts
while [ $COUNT -lt $MAXCOUNT ] ; do
    # padding
    NUM=$(printf %03d $COUNT)
    # Date extract to button
    /bin/echo "<button class=\"accordion\">" >> $OUTPUT_PATH/$OUTPUT_FILENAME
    $PUPPATH/pup --charset iso-8859-1 -f $S_SUBDIR/f2/subst_$NUM.htm 'div.mon_title' >> $OUTPUT_PATH/$OUTPUT_FILENAME
    /bin/echo "</button>" >> $OUTPUT_PATH/$OUTPUT_FILENAME
    /bin/echo "<div class=\"panel\">" >> $OUTPUT_PATH/$OUTPUT_FILENAME
    # Headline is set to H3
    /bin/echo "<h4>Sch&uuml;ler/innen</h4>" >> $OUTPUT_PATH/$OUTPUT_FILENAME
    /bin/echo "<p></p>" >> $OUTPUT_PATH/$OUTPUT_FILENAME
    # Table extraction
    $PUPPATH/pup --charset iso-8859-1 -f $S_SUBDIR/f2/subst_$NUM.htm 'table' >> $OUTPUT_PATH/$OUTPUT_FILENAME
    /bin/echo "</div>" >> $OUTPUT_PATH/$OUTPUT_FILENAME
    # Warning
    /bin/echo $WARNMESS >> $OUTPUT_PATH/$OUTPUT_FILENAME
    let COUNT=COUNT+1
done

# create footer
/bin/echo "<p></p>" >> $OUTPUT_PATH/$OUTPUT_FILENAME
/bin/cat $WORKDIR/$FOOT_FILENAME >> $OUTPUT_PATH/$OUTPUT_FILENAME

# cleanup
/bin/chown www-data.www-data $OUTPUT_PATH/$OUTPUT_FILENAME
/bin/chmod 2750 $OUTPUT_PATH/$OUTPUT_FILENAME
# and we are done
exit 0

Cron ruft das Skript alle 20 Minuten auf. Schöner wäre natürlich, wenn das Skript nur liefe, wenn sich was ändert im WebDavs Share. Aber inotify und Freunde sind auch nicht ohne. So ist es simpel und scheint zu funktionieren, ohne viel Ressourcen zu fressen.

Update 23.08

Einige Fehler im Skript (meist die vergessenenen \ vor den „) behoben und mit Hilfe von JavaScript mehr Übersichtlichkeit im Output erzeugt.