diff --git a/src/main/java/org/texttechnologylab/project/gruppe_05_1/database/MongoPprUtils.java b/src/main/java/org/texttechnologylab/project/gruppe_05_1/database/MongoPprUtils.java index b020bbf..6199798 100644 --- a/src/main/java/org/texttechnologylab/project/gruppe_05_1/database/MongoPprUtils.java +++ b/src/main/java/org/texttechnologylab/project/gruppe_05_1/database/MongoPprUtils.java @@ -1,14 +1,22 @@ package org.texttechnologylab.project.gruppe_05_1.database; +import com.mongodb.client.FindIterable; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoCursor; import org.bson.Document; +import org.texttechnologylab.project.gruppe_05_1.database.domainimp.speeches.Speech_MongoDB_Impl; import org.texttechnologylab.project.gruppe_05_1.domain.html.Parlamentarier; import org.texttechnologylab.project.gruppe_05_1.domain.html.ParlamentarierDetails; import org.texttechnologylab.project.gruppe_05_1.domain.speaker.Membership; +import org.texttechnologylab.project.gruppe_05_1.domain.speech.SpeechMetaData; +import org.texttechnologylab.project.gruppe_05_1.util.GeneralUtils; +import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Impls.Speech_File_Impl; +import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Interfaces.Speech; import java.time.LocalDate; +import java.time.LocalDateTime; import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.*; /** @@ -32,6 +40,8 @@ public class MongoPprUtils { private static MongoCollection speakerCollection = null; private static MongoCollection speechCollection = null; + private static MongoCollection sessionCollection = null; + private static MongoCollection agendaItemsCollection = null; private static MongoCollection picturesCollection = null; private static MongoCollection commentCollection = null; @@ -45,6 +55,15 @@ public class MongoPprUtils { return speechCollection; } + public static MongoCollection getSessionCollection() { + if (sessionCollection == null) sessionCollection = MongoDBHandler.getMongoDatabase().getCollection(SESSION_COLLECTION_NAME); + return sessionCollection; + } + + public static MongoCollection getAgendaItemsCollection() { + if (agendaItemsCollection == null) agendaItemsCollection = MongoDBHandler.getMongoDatabase().getCollection(AGENDA_ITEMS_COLLECTION_NAME); + return agendaItemsCollection; + } /** * Create the Speaker Collection and useful indices for it @@ -259,4 +278,114 @@ public class MongoPprUtils { } // TODO: kopiere die Speech-Sachen von Übung 4 hierher! + + /** + * Aufzählen, wie viele Reden eines bestimmten Redners gespeichert sind + * @param speakerId + * @return Anzahl Reden + */ + public static Long countSpeechesOfSpeaker(String speakerId) { + return getSpeechCollection().countDocuments(new Document("speakerId", Integer.parseInt(speakerId))); + } + + + /** + * Liefert alle Reden eines Redners zurück + * @param speakerId + * @return Alle Reden eines Redners + */ + public static List getSpeechesOfSpeaker(String speakerId) { + List speeches = new ArrayList<>(); + + Document filter = new Document("speakerId", Integer.parseInt(speakerId)); + List docs = getSpeechCollection().find(filter).into(new ArrayList<>()); + + for (Document doc : docs) { + speeches.add(new Speech_MongoDB_Impl(doc)); + } + + return speeches; + } + + /** + * Liefert Metadaten (aber keine Inhalte!) für alle Reden eines Redners zurück. + * Als Metadaten zählen das Datum, Agenda-ID etc. + * @param speakerId + * @return + */ + public static List getSpeechesMetadataForSeaker(String speakerId) { + + List speechMetaDataList = new ArrayList<>(); + List speeches = MongoPprUtils.getSpeechesOfSpeaker(speakerId); + for (Speech speech : speeches) { + SpeechMetaData md = new SpeechMetaData(); + + md.setSpeechKey(speech.getSpeechKey()); + md.setSpeechId(speech.getSpeechId()); + md.setSpeakerId(speech.getSpeakerId()); + int sessionId = speech.getSessionId(); + md.setSessionId(sessionId); + + + // aus "sessions" Collection + String dateTimeString = getSessionDateTime(sessionId); + if (dateTimeString != null) { + md.setDateTimeString(dateTimeString); + LocalDateTime tmp = GeneralUtils.parseDateTime(dateTimeString, "dd.MM.yyyy HH:mm"); + if (tmp == null) { + tmp = GeneralUtils.parseDateTime(dateTimeString, "dd.MM.yyyy H:mm"); + if (tmp == null) { + System.out.println(dateTimeString + " could not be parsed"); + } + } + md.setDateTime(tmp); + } + + // aus "agendaItems" Collection + int agendaItemId = speech.getAgendaItemId(); + String agendaTitel = getAgendaTitle(sessionId, agendaItemId); + md.setAgendaTitle(agendaTitel); + + speechMetaDataList.add(md); + + } + + // Sortiere nach Datum, absteigend + speechMetaDataList.sort((md1, md2) -> { + return md2.getDateTime().compareTo(md1.getDateTime()); + }); + + return speechMetaDataList; + } + + + /** + * Liefert das Datum und die Uhrzeit einer Sitzung zurück + * @param sessionId + * @return + */ + public static String getSessionDateTime(int sessionId) { + Document filter = new Document("sessionId", sessionId); + Object dateTime = getSessionCollection().find(filter).first().get("dateTime"); + if (dateTime == null) { + return null; + } else { + return (String) dateTime; + } + } + + /** + * Liefert den Agenda-Titel zurück + * @param sessionId + * @return + */ + public static String getAgendaTitle(int sessionId, int agendaItemId) { + Document filter = new Document("sessionId", sessionId).append("id", agendaItemId); + FindIterable iter = getAgendaItemsCollection().find(filter); + if ((iter == null || (iter.first() == null))) { + return "(kein Agendatitel)"; + } else { + return (String) iter.first().get("title"); + } + } } diff --git a/src/main/java/org/texttechnologylab/project/gruppe_05_1/domain/speech/SpeechMetaData.java b/src/main/java/org/texttechnologylab/project/gruppe_05_1/domain/speech/SpeechMetaData.java new file mode 100644 index 0000000..bb9d55d --- /dev/null +++ b/src/main/java/org/texttechnologylab/project/gruppe_05_1/domain/speech/SpeechMetaData.java @@ -0,0 +1,104 @@ +package org.texttechnologylab.project.gruppe_05_1.domain.speech; + +import java.time.LocalDateTime; +import java.util.Objects; +import java.util.StringJoiner; + +/** + * Diese Klasse dient der Darstellung aller Reden eines Parlamentariers. + */ +public class SpeechMetaData { + // aus "speech" Collection + String speechKey; // z.B. "ID2011400300" + int speechId; // TODO: nötig? + int speakerId; + int sessionId; // TODO: nötig? + + // aus "sessions" Collection + LocalDateTime dateTime; + String dateTimeString; + + // aus "agendaItems" Collection + String agendaTitle; + + public String getSpeechKey() { + return speechKey; + } + + public void setSpeechKey(String speechKey) { + this.speechKey = speechKey; + } + + public int getSpeechId() { + return speechId; + } + + public void setSpeechId(int speechId) { + this.speechId = speechId; + } + + public int getSpeakerId() { + return speakerId; + } + + public void setSpeakerId(int speakerId) { + this.speakerId = speakerId; + } + + public int getSessionId() { + return sessionId; + } + + public void setSessionId(int sessionId) { + this.sessionId = sessionId; + } + + public LocalDateTime getDateTime() { + return dateTime; + } + + public void setDateTime(LocalDateTime dateTime) { + this.dateTime = dateTime; + } + + public String getDateTimeString() { + return dateTimeString; + } + + public void setDateTimeString(String dateTimeString) { + this.dateTimeString = dateTimeString; + } + + public String getAgendaTitle() { + return agendaTitle; + } + + public void setAgendaTitle(String agendaTitle) { + this.agendaTitle = agendaTitle; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof SpeechMetaData that)) return false; + return speechId == that.speechId && speakerId == that.speakerId && sessionId == that.sessionId && Objects.equals(speechKey, that.speechKey) && Objects.equals(dateTime, that.dateTime) && Objects.equals(dateTimeString, that.dateTimeString) && Objects.equals(agendaTitle, that.agendaTitle); + } + + @Override + public int hashCode() { + return Objects.hash(speechKey, speechId, speakerId, sessionId, dateTime, dateTimeString, agendaTitle); + } + + @Override + public String toString() { + return new StringJoiner(", ", SpeechMetaData.class.getSimpleName() + "[", "]") + .add("speechKey='" + speechKey + "'") + .add("speechId=" + speechId) + .add("speakerId=" + speakerId) + .add("sessionId=" + sessionId) + .add("dateTime=" + dateTime) + .add("dateTimeString='" + dateTimeString + "'") + .add("agendaTitle='" + agendaTitle + "'") + .toString(); + } +} diff --git a/src/main/java/org/texttechnologylab/project/gruppe_05_1/rest/ParlamentarierController.java b/src/main/java/org/texttechnologylab/project/gruppe_05_1/rest/ParlamentarierController.java index aaed14d..6a63a9a 100644 --- a/src/main/java/org/texttechnologylab/project/gruppe_05_1/rest/ParlamentarierController.java +++ b/src/main/java/org/texttechnologylab/project/gruppe_05_1/rest/ParlamentarierController.java @@ -6,7 +6,9 @@ import org.texttechnologylab.project.gruppe_05_1.domain.html.Parlamentarier; import org.texttechnologylab.project.gruppe_05_1.domain.html.ParlamentarierDetails; import org.texttechnologylab.project.gruppe_05_1.database.MongoPprUtils; import org.texttechnologylab.project.gruppe_05_1.util.PPRUtils; +import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Interfaces.Speech; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -31,6 +33,8 @@ public class ParlamentarierController { * @param ctx JavaLin-Context */ + private static List emptyList = new ArrayList<>(); // passed as an indicator if a certain list exists or not (in latter case: pass null) + @OpenApi( summary = "Get alle Parlamentarier. Man kann nach Vor-, Nachname oder Partei filtern.", description = "Listet alle Parlamentarier bzw. diejenige, welche den Filter entsprechen", @@ -88,7 +92,16 @@ public class ParlamentarierController { Map attributes = new HashMap<>(); attributes.put("p", pd); - attributes.put("speechesCount", pd.getReden() == null ? 0 : pd.getReden().size()); + Long speechCount = MongoPprUtils.countSpeechesOfSpeaker(pd.getId()); + attributes.put("speechesCount", speechCount); + if (speechCount == 0) { + attributes.put("speechesPlaceholder", null); + } else { + attributes.put("speechesPlaceholder", emptyList); + } + + + List speeches = MongoPprUtils.getSpeechesOfSpeaker(pd.getId()); ctx.render("parlamentarierDetails.ftl", attributes); } diff --git a/src/main/java/org/texttechnologylab/project/gruppe_05_1/rest/RESTHandler.java b/src/main/java/org/texttechnologylab/project/gruppe_05_1/rest/RESTHandler.java index 1f5561c..1eb08d6 100644 --- a/src/main/java/org/texttechnologylab/project/gruppe_05_1/rest/RESTHandler.java +++ b/src/main/java/org/texttechnologylab/project/gruppe_05_1/rest/RESTHandler.java @@ -57,17 +57,9 @@ public class RESTHandler { app.get("/portfolio/{id}", ParlamentarierController::getParlamentarierDetails); app.delete("/deleteParlamentarier", ParlamentarierController::deleteAllParlamentarier); - /* - TODO - // Fotos - app.get("/editFoto/{id}", FotosController::editFotos); - app.post("/editFoto/updateFotoUrl/{id}/{pictureId}", FotosController::updateFotoUrl); - app.post("/editFoto/defineFotoAsPrimary/{id}", FotosController::defineFotoAsPrimary); - // Reden - app.get("/reden/{id}", RedenController::listSpeeches); // zeige Reden eines Parlamentariers an - app.get("/reden/{id}/{redeId}", RedenController::showSpeech); // zeige eine bestimmte Rede des Parlamentariers an - app.post("/reden/updateComment/{id}/{speechId}/{commentId}", RedenController::updateComment); // aktualisiere Änderung an einer Kommentar + app.get("/reden/{id}", SpeechController::listSpeeches); // zeige Reden eines Parlamentariers an + app.get("/reden/{id}/{redeId}", SpeechController::showSpeech); // zeige eine bestimmte Rede des Parlamentariers an - */ } } diff --git a/src/main/java/org/texttechnologylab/project/gruppe_05_1/rest/SpeechController.java b/src/main/java/org/texttechnologylab/project/gruppe_05_1/rest/SpeechController.java new file mode 100644 index 0000000..999c258 --- /dev/null +++ b/src/main/java/org/texttechnologylab/project/gruppe_05_1/rest/SpeechController.java @@ -0,0 +1,105 @@ +package org.texttechnologylab.project.gruppe_05_1.rest; + +import io.javalin.http.Context; +import io.javalin.openapi.*; +import org.texttechnologylab.project.gruppe_05_1.database.MongoPprUtils; +import org.texttechnologylab.project.gruppe_05_1.domain.html.ParlamentarierDetails; +import org.texttechnologylab.project.gruppe_05_1.domain.speech.Protocol; +import org.texttechnologylab.project.gruppe_05_1.domain.speech.SpeechMetaData; +import org.texttechnologylab.project.gruppe_05_1.util.GeneralUtils; +import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Interfaces.Comment; +import org.texttechnologylab.project.gruppe_05_1.xml.speeches.Interfaces.Speech; + +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class SpeechController { + /** + * Liste alle Reden eines Parlamentariers an + * @param ctx Javalin Context + */ + @OpenApi( + summary = "Liste alle Reden eines Parlamentariers an", + description = "Liste alle Reden eines Parlamentariers an", + operationId = "listSpeeches", + path = "/reden/{id}", + methods = HttpMethod.GET, + tags = {"Rede"}, + pathParams = { + @OpenApiParam(name = "id", description = "id des Parlamentariers", required = true), + }, + responses = { + @OpenApiResponse(status = "200", content = {@OpenApiContent(from = Speech[].class)}) + }) + public static void listSpeeches(Context ctx) { + String parlamentarierId = ctx.pathParam("id"); + + ParlamentarierDetails p = MongoPprUtils.getParlamentarierDetailsByID(parlamentarierId); + List speechMetaDataList = MongoPprUtils.getSpeechesMetadataForSeaker(parlamentarierId); + + Map attributes = new HashMap<>(); + attributes.put("p", p); + attributes.put("speechesMetaDataList", speechMetaDataList); + ctx.render("showSpeechesList.ftl", attributes); + } + + /** + * Zeige eine bestimmte Rede des Parlamentariers an + * @param ctx Javalin Context + */ + @OpenApi( + summary = "Zeige eine bestimmte Rede des Parlamentariers an", + description = "Zeige eine bestimmte Rede des Parlamentariers an", + operationId = "showSpeech", + path = "/reden/{id}/{redeID}", + methods = HttpMethod.GET, + tags = {"Rede"}, + pathParams = { + @OpenApiParam(name = "id", description = "id des Parlamentariers", required = true), + @OpenApiParam(name = "redeId", description = "id der Rede", required = true), + }, + responses = { + @OpenApiResponse(status = "200", content = {@OpenApiContent(from = Speech.class)}) + }) + public static void showSpeech(Context ctx) { + String parlamentarierId = ctx.pathParam("id"); + String redeId = ctx.pathParam("redeId"); + + Map attributes = new HashMap<>(); + + /* + Speech rede = MongoPprUtils.getSpeechesById(redeId); + List comments = MongoPprUtils.getCommentsForSpeech(redeId); + ParlamentarierDetails p = MongoPprUtils.getParlamentarierDetailsByID(parlamentarierId); + + + attributes.put("p", p); + attributes.put("rede", rede); + attributes.put("comments", comments.size() > 0 ? comments : null); + Protocol protocol = rede.getProtocol(); + if (protocol == null) { + attributes.put("date", "(keine Angaben)"); + attributes.put("time", "(keine Angaben)"); + } else { + LocalDate date = protocol.getDate(); + LocalTime time = protocol.getStarttime(); + if (date == null) { + attributes.put("date", "(keine Angaben)"); + } else { + attributes.put("date", GeneralUtils.formatDate(date)); + } + if (time == null) { + attributes.put("time", "(keine Angaben)"); + } else { + attributes.put("time", GeneralUtils.formatTime(time)); + } + } + + */ + ctx.render("speechWithComments.ftl", attributes); + } + +} diff --git a/src/main/java/org/texttechnologylab/project/gruppe_05_1/util/GeneralUtils.java b/src/main/java/org/texttechnologylab/project/gruppe_05_1/util/GeneralUtils.java index 0b013a3..d67d198 100644 --- a/src/main/java/org/texttechnologylab/project/gruppe_05_1/util/GeneralUtils.java +++ b/src/main/java/org/texttechnologylab/project/gruppe_05_1/util/GeneralUtils.java @@ -1,6 +1,7 @@ package org.texttechnologylab.project.gruppe_05_1.util; import java.time.LocalDate; +import java.time.LocalDateTime; import java.time.LocalTime; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; @@ -74,4 +75,11 @@ public abstract class GeneralUtils { return time.format(DateTimeFormatter.ofPattern("HH.mm")); } + public static LocalDateTime parseDateTime(String dateTime, String timeFormat) { + try { + return LocalDateTime.parse(dateTime, DateTimeFormatter.ofPattern(timeFormat)); + } catch (DateTimeParseException ex) { + return null; + } + } } diff --git a/src/main/java/org/texttechnologylab/project/gruppe_05_1/website/templates/parlamentarierDetails.ftl b/src/main/java/org/texttechnologylab/project/gruppe_05_1/website/templates/parlamentarierDetails.ftl index 0ad5435..732a4ef 100644 --- a/src/main/java/org/texttechnologylab/project/gruppe_05_1/website/templates/parlamentarierDetails.ftl +++ b/src/main/java/org/texttechnologylab/project/gruppe_05_1/website/templates/parlamentarierDetails.ftl @@ -26,10 +26,10 @@

Reden

- <#if p.reden??> + <#if speechesPlaceholder??> ${speechesCount} Reden vorhanden <#else> - Keine Reden + Keine Reden vorhanden

diff --git a/src/main/java/org/texttechnologylab/project/gruppe_05_1/website/templates/showSpeechesList.ftl b/src/main/java/org/texttechnologylab/project/gruppe_05_1/website/templates/showSpeechesList.ftl new file mode 100644 index 0000000..fc8ba12 --- /dev/null +++ b/src/main/java/org/texttechnologylab/project/gruppe_05_1/website/templates/showSpeechesList.ftl @@ -0,0 +1,43 @@ + + + + + + Reden von ${p.vorname} ${p.nachname} (${p.partei}) + + + +
+

Reden von ${p.vorname} ${p.nachname} (${p.partei})

+
+ +
+
+ + + + + + + + + + + <#list speechesMetaDataList as redeMd> + + + + + + + +
DatumSitzung / Agenda
${redeMd.dateTimeString}${redeMd.sessionId} / ${redeMd.agendaTitle}
+
+
+ \ No newline at end of file