Dies ist der Code für die Website vom aka-Filmclub Freiburg e.V., erreichbar unter https://www.aka-filmclub.de/.
Diese Readme enthält Erklärungen zum Technologie-Stack und zur Progammierung. Dabei wird besonders auf die Dinge eingegangen, die vom Standard abweichen.
Außerdem wird erklärt, was nötig ist, um die App lokal zu installieren.
Das Backend der Website ist mit Laravel gebaut, das Frontend mit React.
Es handelt sich um eine Single-Page-Applicaton (SPA), d.h. beim Aufruf der Website wird das gesamte Frontend als JavaScript-Anwendung an den Browser geschickt. Beim Navigieren oder anderen Interaktionen fragt das Frontend nur noch Daten vom Backend ab bzw. schickt Daten ans Backend.
Am einfachsten lässt sich die App lokal mit Laravel Sail einrichten.
Es ist empfehlenswert sich ein Alias für das Sail-Script anzulegen, wie hier beschrieben. Bei den unten angegebenen Befehlen wird davon ausgegangen, dass dieses Alias angelegt ist.
Mit Laravel Sail läuft die App in einem Docker-Container. Damit das funktioniert, muss Docker installiert sein. Das geht auf verschiedenen Wegen. Hier zwei Möglichkeiten:
- Docker Desktop installieren, das eine grafische Benutzerfläche enthält.
- Docker Engine installieren, die keine grafische Benutzeroberfläche enthält.
Wenn Docker installiert ist, kann die App eingerichtet werden. Dazu sind folgende Schritte in dieser Reihenfolge nötig. (Bei Veränderung der Reihenfolge einiger Schritte treten Fehler auf.)
- Auf oberster Ebene im Repository eine Datei .env anlegen und den Inhalt von .env.example in die Datei kopieren. Erklärungen finden sich hier und hier in der Laravel-Doku.
sail up
ausführen und die Container laufen lassen.sail artisan key:generate
ausführen, um einen APP_KEY in .env einzutragen.sail artisan migrate
ausführen, um die Datenbank-Tabellen zu erstellen.sail artisan db:seed
ausführen, um einige notwendige Werte in die Datenbank zu schreiben. Dadurch werden auch die User "armin", "edith", und "otto" erzeugt - jeweils mit gleichlautendem Passwort.sail artisan storage:link
ausführen, um die Interaktion mit dem Dateisystem einzurichten, siehe hier.
Jetzt sollte die App unter http://localhost erreichbar sein und funktionieren.
Falls die Verbindung zum Forum lokal getestet werden soll, muss dafür eine zusätzliche Datenbank eingerichtet werden. Die einfachste Möglichkeit, die Datenbank einzurichten, ist wohl, ein phpBB-Forum lokal zu installieren.
Zur Versionsverwaltung wird Git verwendet. Im Folgenden sind ein paar Besonderheiten beschrieben.
Normalerweise würde man einen Ordner mit Fremd-Bibliotheken wie den vendor-Ordner nicht in die Versionsverwaltung einchecken. Das ist hier aber nötig, weil die App direkt über Git auf den Webserver des Web-Hosts geladen wird und es dort keine Möglichkeit gibt, die Bibliotheken wiederherzustellen (weil z.B. Composer nicht auf dem Webserver installiert ist).
Die Datei public/js/app.js, die das kompilierte Frontend enthält, würde man eigentlich auch nicht mit einchecken. Dass es dennoch so ist, hat einen ähnlichen Grund wie beim vendor-Ordner: Es gibt keine Möglichkeit die Datei auf dem Webserver zu kompilieren.
Der Hauptbranch heißt main. In diesem liegt der produktive Code, d.h. es dürfen keine Zwischenstände auf main commited werden. Außerdem muss in main immer das mit npm run prod
gebaute Frontend liegen.
Für größere Entwicklungen sollte ein feature-Branch abgezweigt und über einen Pull Request bei GitHub gemerget werden.
Das Frontend wird mithilfe von Laravel Mix kompiliert. Die Konfiguration von Mix liegt in der Datei webpack.mix.js.
Node.js und npm sind im Sail-Container installiert und die angegebenen Befehle beziehen sich darauf. (Alternativ kann man sich auch Node.js lokal installieren, am besten mit nvm.)
Vor dem erstmaligen Verwenden der App muss einmal der Befehl sail npm install
ausgeführt werden.
Die anderen für diese App relevanten npm-Befehle (die sich auch in der package.json finden) sind:
sail npm run dev
: Kompiliert das Frontend.sail npm run watch
: Überwacht Änderungen im Code und kompiliert das Frontend automatisch bei jeder Änderung.sail npm run prod
: Kompiliert das Frontend und minifiziert das Output-File.
Wichtig: Vor einem Commit in den main-Branch muss immer sail npm run prod
ausgeführt werden.
Die Web-Routes sind in der Datei routes/web.php definiert. Es gibt nur zwei:
- Die obere ist ein Spezialfall: Unter /files lassen sich Dateien zum Download hinterlegen, siehe dazu hier.
- Auf allen anderen Routes, die nicht mit api beginnen, wird der index-View zurückgegeben, über den dann die React-App geladen wird.
Die Api-Routes sind in der Datei routes/api.php definiert und nach Ressourcen gruppiert.
Zum Routing siehe: https://laravel.com/docs/8.x/routing.
Zur Authentifizierung wird Laravel Sanctum verwendet. Siehe insbesondere den Abschnitt zu SPA Authentication in der Doku.
Die Authentifizierung ist manuell implementiert, ausgehend von dieser Beschreibung. Sie findet sich in app/Http/Controllers/UserController.php. Sie ist so eingerichtet, dass der Login nach x fehlgeschlagenen Anmeldeversuchen für y Minuten für den jeweiligen User blockiert wird. x und y können im env-File eingestellt werden.
Für die Speicherung der Session wurde die Datenbank gewählt, siehe dazu: https://laravel.com/docs/8.x/session#introduction
Authorisierung und Validierung sind mit Form Requests implementiert.
Auf der Website können Bilder hochgeladen werden, die wie hier beschrieben gespeichert werden.
Fürs Sharen auf Facebook, Telegram, WhatsApp und Twitter gibt es eine eigene Middleware, die unter app/Http/Middleware/SendJustMetaWhenSharing.php zu finden ist.
Die Middleware checkt den User-Agent des Requests. Wenn dieser zu einer der genannten Websites/Apps gehört, werden nur passende Meta-Daten zurückgegeben. Ansonsten nimmt der Request seinen normalen Lauf.
Zur Erklärung: Normalerweise würde man die Meta-Daten in den Head der jeweiligen HTML-Seite schreiben, wie hier in der Doku des Open Graph Protokolls beschrieben. Das ist bei einer SPA jedoch nicht ohne Weiteres möglich, da die HTML-Seiten dynamisch erzeugt werden. Daher werden die Requests wie beschrieben abgefangen.
Über die User-Administration auf der Website können auch die User eines angeschlossenen phpBB-Forums administriert werden.
Im env-File gibt es den Config-Schalter IS_FORUM_CONNECTED. Dieser steuert, ob vom UserController der ForumUserService aufgerufen wird.
Falls diese Funktionalität genutzt werden soll, muss im env-File die Datenbankverbindung zum Forum hinterlegt werden.
Konstanten, die in der ganzen App zur Verfügung stehen sollen, sind in config/constants.php hinterlegt.
Der gesamte Quellcode fürs Frontend findet sich in /resources/js. Der Code der React-App liegt dort im Ordner react-app.
Das Frontend ist wie oben beschrieben eine mit React gebaute SPA.
Die Dateien app.js und bootstrap.js im Ordner resources/js sind Dateien aus dem Standard-Setup von Laravel. In app.js wird der JavaScript-Code gesammelt, der von Laravel Mix kompiliert wird. In bootstrap.js steht globale Konfiguration - momentan nur für Axios.
Das Gerüst der React-App lehnt sich an das Gerüst an, das standardmäßig von Create React App für eine neue App erzeugt wird. Der Eintrittspunkt ist in index.js, wo die App-Komponente ins DOM gerendert wird. Die App-Komponente befindet sich der Datei App.js und enthält alle weiteren Komponenten.
-
pages enthält die React-Komponenten, die Seiten entsprechen.
-
common enthält alle React-Komponenten, die nicht Seiten entsprechen.
-
services enthält Funktionen zum Aufruf des Backends.
-
utils enthält zusätzliche JavaScript-Funktionalität.
-
styles enthält Dateien, die CSS-Styles betreffen.
-
assets enthält statische Dateien, die in der App verwendet werden.
Die React-App ist mit React Function Components und Hooks geschrieben. (Achtung vor Verwirrung: Viele Beispiele in der React-Dokumentation beziehen sich noch auf React Class Components.)
Um Werte in der ganzen App verfügbar zu machen, werden Context und der useContext-Hook verwendet.
-
Zum Frontend-Routing verwendet die App React Router. Das Routing findet in der App-Komponente statt.
-
Fürs CSS-Styling verwendet die App Styled Components und hier insbesondere auch GlobalStyles.
-
Zur Erzeugung von PDFs verwendet die App React PDF.
-
Für die WYSIWYG-Editoren wird React Draft Wysiwyg verwendet.
Mit einer Ausnahme gehen alle Calls aus der App an die eigene Laravel-Api.
Für alle Calls an die Laravel-API wird Axios verwendet. Die zugehörigen Services finden sich im Ordner utils/services.
In baseService.js ist ein globales Error-Handling implementiert, das bei Server-Fehlern oder unbekannten Fehlern auf eine Fehler-Seite umleitet.
Beim Eintragen von neuen Filmen kann man Informationen von der OMDB-API abrufen. Dieser Call ist mit Fetch implementiert, weil die Konfiguration von Axios hier Probleme bereiten würde. Siehe pages/intern/AddScreeningPage.js.
Das Scrolling ist momentan so implementiert, dass bei jedem Seitenwechsel ganz nach oben gescrollt wird, siehe common/ScrollToTop.js. Falls es einen eleganten Weg gibt, den Scroll bei jedem Seitenwechsel wiederherzustellen, könnte das Scrolling dementsprechend verbessert werden.
In der Datei constants.js werden alle Konstanten gesammelt, die in der ganzen App gebraucht werden.
Die Favicons (einschließlich diverser Icons für spezielle Betriebssysteme und Geräte) wurden mit RealFaviconGenerator erstellt und liegen im public-Ordner. Dort liegt auch eine (vom RealFaviconsGenerator erstellte) README_favicons.md.
Manche Kommentare im Code sind auf deutsch, manche auf englisch. Das ist aus Unachtsamkeit entstanden und hat keine Bedeutung, wäre aber zu viel Aufwand zu vereinheitlichen.
Eigentlich wird in der App überall camelCase oder PascalCase verwendet, aber an einigen Stellen taucht auch snake_case auf. Das liegt daran, dass die Benamung von einigen Datenbank-Spalten durcheinander gegangen ist. Der unterschiedliche Case hat keine Bedeutung; es wäre aber zu viel Aufwand ihn zu vereinheitlichen.
Beim Testen der API-Routes mit Postman gibt es einige Besonderheiten zu beachten - genauer gesagt bei den Routes, die mit Laravel Sanctum geschützt sind. Ein Tutorial zur entsprechenden Einrichtung von Postman findet sich hier. Zusätzlicher Hinweis: Das dort beschriebene Pre-request Script muss vor allen POST Requests ausgeführt werden (GET Requests gehen auch ohne).