other merge conflict resloves
This commit is contained in:
parent
37a300fa50
commit
332fe49a02
5 changed files with 453 additions and 9 deletions
|
@ -4,6 +4,7 @@ import com.mongodb.MongoClientSettings;
|
|||
import com.mongodb.MongoCredential;
|
||||
import com.mongodb.ServerAddress;
|
||||
import com.mongodb.WriteConcern;
|
||||
import com.mongodb.WriteConcern;
|
||||
import com.mongodb.bulk.BulkWriteResult;
|
||||
import com.mongodb.client.MongoClient;
|
||||
import com.mongodb.client.MongoClients;
|
||||
|
@ -773,6 +774,14 @@ public class MongoDBHandler {
|
|||
return count > 0;
|
||||
}
|
||||
|
||||
public String getMemberPhoto(String memberId) {
|
||||
Document photoDocument = memberPhotoCollection.find(eq("memberId", memberId)).first();
|
||||
if (photoDocument == null) {
|
||||
return null;
|
||||
}
|
||||
return photoDocument.getString("base64");
|
||||
}
|
||||
|
||||
public void close() {
|
||||
mongoClient.close();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
package org.texttechnologylab.project.gruppe_05_1.rest;
|
||||
|
||||
import gnu.trove.impl.sync.TSynchronizedShortObjectMap;
|
||||
import io.javalin.http.Context;
|
||||
import io.javalin.openapi.*;
|
||||
import org.apache.commons.collections.bag.SynchronizedSortedBag;
|
||||
import org.texttechnologylab.project.gruppe_05_1.database.MongoPprUtils;
|
||||
import org.texttechnologylab.project.gruppe_05_1.domain.html.HtmlSpeech;
|
||||
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.speech.SpeechMetaData;
|
||||
import org.texttechnologylab.project.gruppe_05_1.util.Logger;
|
||||
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;
|
||||
|
||||
public class FrontEndController {
|
||||
@OpenApi(
|
||||
summary = "Get the homepage.",
|
||||
description = "Get the homepage",
|
||||
operationId = "getHomepage",
|
||||
path = "/",
|
||||
methods = HttpMethod.GET,
|
||||
tags = {"Homepage"},
|
||||
responses = {
|
||||
@OpenApiResponse(status = "200")
|
||||
})
|
||||
public static void getHomepage(Context ctx) {
|
||||
ctx.render("home.ftl");
|
||||
}
|
||||
|
||||
@OpenApi(
|
||||
summary = "Get alle Parlamentarier. Man kann nach Vor-, Nachname oder Partei filtern.",
|
||||
description = "Listet alle Parlamentarier bzw. diejenige, welche den Filter entsprechen",
|
||||
operationId = "getAllParlamentarier",
|
||||
path = "/",
|
||||
methods = HttpMethod.GET,
|
||||
tags = {"Parlamentarier"},
|
||||
queryParams = {
|
||||
@OpenApiParam(name = "filter", description = "Full-Text-Filter. Kann Vorname, Nachname oder Partei filtern", required = false),
|
||||
},
|
||||
responses = {
|
||||
@OpenApiResponse(status = "200", content = {@OpenApiContent(from = Parlamentarier[].class)})
|
||||
})
|
||||
public static void getAllParlamentarier(Context ctx) {
|
||||
String filter = ctx.queryParam("filter");
|
||||
Logger.info("Filter: '" + filter + "'");
|
||||
|
||||
List<Parlamentarier> parlamentarier = MongoPprUtils.getAllParlamentarier(filter);
|
||||
PPRUtils.sortParlamentarierByName(parlamentarier);
|
||||
Logger.info(parlamentarier.size() + " MdBs gefunden");
|
||||
|
||||
Map<String, Object> attributes = new HashMap<>();
|
||||
attributes.put("parlamentarier", parlamentarier);
|
||||
attributes.put("filter", filter);
|
||||
ctx.render("parlamentarier.ftl", attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt die Details eines Parlamentariers an:
|
||||
* - persönliche Daten (Geburtsdatum, -ort, Vita, Religion etc.).
|
||||
* - Mitgliederschaften, falls vorhanden
|
||||
* - Fotos, falls vorhanden
|
||||
* @param ctx JavaLin-Context
|
||||
*/
|
||||
|
||||
@OpenApi(
|
||||
summary = "Zeigt die Details eines Parlamentariers an",
|
||||
description = "Zeigt persönliche Daten, Mitgliederschaften, Fotos",
|
||||
operationId = "getParlamentarierDetails",
|
||||
path = "/portfolio/{id}",
|
||||
methods = HttpMethod.GET,
|
||||
tags = {"Parlamentarier"},
|
||||
pathParams = {
|
||||
@OpenApiParam(name = "id", description = "id des Parlamentariers", required = true),
|
||||
},
|
||||
responses = {
|
||||
@OpenApiResponse(status = "200", content = {@OpenApiContent(from = ParlamentarierDetails.class)})
|
||||
})
|
||||
public static void getParlamentarierDetails(Context ctx) {
|
||||
String id = ctx.pathParam("id");
|
||||
Logger.info("getParlamentarierDetails, ID = " + id);
|
||||
|
||||
ParlamentarierDetails pd = MongoPprUtils.getParlamentarierDetailsByID(id);
|
||||
|
||||
Map<String, Object> attributes = new HashMap<>();
|
||||
attributes.put("p", pd);
|
||||
Long speechCount = MongoPprUtils.countSpeechesOfSpeaker(pd.getId());
|
||||
attributes.put("speechesCount", speechCount);
|
||||
attributes.put("pic", MongoPprUtils.getMemberPhoto(pd.getId()));
|
||||
if (speechCount == 0) {
|
||||
attributes.put("speechesPlaceholder", null);
|
||||
} else {
|
||||
attributes.put("speechesPlaceholder", new ArrayList<>());
|
||||
}
|
||||
|
||||
ctx.render("parlamentarierDetails.ftl", attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<SpeechMetaData> speechMetaDataList = MongoPprUtils.getSpeechesMetadataForSpeaker(parlamentarierId);
|
||||
|
||||
Map<String, Object> 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 redeId = ctx.pathParam("redeId");
|
||||
|
||||
Map<String, Object> attributes = new HashMap<>();
|
||||
|
||||
HtmlSpeech speech = MongoPprUtils.getSpeechByKey(redeId);
|
||||
attributes.put("s", speech);
|
||||
|
||||
ctx.render("speech.ftl", attributes);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
package org.texttechnologylab.project.gruppe_05_1.rest;
|
||||
|
||||
import freemarker.template.Configuration;
|
||||
import freemarker.template.TemplateExceptionHandler;
|
||||
import io.javalin.Javalin;
|
||||
import io.javalin.http.staticfiles.Location;
|
||||
import io.javalin.openapi.plugin.OpenApiPlugin;
|
||||
import io.javalin.openapi.plugin.redoc.ReDocPlugin;
|
||||
import io.javalin.rendering.template.JavalinFreemarker;
|
||||
import org.texttechnologylab.project.gruppe_05_1.util.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.texttechnologylab.project.gruppe_05_1.Main.JAVALIN_STATIC_FILES_DIR;
|
||||
import static org.texttechnologylab.project.gruppe_05_1.Main.JAVALIN_TEMPLATE_DIR;
|
||||
|
||||
public class RESTHandlerOld {
|
||||
|
||||
public void startJavalin() {
|
||||
|
||||
// Javalin Konfiguration (z.B. port)
|
||||
JavalinConfig jlConfig = new JavalinConfig();
|
||||
int port = jlConfig.getPort();
|
||||
|
||||
// FreeMarker Konfiguration
|
||||
Configuration fmConfig = new Configuration(Configuration.VERSION_2_3_33);
|
||||
fmConfig.setDefaultEncoding("UTF-8");
|
||||
try {
|
||||
fmConfig.setDirectoryForTemplateLoading(new File(JAVALIN_TEMPLATE_DIR));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
fmConfig.setLogTemplateExceptions(true);
|
||||
fmConfig.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
|
||||
|
||||
// Erzeuge die Javalin app
|
||||
Javalin app = Javalin.create(config -> {
|
||||
config.staticFiles.add(JAVALIN_STATIC_FILES_DIR, Location.EXTERNAL); // momentan nicht benutzt
|
||||
|
||||
config.fileRenderer(new JavalinFreemarker(fmConfig));
|
||||
|
||||
config.registerPlugin(new OpenApiPlugin(pluginConfig -> {
|
||||
// Define OpenAPI spec configuration
|
||||
pluginConfig.withDefinitionConfiguration((version, definition) -> {
|
||||
definition.withOpenApiInfo(info -> info.setTitle("Javalin OpenAPI Documentation"));
|
||||
});
|
||||
}));
|
||||
|
||||
config.registerPlugin(new ReDocPlugin());
|
||||
|
||||
})
|
||||
.start(port);
|
||||
Logger.info("Javalin app started on http://localhost:" + port);
|
||||
|
||||
// Routes
|
||||
// ======
|
||||
|
||||
// Parlamentarier
|
||||
app.get("/", ParlamentarierController::getAllParlamentarier);
|
||||
app.get("/portfolio/{id}", ParlamentarierController::getParlamentarierDetails);
|
||||
app.delete("/deleteParlamentarier", ParlamentarierController::deleteAllParlamentarier);
|
||||
|
||||
// Reden
|
||||
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
|
||||
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<h1>Heading</h1>
|
||||
<p>paragraph.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
214
src/main/resources/static/index.css
Normal file
214
src/main/resources/static/index.css
Normal file
|
@ -0,0 +1,214 @@
|
|||
@import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css');
|
||||
|
||||
:root {
|
||||
--primary-color: #333;
|
||||
--accent-color: #a00000;
|
||||
--background-color: #F4F4F9;
|
||||
--confirm-button-color: #28a745;
|
||||
--confirm-button-color-hover: #218838;
|
||||
--header-background-color: darkgray;
|
||||
}
|
||||
|
||||
|
||||
/* General Reset */
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
background-color: var(--background-color)
|
||||
}
|
||||
|
||||
header {
|
||||
background-color: var(--header-background-color);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
nav {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
nav a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
font-size: 1.25rem;
|
||||
margin: 10px;
|
||||
margin-top: 0;
|
||||
padding: 5px 10px 5px 10px;
|
||||
border: solid 1px white;
|
||||
border-radius: 5px
|
||||
}
|
||||
|
||||
footer {
|
||||
background-color: black;
|
||||
color: white;
|
||||
text-align: center;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
/* Body Styling */
|
||||
body {
|
||||
font-family: 'Arial', sans-serif;
|
||||
background-color: #f4f4f9;
|
||||
color: var(--primary-color);
|
||||
line-height: 1.6;
|
||||
padding: 20px;
|
||||
margin-top: 120px
|
||||
}
|
||||
|
||||
/* Heading Styling */
|
||||
h1, h2 {
|
||||
text-align: center;
|
||||
font-size: 2.5rem;
|
||||
color: var(--accent-color);
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
/* Form Styling */
|
||||
form {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 15px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
input[type="text"] {
|
||||
padding: 10px;
|
||||
font-size: 1rem;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 10px 20px;
|
||||
font-size: 1rem;
|
||||
background-color: var(--accent-color);
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: var(--accent-color);
|
||||
}
|
||||
|
||||
/* Table Styling */
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 30px;
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: 12px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color:
|
||||
var(--background-color);
|
||||
color: var(--accent-color);
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
td {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
td a {
|
||||
text-decoration: none;
|
||||
color: var(--accent-color);
|
||||
font-weight: bold;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
td a:hover {
|
||||
color: var(--accent-color);
|
||||
}
|
||||
|
||||
tbody tr:hover {
|
||||
background-color: var(--background-color);
|
||||
}
|
||||
|
||||
/* Responsive Styling */
|
||||
@media (max-width: 768px) {
|
||||
table, th, td {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
form {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
input[type="text"] {
|
||||
width: 100%;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
button {
|
||||
width: 100%;
|
||||
max-width: 150px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.add-member-button {
|
||||
background-color: var(--confirm-button-color); /* Green color */
|
||||
color: white;
|
||||
padding: 10px 20px;
|
||||
text-decoration: none;
|
||||
border-radius: 5px;
|
||||
font-size: 16px;
|
||||
display: inline-block;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
/* Change button color on hover */
|
||||
.add-member-button:hover {
|
||||
background-color: var(--confirm-button-color-hover); /* Darker green on hover */
|
||||
}
|
||||
|
||||
#search-button {
|
||||
width: 75px;
|
||||
background-color: var(--confirm-button-color);
|
||||
border-radius: 5px;
|
||||
border: 1px solid lightgray;
|
||||
}
|
||||
|
||||
#search-button:hover {
|
||||
background-color: var(--confirm-button-color-hover);
|
||||
}
|
||||
|
||||
.back-link {
|
||||
position: fixed;
|
||||
bottom: 50px;
|
||||
right: 50px;
|
||||
background-color: var(--accent-color);
|
||||
border-radius: 5px;
|
||||
padding: 5px 10px 5px 10px;
|
||||
text-decoration: none;
|
||||
color: white
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue