Skip to content
This repository has been archived by the owner on Sep 7, 2020. It is now read-only.

Verknüpfung von Projekten und Modulen

xLacrima edited this page Sep 30, 2019 · 6 revisions

Version 3

Redesign der Modulauswahl zur Verbesserung der Usability

Da das anzeigen einer langen Liste mit allen Modulen unübersichtlich war, sollte dies noch einmal angepasst werden. Als Ablösung soll eine kleine UI-Komponente dienen, über die zunächst ein Studiengang und anschließend die gewünschten Module ausgewählt werden können. Die Umsetzung der Karte erfolgte in Form einer mit Angular Forms kompatiblen Komponente, welche als Input Element zukünftig auch in anderen Eingabemasken verwendet werden könnte. Die Komponente verhält sich wie andere Input Elemente und verfügt über eine eigene Validation (Kann als Part einer größeren Form valid/unvalid sein) sowie der Möglichkeit die Werte über die Angular Forms API auszulesen und zu setzen. Der Wert einer Karte ist hierbei stets vom Typ StudyCourseModuleSelectionModel, dieses enthält als Attribute den ausgewählten StudyCourse und ein Array der selektierten Module.

Neue Modulauswahl v3

In der neuen Maske zum anlegen bzw. bearbeiten von Projekten existieren 1-n der neuen Karten. Neue Karten können über einen "+" Button hinzugefügt und bestehende durch ein Mülleimer Symbol Button gelöscht werden.

Version 2

Implementieren der Modulauswahl mit eindeutigem Studiengang

Bisher wurde zur Modulauswahl eine Liste von Modulen angeboten. Aufgrund des Datenbestandes existieren teilweise allerdings mehrere Module, welche gleich benannt sind, jedoch unterschiedlichen Studiengängen zugeordnet sind. Da dazugehörige Studiengänge bisher nicht mit angezeigt wurden, konnte der Nutzer gleichnamige Module nicht voneinander unterscheiden. Eine erste Lösung sollte es sein, die dazugehörigen Studiengänge mithilfe einer Klammerschreibweise hinter jedes Modul zu schreiben. Bsp.: Bachelorarbeit {Informatik, Medieninformatik}

Um die zu den Modulen verknüpften Studiengänge allerdings anzeigen zu können, mussten diese in einem ersten Schritt in dem Model der Module referenziert werden. Diese n-m Beziehung wird von Angular als zirkuläre Abhängigkeit in Form einer Warnung bemängelt. Da sich diese zirküläre Abhängigkeit allerdings aus den Beziehungen des Datenmodells ergeben, kann dies nicht ohne weiteres verhindert werden.

Neue Modulauswahl wegen neuer Beziehung zwischen Modulen und Studiengängen

Aufgrund der Qualität des Datenbestandes wurde die Beziehung von Modulen zu Studiengängen angepasst. Ein Modul ist nun nur noch einem einzigen Studiengang zugeordnet. Daraus ergibt sich eine 1-m Beziehung. Falls ein Modul, beispielsweise eine Bachelorarbeit, mit mehreren Studiengängen assoziiert wurde, so wird das Modul nun dupliziert und jedem verknüpften Studiengang einzeln zugeordnet. Infolgedessen wurde damit auch das Anzeigeverfahren von Modulen im Projekt-Erstelldialog angepasst. Nun werden Module nach Studiengängen aufgelistet:

Neue Modulauswahl v2

Version 1

Beim Anlegen eines Projekts muss mindestens 1 Modul ausgewählt werden

Module können nun einem Projekt hinzugefügt werden. Dargestellt werden diese mithilfe einer mat-cat-list. Einfaches Klicken wählt ein Modul aus, erneutes Klicken entwählt das Modul. Intern wird eine Liste mit allen ausgewählten Modulen gepflegt. Falls diese Liste leer ist, wird auf der Benutzeroberfläche ein Element eingeblendet, welches dem Benutzer mitteilt, dass noch kein Modul ausgewählt wurde. Außerdem wird verhindert, dass ein Projekt angelegt wird, obwohl noch keine Module ausgewählt wurden.

Verknüpfung von einem Projekt zu Modulen

Bei der Beziehung zwischen Projekten und Modulen handelt es sich um eine n-m Beziehung. Das Verknüpfen von Projekten und Modulen gestaltete sich jedoch nicht ganz einfach. Dies ist dadurch begründet, dass ein einfaches Modul-Array im projekt nicht möglich ist, weil die Module dann nicht so serialisiert werden, dass die von spring generierten REST-Schnittstellen den Request-Body interpretieren können. Ein Projekt mitsamt den Modulen würde wie folgt serialisiert werden:

{
    "modules": [
        {
            "name": "Bachelor Kolloquium",
            "_links": {
                "self": {
                    "href": "http://localhost:9002/projectModules/c5f1ed63-da20-4cb8-8f4e-1d3fdd34b1cb"
                },
                "module": {
                    "href": "http://localhost:9002/projectModules/c5f1ed63-da20-4cb8-8f4e-1d3fdd34b1cb"
                }
            }
        }
    ],
    "creatorID": "3884c236-d503-4c29-b311-f56da393b914",
    "creatorName": "Professor X",
    "name": "Testfdsdfsdf",
    "description": "dfsfsf",
    "status": "LAUFEND"
}

Dieser Request-Body führt im Backend zu einem Fehler, weil der spring REST Controller unter der Relation modules eine URI-Liste erwartet, welche alle self Links der einzelnen Module enthält und nicht die Module mitsamt ihrem Payload selbst. Um dem entgegenzuwirken, wurden einige Alternativen ausprobiert und schlussendlich die beste Alternative implementiert.

Alternativen zur Modulverknüpfung

Methode addRelation

Alternativ können die Module über die Methode addRelation des genutzten Frameworks Angular4-hal hinzugefügt werden, wobei die Anfragen nun direkt an die Association vom Projekt zu den Modulen gerichtet werden (Quelle). Allerdings fügt die Methode addRelation immer nur eine Resource hinzu. Bei 5 Modulen werden 5 separate Anfragen getätigt. Außerdem müssen zuvor bestehende Module gelöscht werden, bevor neue hinzugefügt werden können. Dies könnte bei beispielsweise 25 verlinkten Modulen zu insgesamt rund 50 Anfragen auf dieselbe Association führen. Aufgrunddessen scheint diese Möglichkeit keine gute Alternative zu sein.

URI-Liste von Modulen im Projekt-Model

Die self links der Module könnten (per Hack) genau so in das Projekt-Model eingetragen werden, sodass die Request vom spring Backend verstanden werden kann. Dies könnte mit folgender Methode geschehen:

setModules(newModules: Module[]) { 
 this["modules"] = new Array();
 for (let module of newModules) {
   this["modules"].push(module._links.self.href);
 }
}

Das serialisierte Projekt würde dann wie folgt aufgebaut sein:

{
    "description": "ycycxy",
    "status": "LAUFEND",
    "created": "2019-03-20T16:08:57.939+0000",
    "modified": "2019-03-20T16:09:09.314+0000",
    "creatorID": "53e76c0e-9546-cbdb-6a69-3625f6912263",
    "creatorName": "Professor X",
    "modules": [
            "http://localhost:9002/projectModules/1c1293e9-4b9b-40c2-b73d-5904db21f244",
            "http://localhost:9002/projectModules/eb572e1d-257f-4b10-bb73-5869d476b2cf"
    ]
}

Interessant ist, dass dies nur mit POST und PATCH, aber nicht mit PUT - Anfragen auf die Projekt-Ressource funktioniert. Dies ist dadurch begründet, dass kein eindeutiges Verhalten definiert werden kann, für den Fall, dass keine Module angegeben werden würden. Schließlich könnte die Intention sein, entweder alle Module zu löschen, weil kein Modul als Link enthalten ist oder kein Modul zu löschen, weil Module absichtlich nicht als Links mitgeschickt wurden, weil diese eigentlich Teil einer Association Ressource sind und nicht der Projekt Ressource (Quelle).

Erweiterte addRelation Methode

Eine weitere Möglichkeit ergibt sich daraus, mithilfe einer eigenen CustomResource-Klasse die Funktionen des bestehenden Frameworks zu nutzen, um eine Methode zu implementieren, welche alle Module auf einmal verlinkt. Diese könnte wie folgt aussehen:

export class CustomResource extends Resource {

 private createUriListFromResourceArray<T extends Resource>(resources: T[]): String {
   let uriList : String = new String();

   for (let i = 0; i < resources.length; i++) {
     if (i != 0) {
       uriList = uriList.concat("\n");
     }
     uriList = uriList.concat(resources[i]._links.self.href);
   }
   return uriList;
 }

 // Set collection of related resources
 public setRelationArray<T extends Resource>(relation: string, resources: T[]): Observable<any> {
   let header = ResourceHelper.headers.append('Content-Type', 'text/uri-list');
   let payload = this.createUriListFromResourceArray(resources);

   return ResourceHelper.getHttp().put(ResourceHelper.getProxy(this._links[relation].href), payload, {headers: header});
 }
}

Die Methode setRelationArray führt eine PUT-Anfrage auf die Association selbst aus und schickt als Payload eine URI-List, welche alle self-Links der Module enthält. Um die URI-Liste zu generieren, wird die Methode createUriListFromResourceArray genutzt. Bei dieser Variante muss nun bei jeder Anzahl von Modulen nur insgesamt eine Anfrage gesendet werden, sodass keine inkonsistenten Zustände wie bei dem Aufteilen auf mehrere Anfragen entstehen können. Infolgedessen scheint diese Variante geeignet und wurde für das Verknüpfen von Projekten mit Modulen genutzt.