From c19bb535f4023df5863dd10b7afc5b0693dccba5 Mon Sep 17 00:00:00 2001
From: Johannes Theiner
Date: Wed, 29 May 2019 12:37:28 +0200
Subject: [PATCH] ~ refactor web
Signed-off-by: Johannes Theiner
#SPM-32: add work 2h development
---
.../de/hsel/spm/baudas/analysis/Analysis.java | 2 +-
.../hsel/spm/baudas/analysis/Attribute.java | 2 +-
.../de/hsel/spm/baudas/analysis/Cluster.java | 2 +-
...{TopFlopArticle.java => SalesNumbers.java} | 7 +-
.../spm/baudas/analysis/ShoppingCart.java | 2 +-
.../spm/baudas/analysis/ShoppingTimes.java | 2 +-
.../spm/baudas/analysis/WeekOverview.java | 15 +-
.../spm/baudas/web/AuthenticationFilter.java | 67 ------
.../spm/baudas/web/AuthorizationFilter.java | 68 ++++++
.../web/{Data.java => DatasetManagement.java} | 12 +-
.../web/{Files.java => DatasetsServlet.java} | 18 +-
.../de/hsel/spm/baudas/web/ErrorCode.java | 1 +
.../de/hsel/spm/baudas/web/LoginServlet.java | 24 ++-
.../de/hsel/spm/baudas/web/LogoutServlet.java | 19 +-
.../de/hsel/spm/baudas/web/SavedFile.java | 2 +-
.../spm/baudas/web/ShoppingCartDiagram.java | 70 -------
.../web/{Upload.java => UploadServlet.java} | 11 +-
.../ClusterTable.java} | 47 +++--
.../spm/baudas/web/depiction/Depiction.java | 73 +++++++
.../SalesNumberChart.java} | 45 ++--
.../web/depiction/ShoppingCartTable.java | 80 +++++++
.../ShoppingTimesChart.java} | 59 +++---
.../WeekOverviewChart.java} | 44 ++--
src/main/resources/LogoBauDas2.gif | Bin 32328 -> 0 bytes
src/main/webapp/analysis.jsp | 87 ++++++++
src/main/webapp/footer.jsp | 18 +-
src/main/webapp/head.jsp | 1 +
src/main/webapp/index.jsp | 198 +-----------------
src/main/webapp/js/cache.js | 6 +-
src/main/webapp/js/{top_flop.js => sales.js} | 14 +-
src/main/webapp/login.html | 47 -----
src/main/webapp/login.jsp | 26 +++
src/main/webapp/marketing.jsp | 102 +++++++++
src/main/webapp/theming.jsp | 22 +-
.../baudas/analysis/TopFlopArticlesTest.java | 6 +-
.../spm/baudas/analysis/WeekOverviewTest.java | 2 +-
36 files changed, 638 insertions(+), 563 deletions(-)
rename src/main/java/de/hsel/spm/baudas/analysis/{TopFlopArticle.java => SalesNumbers.java} (91%)
delete mode 100644 src/main/java/de/hsel/spm/baudas/web/AuthenticationFilter.java
create mode 100644 src/main/java/de/hsel/spm/baudas/web/AuthorizationFilter.java
rename src/main/java/de/hsel/spm/baudas/web/{Data.java => DatasetManagement.java} (90%)
rename src/main/java/de/hsel/spm/baudas/web/{Files.java => DatasetsServlet.java} (66%)
delete mode 100644 src/main/java/de/hsel/spm/baudas/web/ShoppingCartDiagram.java
rename src/main/java/de/hsel/spm/baudas/web/{Upload.java => UploadServlet.java} (89%)
rename src/main/java/de/hsel/spm/baudas/web/{ClusterDiagram.java => depiction/ClusterTable.java} (52%)
create mode 100644 src/main/java/de/hsel/spm/baudas/web/depiction/Depiction.java
rename src/main/java/de/hsel/spm/baudas/web/{TopFlopArticleDiagram.java => depiction/SalesNumberChart.java} (60%)
create mode 100644 src/main/java/de/hsel/spm/baudas/web/depiction/ShoppingCartTable.java
rename src/main/java/de/hsel/spm/baudas/web/{ShoppingTimesDiagram.java => depiction/ShoppingTimesChart.java} (69%)
rename src/main/java/de/hsel/spm/baudas/web/{WeekOverviewDiagram.java => depiction/WeekOverviewChart.java} (71%)
delete mode 100644 src/main/resources/LogoBauDas2.gif
create mode 100644 src/main/webapp/analysis.jsp
rename src/main/webapp/js/{top_flop.js => sales.js} (72%)
delete mode 100644 src/main/webapp/login.html
create mode 100644 src/main/webapp/login.jsp
create mode 100644 src/main/webapp/marketing.jsp
diff --git a/src/main/java/de/hsel/spm/baudas/analysis/Analysis.java b/src/main/java/de/hsel/spm/baudas/analysis/Analysis.java
index 3f8f86a..3723996 100644
--- a/src/main/java/de/hsel/spm/baudas/analysis/Analysis.java
+++ b/src/main/java/de/hsel/spm/baudas/analysis/Analysis.java
@@ -12,7 +12,7 @@ import java.io.IOException;
*
* @author Johannes Theiner
* @version 0.1
- * @since 0.1
+ * @since 1.0
* @param Type the chosen analysis returns as a result
*/
public interface Analysis {
diff --git a/src/main/java/de/hsel/spm/baudas/analysis/Attribute.java b/src/main/java/de/hsel/spm/baudas/analysis/Attribute.java
index e6d9883..9d29e36 100644
--- a/src/main/java/de/hsel/spm/baudas/analysis/Attribute.java
+++ b/src/main/java/de/hsel/spm/baudas/analysis/Attribute.java
@@ -5,7 +5,7 @@ package de.hsel.spm.baudas.analysis;
*
* @author Johannes Theiner
* @version 0.1
- * @since 0.1
+ * @since 1.0
**/
class Attribute {
diff --git a/src/main/java/de/hsel/spm/baudas/analysis/Cluster.java b/src/main/java/de/hsel/spm/baudas/analysis/Cluster.java
index d8cd1bd..0608bd7 100644
--- a/src/main/java/de/hsel/spm/baudas/analysis/Cluster.java
+++ b/src/main/java/de/hsel/spm/baudas/analysis/Cluster.java
@@ -15,7 +15,7 @@ import java.util.Map;
*
* @author Johannes Theiner
* @version 0.1
- * @since 0.4
+ * @since 1.0
*/
public class Cluster implements Analysis>> {
diff --git a/src/main/java/de/hsel/spm/baudas/analysis/TopFlopArticle.java b/src/main/java/de/hsel/spm/baudas/analysis/SalesNumbers.java
similarity index 91%
rename from src/main/java/de/hsel/spm/baudas/analysis/TopFlopArticle.java
rename to src/main/java/de/hsel/spm/baudas/analysis/SalesNumbers.java
index 059532b..2950b7d 100644
--- a/src/main/java/de/hsel/spm/baudas/analysis/TopFlopArticle.java
+++ b/src/main/java/de/hsel/spm/baudas/analysis/SalesNumbers.java
@@ -15,15 +15,14 @@ import java.util.stream.Stream;
*
* @author Karsten Eden
* @version 0.1
- * @since 0.2
+ * @since 1.0
*/
-public class TopFlopArticle implements Analysis> {
+public class SalesNumbers implements Analysis> {
private Instances instances;
private Map results;
- public TopFlopArticle(File file) {
-
+ public SalesNumbers(File file) {
instances = load(file);
}
diff --git a/src/main/java/de/hsel/spm/baudas/analysis/ShoppingCart.java b/src/main/java/de/hsel/spm/baudas/analysis/ShoppingCart.java
index edac14f..f1277e1 100644
--- a/src/main/java/de/hsel/spm/baudas/analysis/ShoppingCart.java
+++ b/src/main/java/de/hsel/spm/baudas/analysis/ShoppingCart.java
@@ -18,7 +18,7 @@ import java.util.Map;
* The shopping-cart analysis.
*
* @author Julian Hinxlage
- * @version 0.4
+ * @version 1.0
*/
public class ShoppingCart implements Analysis, List>> {
diff --git a/src/main/java/de/hsel/spm/baudas/analysis/ShoppingTimes.java b/src/main/java/de/hsel/spm/baudas/analysis/ShoppingTimes.java
index 26810ba..f9c494f 100644
--- a/src/main/java/de/hsel/spm/baudas/analysis/ShoppingTimes.java
+++ b/src/main/java/de/hsel/spm/baudas/analysis/ShoppingTimes.java
@@ -13,7 +13,7 @@ import java.util.Map;
*
* @author Johannes Theiner
* @version 0.1
- * @since 0.1
+ * @since 1.0
**/
public class ShoppingTimes implements Analysis, Integer>> {
diff --git a/src/main/java/de/hsel/spm/baudas/analysis/WeekOverview.java b/src/main/java/de/hsel/spm/baudas/analysis/WeekOverview.java
index c41d92a..ee3dd19 100644
--- a/src/main/java/de/hsel/spm/baudas/analysis/WeekOverview.java
+++ b/src/main/java/de/hsel/spm/baudas/analysis/WeekOverview.java
@@ -13,7 +13,7 @@ import java.util.Map;
*
* @author Julian Hinxlage
* @version 0.1
- * @since 0.1
+ * @since 1.0
**/
public class WeekOverview implements Analysis>> {
@@ -45,14 +45,13 @@ public class WeekOverview implements Analysis(0.0, 0));
- } else {
- result.put(day,
- new AbstractMap.SimpleEntry<>(
- result.get(day).getKey() + amount,
- result.get(day).getValue() + 1
- )
- );
}
+ result.put(day,
+ new AbstractMap.SimpleEntry<>(
+ result.get(day).getKey() + amount,
+ result.get(day).getValue() + 1
+ )
+ );
}
diff --git a/src/main/java/de/hsel/spm/baudas/web/AuthenticationFilter.java b/src/main/java/de/hsel/spm/baudas/web/AuthenticationFilter.java
deleted file mode 100644
index df5f74f..0000000
--- a/src/main/java/de/hsel/spm/baudas/web/AuthenticationFilter.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package de.hsel.spm.baudas.web;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.annotation.WebFilter;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-import java.io.IOException;
-
-/**
- * Filter implementation class AuthenticationFilter.
- *
- * @author Edgar Schkrob
- */
-
-@WebFilter(urlPatterns = {"/*"})
-public class AuthenticationFilter implements Filter {
- private ServletContext context;
-
- /**
- * Called by the web container to indicate to a filter that it is being placed into service. This filter manages the authentication.
- *
- * @param filterConfig This parameter provides access to everything the code needs to work.
- * @throws ServletException Defines a general exception a servlet can throw when it encounters difficulty.
- */
-
- public void init(FilterConfig filterConfig) throws ServletException {
- this.context = filterConfig.getServletContext();
- this.context.log("AuthenticationFilter initialized");
- }
-
- /**
- * The doFilter method of the Filter is called by the container each time a request/response pair is passed through the chain due to a client request for a resource at the end of the chain.
- *
- * @param request This parameter provides access to everything the code needs to work.
- * @param response This parameter provides access to everything the code needs to issue a response.
- * @param chain This parameter allows passing request along the chain of potential handlers until one of them handles the request.
- * @throws ServletException Defines a general exception a servlet can throw when it encounters difficulty.
- * @throws IOException Signals that an I/O exception of some sort has occurred. This class is the general class of exceptions produced by failed or interrupted I/O operations.
- */
-
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
- HttpServletRequest req = (HttpServletRequest) request;
- HttpServletResponse res = (HttpServletResponse) response;
- HttpSession session = req.getSession(false);
- String url = req.getRequestURI();
- if (url.contains("login") || url.contains("logo") || url.contains("js/")) {
- chain.doFilter(request, response);
- } else if (session == null || !((boolean) session.getAttribute("authentication"))) { //checking whether the session exists and if authentication succeed
- this.context.log("Unauthorized access request");
- res.sendRedirect(req.getContextPath() + "/login.html");
- } else {
- chain.doFilter(request, response);
-
- }
- }
-
- public void destroy() {
- //close any resources here
- }
-}
\ No newline at end of file
diff --git a/src/main/java/de/hsel/spm/baudas/web/AuthorizationFilter.java b/src/main/java/de/hsel/spm/baudas/web/AuthorizationFilter.java
new file mode 100644
index 0000000..6d0b81c
--- /dev/null
+++ b/src/main/java/de/hsel/spm/baudas/web/AuthorizationFilter.java
@@ -0,0 +1,68 @@
+package de.hsel.spm.baudas.web;
+
+import org.jetbrains.annotations.NotNull;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.annotation.WebFilter;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import java.io.IOException;
+
+/**
+ * handles all authorisation filtering.
+ *
+ * @author Edgar Schkrob
+ * @version 0.1
+ * @since 0.4
+ */
+
+@WebFilter(urlPatterns = {"/*"})
+public class AuthorizationFilter implements Filter {
+
+ private ServletContext context;
+
+ /**
+ * initialize this filter.
+ *
+ * @param filterConfig configuration
+ * @throws ServletException failed to initialize filter
+ */
+ @Override
+ public void init(@NotNull FilterConfig filterConfig) throws ServletException {
+ this.context = filterConfig.getServletContext();
+ this.context.log("AuthorizationFilter initialized");
+ }
+
+ /**
+ * filter all unauthorized requests.
+ *
+ * @param request request object
+ * @param response response object
+ * @param chain filter chain
+ * @throws ServletException something failed inside the filter chain
+ * @throws IOException failed to redirect
+ */
+ @Override
+ public void doFilter(@NotNull ServletRequest request, @NotNull ServletResponse response, @NotNull FilterChain chain) throws IOException, ServletException {
+ HttpServletRequest req = (HttpServletRequest) request;
+ HttpServletResponse res = (HttpServletResponse) response;
+ HttpSession session = req.getSession(false);
+ String url = req.getRequestURI();
+ if (url.contains("login") || url.contains("logo") || url.contains("js/")) {
+ chain.doFilter(request, response);
+ } else if (session == null || !((boolean) session.getAttribute("authentication"))) { //checking whether the session exists and if authentication succeed
+ this.context.log("Unauthorized access request");
+ res.sendRedirect(req.getContextPath() + "/login.jsp");
+ } else {
+ chain.doFilter(request, response);
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/de/hsel/spm/baudas/web/Data.java b/src/main/java/de/hsel/spm/baudas/web/DatasetManagement.java
similarity index 90%
rename from src/main/java/de/hsel/spm/baudas/web/Data.java
rename to src/main/java/de/hsel/spm/baudas/web/DatasetManagement.java
index 88c3d32..5cd4f69 100644
--- a/src/main/java/de/hsel/spm/baudas/web/Data.java
+++ b/src/main/java/de/hsel/spm/baudas/web/DatasetManagement.java
@@ -22,9 +22,9 @@ import java.util.concurrent.ConcurrentMap;
*
* @author Johannes Theiner
* @version 0.1
- * @since 0.1
+ * @since 1.0
**/
-public class Data {
+public class DatasetManagement {
@Getter
private static ConcurrentMap> files = new ConcurrentHashMap<>();
@@ -46,7 +46,7 @@ public class Data {
if (files.get(session).size() >= 5) {
SavedFile file = files.get(session).iterator().next();
if (!get(file.getUuid()).delete()) {
- System.err.println("failed to delete file..." + file);
+ System.err.println("failed to delete file " + file);
}
files.get(session).remove(file);
}
@@ -59,10 +59,12 @@ public class Data {
*
* @param session session id
*/
- static void delete(String session) {
+ static void delete(@NotNull String session) {
+ if (!files.containsKey(session)) return;
+
for (SavedFile file : files.get(session)) {
if (!get(file.getUuid()).delete())
- System.err.println("failed to delete file..." + file);
+ System.err.println("failed to delete file " + file);
}
files.remove(session);
diff --git a/src/main/java/de/hsel/spm/baudas/web/Files.java b/src/main/java/de/hsel/spm/baudas/web/DatasetsServlet.java
similarity index 66%
rename from src/main/java/de/hsel/spm/baudas/web/Files.java
rename to src/main/java/de/hsel/spm/baudas/web/DatasetsServlet.java
index 362ef89..d809412 100644
--- a/src/main/java/de/hsel/spm/baudas/web/Files.java
+++ b/src/main/java/de/hsel/spm/baudas/web/DatasetsServlet.java
@@ -12,18 +12,26 @@ import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
/**
- * list all currently available files.
+ * list all currently available datasets.
*
* @author Johannes Theiner
* @version 0.1
- * @since 0.1
+ * @since 1.0
**/
-@WebServlet("/files")
-public class Files extends HttpServlet {
+@WebServlet("/datasets")
+public class DatasetsServlet extends HttpServlet {
private static final long serialVersionUID = 148451844848L;
+
+ /**
+ * returns all available datasets for session.
+ *
+ * @param req request object
+ * @param resp response object
+ * @throws IOException failed to initialize print writer
+ */
@Override
protected void doGet(@NotNull HttpServletRequest req, @NotNull HttpServletResponse resp)
throws IOException {
@@ -31,6 +39,6 @@ public class Files extends HttpServlet {
resp.setCharacterEncoding(StandardCharsets.UTF_8.name());
PrintWriter out = resp.getWriter();
Gson gson = new Gson();
- out.print(gson.toJson(Data.getFiles().get(req.getSession().getId())));
+ out.print(gson.toJson(DatasetManagement.getFiles().get(req.getSession().getId())));
}
}
\ No newline at end of file
diff --git a/src/main/java/de/hsel/spm/baudas/web/ErrorCode.java b/src/main/java/de/hsel/spm/baudas/web/ErrorCode.java
index 7fa1d53..c293349 100644
--- a/src/main/java/de/hsel/spm/baudas/web/ErrorCode.java
+++ b/src/main/java/de/hsel/spm/baudas/web/ErrorCode.java
@@ -8,6 +8,7 @@ import lombok.Getter;
*
* @author Julian Hinxlage
* @version 0.1
+ * @since 1.0
*/
@Getter
@AllArgsConstructor
diff --git a/src/main/java/de/hsel/spm/baudas/web/LoginServlet.java b/src/main/java/de/hsel/spm/baudas/web/LoginServlet.java
index e6571e0..de96b79 100644
--- a/src/main/java/de/hsel/spm/baudas/web/LoginServlet.java
+++ b/src/main/java/de/hsel/spm/baudas/web/LoginServlet.java
@@ -1,5 +1,7 @@
package de.hsel.spm.baudas.web;
+import org.jetbrains.annotations.NotNull;
+
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
@@ -11,9 +13,11 @@ import java.io.IOException;
import java.io.PrintWriter;
/**
- * Servlet implementation class LoginServlet.
+ * authenticates users.
*
* @author Edgar Schkrob
+ * @version 0.1
+ * @since 1.0
*/
@WebServlet("/login")
@@ -22,25 +26,23 @@ public class LoginServlet extends HttpServlet {
private final String password = "SPM2019SS";
/**
- * This is a Servlet that manages the Login and creates Sessions.
+ * reads from HTTP POST parameter 'password' and compares it.
*
- * @param request This parameter provides access to everything the code needs to work.
- * @param response This parameter provides access to everything the code needs to issue a response.
- * @throws ServletException Defines a general exception a servlet can throw when it encounters difficulty.
- * @throws IOException Signals that an I/O exception of some sort has occurred. This class is the general class of exceptions produced by failed or interrupted I/O operations.
+ * @param request request object
+ * @param response response object
+ * @throws IOException failed to initialize print writer
*/
-
- protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ protected void doPost(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response) throws ServletException, IOException {
String password = request.getParameter("password");
if (this.password.equals(password)) {
HttpSession newSession = request.getSession(true);
newSession.setAttribute("authentication", true);
newSession.setMaxInactiveInterval(5 * 60 * 60); //setting session to expiry in 5 hours
- response.sendRedirect("index.jsp");
+ response.sendRedirect("/");
} else {
- RequestDispatcher rd = getServletContext().getRequestDispatcher("/login.html");
+ RequestDispatcher rd = getServletContext().getRequestDispatcher("/login.jsp");
PrintWriter out = response.getWriter();
- out.println("Das eingegebene Passwort ist falsch. ");
+ out.println("Das eingegebene Passwort ist falsch. ");
rd.include(request, response);
}
}
diff --git a/src/main/java/de/hsel/spm/baudas/web/LogoutServlet.java b/src/main/java/de/hsel/spm/baudas/web/LogoutServlet.java
index cf04180..302c2ca 100644
--- a/src/main/java/de/hsel/spm/baudas/web/LogoutServlet.java
+++ b/src/main/java/de/hsel/spm/baudas/web/LogoutServlet.java
@@ -1,5 +1,7 @@
package de.hsel.spm.baudas.web;
+import org.jetbrains.annotations.NotNull;
+
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
@@ -8,26 +10,27 @@ import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
- * Servlet implementation class LogoutServlet.
+ * logs out user if they request this.
*
* @author Edgar Schkrob
+ * @version 0.1
+ * @since 1.0
*/
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
/**
- * This is a Servlet that manages the Logout and deletes Sessions.
+ * if this servlet is request logout the user.
*
- * @param request This parameter provides access to everything the code needs to work.
- * @param response This parameter provides access to everything the code needs to issue a response.
- * @throws IOException Signals that an I/O exception of some sort has occurred. This class is the general class of exceptions produced by failed or interrupted I/O operations.
+ * @param request request object
+ * @param response response object
+ * @throws IOException failed to initialize print writer
*/
-
- protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ protected void doGet(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response) throws IOException {
HttpSession session = request.getSession();
if (session != null) {
- Data.delete(session.getId());
+ DatasetManagement.delete(session.getId());
session.invalidate();
}
response.sendRedirect(request.getContextPath() + "/");
diff --git a/src/main/java/de/hsel/spm/baudas/web/SavedFile.java b/src/main/java/de/hsel/spm/baudas/web/SavedFile.java
index c0ae3fa..4380a56 100644
--- a/src/main/java/de/hsel/spm/baudas/web/SavedFile.java
+++ b/src/main/java/de/hsel/spm/baudas/web/SavedFile.java
@@ -12,7 +12,7 @@ import java.util.UUID;
*
* @author Johannes Theiner
* @version 0.1
- * @since 0.1
+ * @since 1.0
*/
@Getter
@AllArgsConstructor
diff --git a/src/main/java/de/hsel/spm/baudas/web/ShoppingCartDiagram.java b/src/main/java/de/hsel/spm/baudas/web/ShoppingCartDiagram.java
deleted file mode 100644
index c2413f6..0000000
--- a/src/main/java/de/hsel/spm/baudas/web/ShoppingCartDiagram.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package de.hsel.spm.baudas.web;
-
-import com.google.gson.Gson;
-import de.hsel.spm.baudas.analysis.ShoppingCart;
-import org.jetbrains.annotations.NotNull;
-
-import javax.servlet.annotation.WebServlet;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.File;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
-import java.util.*;
-
-/**
- * Changes data to readable format for table
- *
- * @author Karsten Eden
- * @version 0.1
- * @since 0.1
- */
-@WebServlet("/shopping_cart")
-public class ShoppingCartDiagram extends HttpServlet {
-
- private static final long serialVersionUID = 5026732432605473505L;
-
- private static List> cache;
-
- protected void doGet(@NotNull HttpServletRequest req, @NotNull HttpServletResponse resp) throws IOException {
- req.setCharacterEncoding(StandardCharsets.UTF_8.name());
- resp.setCharacterEncoding(StandardCharsets.UTF_8.name());
- resp.setContentType("application/json");
- PrintWriter out = resp.getWriter();
- Gson gson = new Gson();
-
- if(cache != null) {
- out.println(gson.toJson(cache));
- return;
- }
-
- List> result = new ArrayList<>();
-
- if (req.getParameter("id") == null) {
- out.print(gson.toJson(result));
- return;
- }
-
- UUID uuid = UUID.fromString(req.getParameter("id"));
- File file = Data.get(uuid);
-
- ShoppingCart cart = new ShoppingCart(file);
- Map, List> map = cart.getResult();
-
- List col1 = new ArrayList<>();
- List col2 = new ArrayList<>();
-
- for(Map.Entry, List> entry : map.entrySet()){
- col1.add(String.join(", ", entry.getKey()));
- col2.add(String.join(", ", entry.getValue()));
- }
-
- for(int i = 0; i < col1.size(); i++ ){
- result.add(new AbstractMap.SimpleEntry<>(col1.get(i), col2.get(i)));
- }
-
- out.print(gson.toJson(result));
- }
-}
diff --git a/src/main/java/de/hsel/spm/baudas/web/Upload.java b/src/main/java/de/hsel/spm/baudas/web/UploadServlet.java
similarity index 89%
rename from src/main/java/de/hsel/spm/baudas/web/Upload.java
rename to src/main/java/de/hsel/spm/baudas/web/UploadServlet.java
index 6383e98..9616b2c 100644
--- a/src/main/java/de/hsel/spm/baudas/web/Upload.java
+++ b/src/main/java/de/hsel/spm/baudas/web/UploadServlet.java
@@ -28,7 +28,7 @@ import java.nio.file.StandardCopyOption;
@WebServlet("/upload")
@MultipartConfig
-public class Upload extends HttpServlet {
+public class UploadServlet extends HttpServlet {
private static final long serialVersionUID = 14144111845151L;
@@ -48,6 +48,13 @@ public class Upload extends HttpServlet {
}
}
+ /**
+ * validates file and saves it.
+ *
+ * @param req request object
+ * @param resp response object
+ * @throws IOException failed to initialize print writer
+ */
@Override
protected void doPost(@NotNull HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding(StandardCharsets.UTF_8.name());
@@ -89,7 +96,7 @@ public class Upload extends HttpServlet {
inputStream = filePart.getInputStream();
}
- Path path = Data.add(fileName, req.getSession().getId());
+ Path path = DatasetManagement.add(fileName, req.getSession().getId());
if (!Files.exists(path)) {
Files.createFile(path);
}
diff --git a/src/main/java/de/hsel/spm/baudas/web/ClusterDiagram.java b/src/main/java/de/hsel/spm/baudas/web/depiction/ClusterTable.java
similarity index 52%
rename from src/main/java/de/hsel/spm/baudas/web/ClusterDiagram.java
rename to src/main/java/de/hsel/spm/baudas/web/depiction/ClusterTable.java
index a4ba39a..aa3afb5 100644
--- a/src/main/java/de/hsel/spm/baudas/web/ClusterDiagram.java
+++ b/src/main/java/de/hsel/spm/baudas/web/depiction/ClusterTable.java
@@ -1,7 +1,8 @@
-package de.hsel.spm.baudas.web;
+package de.hsel.spm.baudas.web.depiction;
import com.google.gson.Gson;
import de.hsel.spm.baudas.analysis.Cluster;
+import de.hsel.spm.baudas.web.DatasetManagement;
import org.jetbrains.annotations.NotNull;
import javax.servlet.annotation.WebServlet;
@@ -11,45 +12,45 @@ import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
-import java.util.*;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
/**
- * changes data from cluster analysis into a readable format
+ * changes data from cluster analysis into a readable format.
*
* @author Julian Hinxlage
* @version 0.1
- * @since 0.1
+ * @since 1.0
**/
@WebServlet("/clusters")
-public class ClusterDiagram extends HttpServlet {
+public class ClusterTable extends HttpServlet implements Depiction {
- private static Map> cache;
+ private static Map cache;
+ /**
+ * returns formatted analysis result to HTTP GET request from supplied id.
+ *
+ * @param req request object
+ * @param resp response object
+ * @throws IOException failed to initialize print writer
+ */
@Override
protected void doGet(@NotNull HttpServletRequest req, @NotNull HttpServletResponse resp) throws IOException {
- req.setCharacterEncoding(StandardCharsets.UTF_8.name());
- resp.setCharacterEncoding(StandardCharsets.UTF_8.name());
- resp.setContentType("application/json");
- PrintWriter out = resp.getWriter();
- Gson gson = new Gson();
+ UUID uuid = setup(req, resp, cache);
+ if (uuid == null) return;
- if(cache != null) {
- out.println(gson.toJson(cache));
- return;
- }
Map> result = new HashMap<>();
-
- if (req.getParameter("id") == null) {
- out.print(gson.toJson(result));
- return;
- }
- UUID uuid = UUID.fromString(req.getParameter("id"));
- File file = Data.get(uuid);
+ File file = DatasetManagement.get(uuid);
Cluster cluster = new Cluster(file);
result = cluster.getResult();
+
+ PrintWriter out = resp.getWriter();
+ Gson gson = new Gson();
+
+ cache.put(uuid, result);
out.print(gson.toJson(result));
}
}
diff --git a/src/main/java/de/hsel/spm/baudas/web/depiction/Depiction.java b/src/main/java/de/hsel/spm/baudas/web/depiction/Depiction.java
new file mode 100644
index 0000000..edca3ce
--- /dev/null
+++ b/src/main/java/de/hsel/spm/baudas/web/depiction/Depiction.java
@@ -0,0 +1,73 @@
+package de.hsel.spm.baudas.web.depiction;
+
+import com.google.gson.Gson;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+import java.util.UUID;
+import java.util.regex.Pattern;
+
+/**
+ * handle all common methods for depictions.
+ *
+ * @author Johannes Theiner
+ * @version 0.1
+ * @since 1.0
+ **/
+interface Depiction {
+
+ /**
+ * set all default values and handle caching.
+ *
+ * @param request request object
+ * @param response response object
+ * @param cache cached results
+ * @return validated uuid
+ */
+ @Nullable
+ default UUID setup(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Map cache) {
+ try {
+ request.setCharacterEncoding(StandardCharsets.UTF_8.name());
+ response.setCharacterEncoding(StandardCharsets.UTF_8.name());
+ response.setContentType("application/json");
+ PrintWriter out = response.getWriter();
+
+
+ Gson gson = new Gson();
+
+ UUID uuid = validateAndConvert(request.getParameter("id"));
+ if (uuid == null) return null;
+
+ if (cache.containsKey(uuid)) {
+ out.println(gson.toJson(cache.get(uuid)));
+ return null;
+ }
+ return uuid;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * validates and converts uuid.
+ *
+ * @param id potential uuid
+ * @return UUID object
+ */
+ @Nullable
+ default UUID validateAndConvert(String id) {
+ boolean match = Pattern.matches("[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}", id);
+ if (id == null || !match) {
+ return null;
+ }
+
+ return UUID.fromString(id);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/de/hsel/spm/baudas/web/TopFlopArticleDiagram.java b/src/main/java/de/hsel/spm/baudas/web/depiction/SalesNumberChart.java
similarity index 60%
rename from src/main/java/de/hsel/spm/baudas/web/TopFlopArticleDiagram.java
rename to src/main/java/de/hsel/spm/baudas/web/depiction/SalesNumberChart.java
index 85a36f3..24eba0e 100644
--- a/src/main/java/de/hsel/spm/baudas/web/TopFlopArticleDiagram.java
+++ b/src/main/java/de/hsel/spm/baudas/web/depiction/SalesNumberChart.java
@@ -1,7 +1,8 @@
-package de.hsel.spm.baudas.web;
+package de.hsel.spm.baudas.web.depiction;
import com.google.gson.Gson;
-import de.hsel.spm.baudas.analysis.TopFlopArticle;
+import de.hsel.spm.baudas.analysis.SalesNumbers;
+import de.hsel.spm.baudas.web.DatasetManagement;
import org.jetbrains.annotations.NotNull;
import javax.servlet.annotation.WebServlet;
@@ -11,13 +12,11 @@ import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
-import java.util.regex.Pattern;
/**
* top/flop articles list diagram.
@@ -27,38 +26,28 @@ import java.util.regex.Pattern;
* @since 0.1
**/
-@WebServlet("/top_flop")
-public class TopFlopArticleDiagram extends HttpServlet {
+@WebServlet("/sales")
+public class SalesNumberChart extends HttpServlet implements Depiction {
private static Map cache = new HashMap<>();
private static final long serialVersionUID = 6567531464214L;
+ /**
+ * returns formatted analysis result to HTTP GET request from supplied id.
+ *
+ * @param req request object
+ * @param resp response object
+ * @throws IOException failed to initialize print writer
+ */
@Override
protected void doGet(@NotNull HttpServletRequest req, @NotNull HttpServletResponse resp) throws IOException {
- req.setCharacterEncoding(StandardCharsets.UTF_8.name());
- resp.setCharacterEncoding(StandardCharsets.UTF_8.name());
- resp.setContentType("application/json");
- PrintWriter out = resp.getWriter();
+ UUID uuid = setup(req, resp, cache);
+ if (uuid == null) return;
- Gson gson = new Gson();
+ File file = DatasetManagement.get(uuid);
- String id = req.getParameter("id");
- boolean match = Pattern.matches("[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}", id);
- if (id == null || !match) {
- return;
- }
-
- UUID uuid = UUID.fromString(id);
-
- if (cache.containsKey(uuid)) {
- out.println(gson.toJson(cache.get(uuid)));
- return;
- }
-
- File file = Data.get(uuid);
-
- TopFlopArticle articles = new TopFlopArticle(file);
+ SalesNumbers articles = new SalesNumbers(file);
Map map = articles.getResult();
Map> result = new HashMap<>();
@@ -74,6 +63,8 @@ public class TopFlopArticleDiagram extends HttpServlet {
result.put("labels", labels);
result.put("data", data);
+ PrintWriter out = resp.getWriter();
+ Gson gson = new Gson();
cache.put(uuid, result);
out.print(gson.toJson(result));
diff --git a/src/main/java/de/hsel/spm/baudas/web/depiction/ShoppingCartTable.java b/src/main/java/de/hsel/spm/baudas/web/depiction/ShoppingCartTable.java
new file mode 100644
index 0000000..311df27
--- /dev/null
+++ b/src/main/java/de/hsel/spm/baudas/web/depiction/ShoppingCartTable.java
@@ -0,0 +1,80 @@
+package de.hsel.spm.baudas.web.depiction;
+
+import com.google.gson.Gson;
+import de.hsel.spm.baudas.analysis.ShoppingCart;
+import de.hsel.spm.baudas.web.DatasetManagement;
+import org.jetbrains.annotations.NotNull;
+
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * Changes data to readable format for table.
+ *
+ * @author Karsten Eden
+ * @version 0.1
+ * @since 0.1
+ */
+@WebServlet("/shopping_cart")
+public class ShoppingCartTable extends HttpServlet implements Depiction {
+
+ private static final long serialVersionUID = 5026732432605473505L;
+
+ private static Map cache;
+
+ /**
+ * returns formatted analysis result to HTTP GET request from supplied id.
+ *
+ * @param req request object
+ * @param resp response object
+ * @throws IOException failed to initialize print writer
+ */
+ protected void doGet(@NotNull HttpServletRequest req, @NotNull HttpServletResponse resp) throws IOException {
+ UUID uuid = setup(req, resp, cache);
+ if (uuid == null) return;
+
+
+ List> tmp = new ArrayList<>();
+
+ File file = DatasetManagement.get(uuid);
+
+ ShoppingCart cart = new ShoppingCart(file);
+ Map, List> map = cart.getResult();
+
+ List premises = new ArrayList<>();
+ List consequences = new ArrayList<>();
+
+ for (Map.Entry, List> entry : map.entrySet()) {
+ premises.add(String.join(", ", entry.getKey()));
+ consequences.add(String.join(", ", entry.getValue()));
+ }
+
+ for (int i = 0; i < premises.size(); i++) {
+ tmp.add(new AbstractMap.SimpleEntry<>(premises.get(i), consequences.get(i)));
+ }
+ Map> result = new HashMap<>();
+ int i = 0;
+ for (Map.Entry entry : tmp) {
+ result.put(i, entry);
+ i++;
+ }
+
+ cache.put(uuid, result);
+
+ PrintWriter out = resp.getWriter();
+ Gson gson = new Gson();
+
+ out.print(gson.toJson(result));
+ }
+}
diff --git a/src/main/java/de/hsel/spm/baudas/web/ShoppingTimesDiagram.java b/src/main/java/de/hsel/spm/baudas/web/depiction/ShoppingTimesChart.java
similarity index 69%
rename from src/main/java/de/hsel/spm/baudas/web/ShoppingTimesDiagram.java
rename to src/main/java/de/hsel/spm/baudas/web/depiction/ShoppingTimesChart.java
index bbe011d..615bf57 100644
--- a/src/main/java/de/hsel/spm/baudas/web/ShoppingTimesDiagram.java
+++ b/src/main/java/de/hsel/spm/baudas/web/depiction/ShoppingTimesChart.java
@@ -1,7 +1,8 @@
-package de.hsel.spm.baudas.web;
+package de.hsel.spm.baudas.web.depiction;
import com.google.gson.Gson;
import de.hsel.spm.baudas.analysis.ShoppingTimes;
+import de.hsel.spm.baudas.web.DatasetManagement;
import org.jetbrains.annotations.NotNull;
import javax.servlet.annotation.WebServlet;
@@ -11,54 +12,51 @@ import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
-import java.util.*;
-import java.util.regex.Pattern;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.UUID;
/**
* changes data from shopping times diagram into a readable format for chart.js
*
* @author Johannes Theiner
* @version 0.1
- * @since 0.1
+ * @since 1.0
**/
@WebServlet("/shopping_times")
-public class ShoppingTimesDiagram extends HttpServlet {
+public class ShoppingTimesChart extends HttpServlet implements Depiction {
private static Map cache = new HashMap<>();
private static final long serialVersionUID = 6567531484L;
+ /**
+ * returns formatted analysis result to HTTP GET request from supplied id.
+ *
+ * @param req request object
+ * @param resp response object
+ * @throws IOException failed to initialize print writer
+ */
@Override
protected void doGet(@NotNull HttpServletRequest req, @NotNull HttpServletResponse resp) throws IOException {
- req.setCharacterEncoding(StandardCharsets.UTF_8.name());
- resp.setCharacterEncoding(StandardCharsets.UTF_8.name());
- resp.setContentType("application/json");
- PrintWriter out = resp.getWriter();
+ UUID uuid = setup(req, resp, cache);
+ if (uuid == null) return;
+
List definedOrder = Arrays.asList("<10 Uhr", "10-12 Uhr", "12-14 Uhr", "14-17 Uhr", ">17 Uhr");
Comparator comparator = Comparator.comparingInt(definedOrder::indexOf);
Map> result = new HashMap<>();
- Gson gson = new Gson();
-
- String id = req.getParameter("id");
- boolean match = Pattern.matches("[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}", id);
- if (id == null || !match) {
- return;
- }
-
- UUID uuid = UUID.fromString(id);
-
-
- if (cache.containsKey(uuid)) {
- out.print(gson.toJson(cache.get(uuid)));
- return;
- }
-
-
- File file = Data.get(uuid);
+ File file = DatasetManagement.get(uuid);
ShoppingTimes shoppingTimes = new ShoppingTimes(file);
Map, Integer> map = shoppingTimes.getResult();
@@ -73,14 +71,17 @@ public class ShoppingTimesDiagram extends HttpServlet {
for (String day : days) {
- if (!result.containsKey(day))
+ if (!result.containsKey(day)) {
result.put(day, new ArrayList<>());
+ }
for (String hour : hours) {
if (map.containsKey(new AbstractMap.SimpleEntry<>(day, hour))) {
result.get(day).add(map.get(new AbstractMap.SimpleEntry<>(day, hour)).toString());
} else result.get(day).add("0");
}
}
+ PrintWriter out = resp.getWriter();
+ Gson gson = new Gson();
cache.put(uuid, result);
out.print(gson.toJson(result));
diff --git a/src/main/java/de/hsel/spm/baudas/web/WeekOverviewDiagram.java b/src/main/java/de/hsel/spm/baudas/web/depiction/WeekOverviewChart.java
similarity index 71%
rename from src/main/java/de/hsel/spm/baudas/web/WeekOverviewDiagram.java
rename to src/main/java/de/hsel/spm/baudas/web/depiction/WeekOverviewChart.java
index 6f8534f..d9d0cb0 100644
--- a/src/main/java/de/hsel/spm/baudas/web/WeekOverviewDiagram.java
+++ b/src/main/java/de/hsel/spm/baudas/web/depiction/WeekOverviewChart.java
@@ -1,7 +1,8 @@
-package de.hsel.spm.baudas.web;
+package de.hsel.spm.baudas.web.depiction;
import com.google.gson.Gson;
import de.hsel.spm.baudas.analysis.WeekOverview;
+import de.hsel.spm.baudas.web.DatasetManagement;
import org.jetbrains.annotations.NotNull;
import javax.servlet.annotation.WebServlet;
@@ -11,7 +12,6 @@ import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
@@ -19,50 +19,39 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
-import java.util.regex.Pattern;
/**
* changes data from week overview into readable format for chart.js
*
* @author Johannes Theiner
* @version 0.1
- * @since 0.1
+ * @since 1.0
**/
@WebServlet("/week_overview")
-public class WeekOverviewDiagram extends HttpServlet {
+public class WeekOverviewChart extends HttpServlet implements Depiction {
private static Map cache = new HashMap<>();
private static final long serialVersionUID = 8484151844118L;
+ /**
+ * returns formatted analysis result to HTTP GET request from supplied id.
+ *
+ * @param req request object
+ * @param resp response object
+ * @throws IOException failed to initialize print writer
+ */
@Override
protected void doGet(@NotNull HttpServletRequest req, @NotNull HttpServletResponse resp) throws IOException {
- req.setCharacterEncoding(StandardCharsets.UTF_8.name());
- resp.setCharacterEncoding(StandardCharsets.UTF_8.name());
- resp.setContentType("application/json");
- PrintWriter out = resp.getWriter();
+ UUID uuid = setup(req, resp, cache);
+
+ if (uuid == null) return;
List definedOrder = Arrays.asList("Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag");
Map> result = new HashMap<>();
- Gson gson = new Gson();
-
- String id = req.getParameter("id");
- boolean match = Pattern.matches("[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}", id);
-
-
- if (id == null || !match) {
- return;
- }
-
- UUID uuid = UUID.fromString(id);
- if(cache.containsKey(uuid)) {
- out.println(gson.toJson(cache.get(uuid)));
- return;
- }
-
- File file = Data.get(uuid);
+ File file = DatasetManagement.get(uuid);
WeekOverview overview = new WeekOverview(file);
@@ -86,6 +75,9 @@ public class WeekOverviewDiagram extends HttpServlet {
result.put("count", count);
result.put("revenue", revenue);
+ PrintWriter out = resp.getWriter();
+ Gson gson = new Gson();
+
cache.put(uuid, result);
out.print(gson.toJson(result));
}
diff --git a/src/main/resources/LogoBauDas2.gif b/src/main/resources/LogoBauDas2.gif
deleted file mode 100644
index 2fbc6e1a21e54000b2d456c312bf548152ea7d4d..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 32328
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
WxOc^QrSb5}mAsXvycIS8*!&M6(m0#|
diff --git a/src/main/webapp/analysis.jsp b/src/main/webapp/analysis.jsp
new file mode 100644
index 0000000..db38a5d
--- /dev/null
+++ b/src/main/webapp/analysis.jsp
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+ Wochenübersicht
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Gruppenübersicht
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/webapp/footer.jsp b/src/main/webapp/footer.jsp
index 1e71394..e597888 100644
--- a/src/main/webapp/footer.jsp
+++ b/src/main/webapp/footer.jsp
@@ -1,19 +1,11 @@
-
-
-
-
-<%@include file="theming.jsp"%>
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/webapp/head.jsp b/src/main/webapp/head.jsp
index 3d556dd..b9079f1 100644
--- a/src/main/webapp/head.jsp
+++ b/src/main/webapp/head.jsp
@@ -1,3 +1,4 @@
+<%@ page import="java.nio.charset.StandardCharsets" %>
<% response.setCharacterEncoding(StandardCharsets.UTF_8.name()); %>
<% request.setCharacterEncoding(StandardCharsets.UTF_8.name()); %>
diff --git a/src/main/webapp/index.jsp b/src/main/webapp/index.jsp
index 739394e..28e2390 100644
--- a/src/main/webapp/index.jsp
+++ b/src/main/webapp/index.jsp
@@ -1,198 +1,10 @@
<%@ page import="java.nio.charset.StandardCharsets" %>
-<%@ page contentType="text/html;charset=UTF-8" %>
-<%@include file="menu.jsp" %>
<% response.setCharacterEncoding(StandardCharsets.UTF_8.name()); %>
<% request.setCharacterEncoding(StandardCharsets.UTF_8.name()); %>
+<%@ page contentType="text/html;charset=UTF-8" %>
+<%@include file="menu.jsp" %>
-
-
-
-
-
-<%@include file="footer.jsp" %>
\ No newline at end of file
+<%@include file="theming.jsp" %>
\ No newline at end of file
diff --git a/src/main/webapp/js/cache.js b/src/main/webapp/js/cache.js
index 5768c22..e474c4b 100644
--- a/src/main/webapp/js/cache.js
+++ b/src/main/webapp/js/cache.js
@@ -32,7 +32,7 @@ function clearSelected(){
function updateDatasets() {
let dataset = $('#dataset');
- request('files').then(results => {
+ request('datasets').then(results => {
dataset.empty();
for (const result of results) {
dataset.append($(" ")
@@ -56,7 +56,7 @@ function updateCache() {
} else {
//requesting files, getting values from html does not work...
//if no selection is provided, select newest file
- request('files').then(results => {
+ request('datasets').then(results => {
let uuid = results[results.length - 1].uuid;
dataset.val(uuid);
updateAll(uuid);
@@ -69,7 +69,7 @@ function updateAll(uuid) {
updateWeekOverviewChart(uuid);
updateShoppingTimesChart(uuid);
updateTopFlopChart(uuid);
- updateClusters(uuid)
+ updateClusters(uuid);
updateShoppingCartTable(uuid);
//add new charts here.
}
diff --git a/src/main/webapp/js/top_flop.js b/src/main/webapp/js/sales.js
similarity index 72%
rename from src/main/webapp/js/top_flop.js
rename to src/main/webapp/js/sales.js
index 74b51e1..995a428 100644
--- a/src/main/webapp/js/top_flop.js
+++ b/src/main/webapp/js/sales.js
@@ -1,7 +1,7 @@
let top_flop_result;
-let top_flop = new Chart($("#top_flop_chart"), {
+let sales = new Chart($("#sales_chart"), {
type: 'horizontalBar',
data: {
labels: [],
@@ -34,23 +34,23 @@ let top_flop = new Chart($("#top_flop_chart"), {
function updateTopFlopChart(id) {
if (typeof id !== 'undefined') {
- request('top_flop', id).then(function (data) {
+ request('sales', id).then(function (data) {
top_flop_result = data;
updateTopFlop();
});
- } else request('top_flop').then(function (data) {
+ } else request('sales').then(function (data) {
top_flop_result = data;
updateTopFlop();
});
}
function updateTopFlop() {
- top_flop.data.labels = top_flop_result.labels;
- top_flop.data.datasets[0].data = top_flop_result.data;
+ sales.data.labels = top_flop_result.labels;
+ sales.data.datasets[0].data = top_flop_result.data;
let seq = palette('mpn65', 15);
for (let i = 0; i < 15; i++) {
- top_flop.data.datasets[0].backgroundColor[i] = "#" + seq[i];
+ sales.data.datasets[0].backgroundColor[i] = "#" + seq[i];
}
- top_flop.update();
+ sales.update();
}
diff --git a/src/main/webapp/login.html b/src/main/webapp/login.html
deleted file mode 100644
index cf45487..0000000
--- a/src/main/webapp/login.html
+++ /dev/null
@@ -1,47 +0,0 @@
-
-
-