From 43487093c641385e924f9e32e9b5e014cc82f318 Mon Sep 17 00:00:00 2001 From: Brian-Weloba Date: Tue, 1 Apr 2025 14:18:30 +0100 Subject: [PATCH 1/3] Implement event creation form validation; enhance user input handling with error messages; add prediction functionality for event type; create prediction page for displaying results --- emmas/pom.xml | 7 +- .../java/dev/brianweloba/model/Event.java | 10 ++ .../dev/brianweloba/servlet/CreateEvent.java | 56 ++++--- .../servlet/PredictionServlet.java | 111 +++++++++---- .../java/dev/brianweloba/util/DateUtils.java | 21 +++ .../brianweloba/weka/EventTypeClassifier.java | 2 +- .../main/webapp/WEB-INF/components/footer.jsp | 6 +- .../src/main/webapp/WEB-INF/views/create.jsp | 147 ++++++++++++++---- emmas/src/main/webapp/WEB-INF/views/index.jsp | 2 +- .../main/webapp/WEB-INF/views/prediction.jsp | 101 ++++++++++++ emmas/src/main/webapp/css/styles.css | 108 +++++++++++++ 11 files changed, 487 insertions(+), 84 deletions(-) create mode 100644 emmas/src/main/java/dev/brianweloba/util/DateUtils.java create mode 100644 emmas/src/main/webapp/WEB-INF/views/prediction.jsp diff --git a/emmas/pom.xml b/emmas/pom.xml index e7d115c..81ea17b 100644 --- a/emmas/pom.xml +++ b/emmas/pom.xml @@ -33,7 +33,6 @@ - org.projectlombok lombok @@ -45,7 +44,6 @@ mysql-connector-j 9.2.0 - jakarta.servlet jakarta.servlet-api @@ -55,6 +53,11 @@ org.hibernate.orm hibernate-core + + org.hibernate.validator + hibernate-validator + 8.0.0.Final + jakarta.transaction jakarta.transaction-api diff --git a/emmas/src/main/java/dev/brianweloba/model/Event.java b/emmas/src/main/java/dev/brianweloba/model/Event.java index 8b86a84..8915a35 100644 --- a/emmas/src/main/java/dev/brianweloba/model/Event.java +++ b/emmas/src/main/java/dev/brianweloba/model/Event.java @@ -1,6 +1,7 @@ package dev.brianweloba.model; import jakarta.persistence.*; +import jakarta.validation.constraints.*; import lombok.Data; import java.util.Date; @@ -15,21 +16,29 @@ public class Event { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @NotBlank(message = "Event title is required") + @Size(min = 3, max = 100, message = "Title must be between 3 and 100 characters") @Column(nullable = false) private String title; @Column(name = "event_type") private String eventType; + @NotBlank(message = "Host name is required") @Column(name = "event_host") private String eventHost; + @NotBlank(message = "Event location is required") @Column(name = "event_location") private String eventLocation; + @NotBlank(message = "Event description is required") + @Size(min = 10,max = 255, message = "Description be between 10 and 255 characters") @Column(columnDefinition = "TEXT") private String description; + @NotNull(message = "Event date is required") + @Future(message = "Event date must be in the future") @Column(name = "event_date") private Date eventDate; @@ -39,6 +48,7 @@ public class Event { @Column(name = "updated_at", insertable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP") private Date updatedAt; + @Min(value = 1, message = "Event capacity must be at least 1") @Column(name = "event_capacity") private int eventCapacity; diff --git a/emmas/src/main/java/dev/brianweloba/servlet/CreateEvent.java b/emmas/src/main/java/dev/brianweloba/servlet/CreateEvent.java index 6ca196e..457f400 100644 --- a/emmas/src/main/java/dev/brianweloba/servlet/CreateEvent.java +++ b/emmas/src/main/java/dev/brianweloba/servlet/CreateEvent.java @@ -4,15 +4,14 @@ import dev.brianweloba.model.Event; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; -import jakarta.servlet.http.Cookie; -import jakarta.servlet.http.HttpServlet; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.*; import java.io.IOException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; @WebServlet("/events/create") public class CreateEvent extends HttpServlet { @@ -27,26 +26,41 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { - Event event = new Event(); - - event.setTitle(request.getParameter("title")); - event.setEventHost(request.getParameter("eventHost")); - event.setDescription(request.getParameter("description")); - event.setEventType(request.getParameter("eventType")); - event.setEventLocation(request.getParameter("location")); - event.setEventCapacity(Integer.parseInt(request.getParameter("eventCapacity"))); - - String dateString = request.getParameter("eventDate"); - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); - try { - Date eventDate = dateFormat.parse(dateString); - event.setEventDate(eventDate); - } catch (ParseException e) { - throw new RuntimeException(e); + HttpSession session = request.getSession(); + Event event = (Event) session.getAttribute("event"); + + if (event == null) { + response.sendRedirect(request.getContextPath() + "/events/create"); + return; } +// event.setTitle(request.getParameter("title")); +// event.setEventHost(request.getParameter("eventHost")); +// event.setDescription(request.getParameter("description")); + event.setEventType(request.getParameter("eventType").toUpperCase()); +// event.setEventLocation(request.getParameter("location")); +// String capacityStr = request.getParameter("eventCapacity"); +// int capacity = 0; +// try { +// capacity = Integer.parseInt(capacityStr); +// event.setEventCapacity(capacity); +// } catch (NumberFormatException e) { +// request.setAttribute("capacityError", "Invalid capacity value"); +// } +// +// String dateString = request.getParameter("eventDate"); +// System.out.println("EventDate " + dateString); +// SimpleDateFormat formatter = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.ENGLISH); +// formatter.setTimeZone(TimeZone.getTimeZone("GMT")); +// try { +// Date eventDate = formatter.parse(dateString); +// event.setEventDate(eventDate); +// } catch (ParseException e) { +// throw new RuntimeException(e); +// } event = eventDAO.create(event); + session.removeAttribute("event"); - Cookie tokenCookie = new Cookie("event_"+event.getId()+"_token", event.getEditToken()); + Cookie tokenCookie = new Cookie("event_" + event.getId() + "_token", event.getEditToken()); tokenCookie.setMaxAge(60 * 60 * 24 * 365); tokenCookie.setPath("/"); response.addCookie(tokenCookie); diff --git a/emmas/src/main/java/dev/brianweloba/servlet/PredictionServlet.java b/emmas/src/main/java/dev/brianweloba/servlet/PredictionServlet.java index a866920..263fc89 100644 --- a/emmas/src/main/java/dev/brianweloba/servlet/PredictionServlet.java +++ b/emmas/src/main/java/dev/brianweloba/servlet/PredictionServlet.java @@ -8,12 +8,18 @@ import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import jakarta.validation.ValidatorFactory; import java.io.IOException; +import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.Iterator; +import java.util.Date; import java.util.List; import java.util.Map; +import java.util.Set; @WebServlet("/events/predict-type") public class PredictionServlet extends HttpServlet { @@ -45,41 +51,86 @@ protected void doPost( response.setContentType("application/json"); try { - // Create temporary event with form data - Event tempEvent = new Event(); - tempEvent.setTitle(request.getParameter("title")); - tempEvent.setDescription(request.getParameter("description")); - tempEvent.setEventHost(request.getParameter("hostName")); - tempEvent.setEventLocation(request.getParameter("location")); - tempEvent.setEventCapacity(Integer.parseInt(request.getParameter("eventCapacity"))); - - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); - tempEvent.setEventDate(dateFormat.parse(request.getParameter("eventDate"))); - - // Get prediction and probabilities - String predictedType = classifier.predictEventType(tempEvent); - Map probabilities = classifier.getPredictionProbabilities(tempEvent); - - // Create JSON response - StringBuilder jsonResponse = new StringBuilder(); - jsonResponse.append("{\"success\":true,\"eventType\":\"").append(predictedType).append("\","); - jsonResponse.append("\"probabilities\":{"); - - Iterator> it = probabilities.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry entry = it.next(); - jsonResponse.append("\"").append(entry.getKey()).append("\":") - .append(String.format("%.2f", entry.getValue() * 100)); - if (it.hasNext()) jsonResponse.append(","); + Event event = new Event(); + event.setTitle(request.getParameter("title")); + event.setDescription(request.getParameter("description")); + event.setEventHost(request.getParameter("eventHost")); + event.setEventLocation(request.getParameter("eventLocation")); + + String capacityStr = request.getParameter("eventCapacity"); + int capacity = 0; + try { + capacity = Integer.parseInt(capacityStr); + event.setEventCapacity(capacity); + } catch (NumberFormatException e) { + request.setAttribute("capacityError", "Invalid capacity value"); + } + + String dateStr = request.getParameter("eventDate"); + try { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + Date eventDate = sdf.parse(dateStr); + event.setEventDate(eventDate); + } catch (ParseException e) { + request.setAttribute("dateError", "Invalid date format"); } - jsonResponse.append("}}"); + Set> violations = validate(event); + + if (!violations.isEmpty()) { + for (ConstraintViolation violation : violations) { + String propertyPath = violation.getPropertyPath().toString(); + String message = violation.getMessage(); - response.getWriter().write(jsonResponse.toString()); + switch (propertyPath) { + case "title": + request.setAttribute("titleError", message); + break; + case "eventHost": + request.setAttribute("hostError", message); + break; + case "eventLocation": + request.setAttribute("locationError", message); + break; + case "eventCapacity": + request.setAttribute("capacityError", message); + break; + case "eventDate": + request.setAttribute("dateError", message); + break; + case "description": + request.setAttribute("descriptionError", message); + break; + } + } + + request.setAttribute("event", event); + + request.getRequestDispatcher("/WEB-INF/views/create.jsp").forward(request, response); + return; + } + + String predictedType = classifier.predictEventType(event); + Map probabilities = classifier.getPredictionProbabilities(event); + + request.setAttribute("predictedType", predictedType); + request.setAttribute("probabilities", probabilities); + request.getSession().setAttribute("event",event); + + request.getRequestDispatcher("/WEB-INF/views/prediction.jsp").forward(request, response); } catch (Exception e) { response.getWriter().write(String.format( - "{\"success\":false,\"error\":\"%s\"}", e.getMessage())); + "{\"success\":false,\"error\":\"%s\"}", e)); + } + } + + + private Set> validate(Event event) { + Validator validator; + try (ValidatorFactory factory = Validation.buildDefaultValidatorFactory()) { + validator = factory.getValidator(); } + return validator.validate(event); } } diff --git a/emmas/src/main/java/dev/brianweloba/util/DateUtils.java b/emmas/src/main/java/dev/brianweloba/util/DateUtils.java new file mode 100644 index 0000000..6a65dde --- /dev/null +++ b/emmas/src/main/java/dev/brianweloba/util/DateUtils.java @@ -0,0 +1,21 @@ +package dev.brianweloba.util; + + +import java.util.Calendar; +import java.util.Date; + +public class DateUtils { + public static boolean isFutureDate(Date date) { + if (date == null) { + return false; + } + Calendar today = Calendar.getInstance(); + today.set(Calendar.HOUR_OF_DAY, 0); + today.set(Calendar.MINUTE, 0); + today.set(Calendar.SECOND, 0); + today.set(Calendar.MILLISECOND, 0); + + return date.after(today.getTime()); + } + } + diff --git a/emmas/src/main/java/dev/brianweloba/weka/EventTypeClassifier.java b/emmas/src/main/java/dev/brianweloba/weka/EventTypeClassifier.java index b4ae813..4640ef0 100644 --- a/emmas/src/main/java/dev/brianweloba/weka/EventTypeClassifier.java +++ b/emmas/src/main/java/dev/brianweloba/weka/EventTypeClassifier.java @@ -52,7 +52,7 @@ public void trainModel(List events) { private Instances applyStringToWordVectorFilter(Instances data) throws Exception { StringToWordVector filter = new StringToWordVector(); - filter.setAttributeIndices("1,2,3,4"); + filter.setAttributeIndices("1,2,3,4,5,6"); filter.setWordsToKeep(1000); filter.setLowerCaseTokens(true); filter.setInputFormat(data); diff --git a/emmas/src/main/webapp/WEB-INF/components/footer.jsp b/emmas/src/main/webapp/WEB-INF/components/footer.jsp index a41c8ed..dc20aba 100644 --- a/emmas/src/main/webapp/WEB-INF/components/footer.jsp +++ b/emmas/src/main/webapp/WEB-INF/components/footer.jsp @@ -10,8 +10,8 @@ class="flex items-center gap-2 hover:text-emerald-800 transition-colors"> - - + + welobab@coventry.ac.uk @@ -19,7 +19,7 @@ class="flex items-center gap-2 hover:text-emerald-800 transition-colors"> - + +44 7512006095 diff --git a/emmas/src/main/webapp/WEB-INF/views/create.jsp b/emmas/src/main/webapp/WEB-INF/views/create.jsp index e1b408c..6253659 100644 --- a/emmas/src/main/webapp/WEB-INF/views/create.jsp +++ b/emmas/src/main/webapp/WEB-INF/views/create.jsp @@ -1,64 +1,159 @@ +<%@ taglib prefix="fmt" uri="jakarta.tags.fmt" %> <%@ page contentType="text/html;charset=UTF-8" %> - Add Event + Create Event + <%@ include file="../components/navbar.jsp" %>
-
+
+
+

Create Event

+
- + + + ${requestScope.titleError} +
- + + + ${requestScope.hostError} +
- - + + + + ${requestScope.capacityError} +
- + + + + ${requestScope.dateError} +
-
- - -
-
+
- + + + ${requestScope.locationError} +
-
+ class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline ${not empty requestScope.descriptionError ? 'border-red-500' : ''}">${requestScope.event.description} + + ${requestScope.descriptionError} +
diff --git a/emmas/src/main/webapp/WEB-INF/views/index.jsp b/emmas/src/main/webapp/WEB-INF/views/index.jsp index d7738d0..1a683af 100644 --- a/emmas/src/main/webapp/WEB-INF/views/index.jsp +++ b/emmas/src/main/webapp/WEB-INF/views/index.jsp @@ -1,5 +1,5 @@ <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ page contentType="text/html;charset=UTF-8" %> diff --git a/emmas/src/main/webapp/WEB-INF/views/prediction.jsp b/emmas/src/main/webapp/WEB-INF/views/prediction.jsp new file mode 100644 index 0000000..867abe3 --- /dev/null +++ b/emmas/src/main/webapp/WEB-INF/views/prediction.jsp @@ -0,0 +1,101 @@ +<%@ page contentType="text/html;charset=UTF-8" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> + + + Predict Event Type + + + +<%@ include file="../components/navbar.jsp" %> +
+
+
+

Create Event

+
+
+

Event Details

+
+
+

Event Title:

+

Host Name:

+

Event Date:

+
+
+

Capacity: people

+

Location:

+
+
+
+

Description:

+

+
+
+ +
+

Recommended Event Type

+ +
+
+

AI suggests:

+ + AI Powered + +
+
+ + +
+ + +

You can modify the suggested type if needed

+
+ +
+ + +
+ +
+ +
+

Confidence Scores

+
+ + + + + + + + + + + + + + + +
Event TypeConfidence
${entry.key} +
+
+
+
+ ${Math.round(entry.value * 100)}% +
+
+
+
+
+
+<%@ include file="../components/footer.jsp" %> + + \ No newline at end of file diff --git a/emmas/src/main/webapp/css/styles.css b/emmas/src/main/webapp/css/styles.css index ae4da43..c272896 100644 --- a/emmas/src/main/webapp/css/styles.css +++ b/emmas/src/main/webapp/css/styles.css @@ -560,9 +560,15 @@ .mx-auto { margin-inline: auto; } + .my-8 { + margin-block: calc(var(--spacing) * 8); + } .my-auto { margin-block: auto; } + .mt-2 { + margin-top: calc(var(--spacing) * 2); + } .mt-4 { margin-top: calc(var(--spacing) * 4); } @@ -608,6 +614,9 @@ .table { display: table; } + .h-2\.5 { + height: calc(var(--spacing) * 2.5); + } .h-4 { height: calc(var(--spacing) * 4); } @@ -706,11 +715,28 @@ margin-block-end: calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse))); } } + .divide-y { + :where(& > :not(:last-child)) { + --tw-divide-y-reverse: 0; + border-bottom-style: var(--tw-border-style); + border-top-style: var(--tw-border-style); + border-top-width: calc(1px * var(--tw-divide-y-reverse)); + border-bottom-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); + } + } + .divide-gray-200 { + :where(& > :not(:last-child)) { + border-color: var(--color-gray-200); + } + } .truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } + .overflow-hidden { + overflow: hidden; + } .rounded { border-radius: 0.25rem; } @@ -757,18 +783,33 @@ .border-cyan-900\/20 { border-color: color-mix(in oklab, var(--color-cyan-900) 20%, transparent); } + .border-emerald-400 { + border-color: var(--color-emerald-400); + } .border-gray-300 { border-color: var(--color-gray-300); } + .border-red-500 { + border-color: var(--color-red-500); + } .bg-amber-200 { background-color: var(--color-amber-200); } .bg-black\/50 { background-color: color-mix(in oklab, var(--color-black) 50%, transparent); } + .bg-blue-50 { + background-color: var(--color-blue-50); + } + .bg-blue-200 { + background-color: var(--color-blue-200); + } .bg-blue-500 { background-color: var(--color-blue-500); } + .bg-blue-600 { + background-color: var(--color-blue-600); + } .bg-cyan-950 { background-color: var(--color-cyan-950); } @@ -781,6 +822,12 @@ .bg-gray-100 { background-color: var(--color-gray-100); } + .bg-gray-200 { + background-color: var(--color-gray-200); + } + .bg-gray-300 { + background-color: var(--color-gray-300); + } .bg-white { background-color: var(--color-white); } @@ -820,6 +867,9 @@ .pt-4 { padding-top: calc(var(--spacing) * 4); } + .pb-4 { + padding-bottom: calc(var(--spacing) * 4); + } .pl-2 { padding-left: calc(var(--spacing) * 2); } @@ -865,6 +915,10 @@ font-size: var(--text-xl); line-height: var(--tw-leading, var(--text-xl--line-height)); } + .text-xs { + font-size: var(--text-xs); + line-height: var(--tw-leading, var(--text-xs--line-height)); + } .leading-tight { --tw-leading: var(--leading-tight); line-height: var(--leading-tight); @@ -885,15 +939,34 @@ --tw-tracking: var(--tracking-wide); letter-spacing: var(--tracking-wide); } + .tracking-wider { + --tw-tracking: var(--tracking-wider); + letter-spacing: var(--tracking-wider); + } + .whitespace-nowrap { + white-space: nowrap; + } + .whitespace-pre-line { + white-space: pre-line; + } .text-amber-200 { color: var(--color-amber-200); } .text-black { color: var(--color-black); } + .text-blue-700 { + color: var(--color-blue-700); + } + .text-blue-800 { + color: var(--color-blue-800); + } .text-cyan-950 { color: var(--color-cyan-950); } + .text-emerald-400 { + color: var(--color-emerald-400); + } .text-gray-100 { color: var(--color-gray-100); } @@ -915,9 +988,18 @@ .text-gray-900 { color: var(--color-gray-900); } + .text-red-500 { + color: var(--color-red-500); + } .text-white { color: var(--color-white); } + .uppercase { + text-transform: uppercase; + } + .italic { + font-style: italic; + } .shadow { --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); @@ -930,6 +1012,10 @@ --tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); } + .shadow-sm { + --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } .filter { filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,); } @@ -1009,6 +1095,13 @@ } } } + .hover\:bg-gray-400 { + &:hover { + @media (hover: hover) { + background-color: var(--color-gray-400); + } + } + } .hover\:bg-gray-700 { &:hover { @media (hover: hover) { @@ -1065,6 +1158,11 @@ border-color: var(--color-cyan-950); } } + .focus\:border-transparent { + &:focus { + border-color: transparent; + } + } .focus\:ring-1 { &:focus { --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentColor); @@ -1092,6 +1190,11 @@ --tw-ring-color: var(--color-gray-200); } } + .focus\:ring-gray-500 { + &:focus { + --tw-ring-color: var(--color-gray-500); + } + } .focus\:outline-none { &:focus { --tw-outline-style: none; @@ -1221,6 +1324,11 @@ inherits: false; initial-value: 0; } +@property --tw-divide-y-reverse { + syntax: "*"; + inherits: false; + initial-value: 0; +} @property --tw-border-style { syntax: "*"; inherits: false; From 0e79f63d2fbbd211cf704c28fd83b142e541ec18 Mon Sep 17 00:00:00 2001 From: Brian-Weloba Date: Tue, 1 Apr 2025 14:21:50 +0100 Subject: [PATCH 2/3] Refactor CreateEvent and PredictionServlet; remove unused imports, streamline capacity parsing, and enhance footer.jsp SVG elements for improved readability --- .../dev/brianweloba/servlet/CreateEvent.java | 5 ----- .../servlet/PredictionServlet.java | 5 ++--- .../java/dev/brianweloba/util/DateUtils.java | 21 ------------------- .../main/webapp/WEB-INF/components/footer.jsp | 16 +++++++------- 4 files changed, 10 insertions(+), 37 deletions(-) delete mode 100644 emmas/src/main/java/dev/brianweloba/util/DateUtils.java diff --git a/emmas/src/main/java/dev/brianweloba/servlet/CreateEvent.java b/emmas/src/main/java/dev/brianweloba/servlet/CreateEvent.java index 457f400..7d10ad0 100644 --- a/emmas/src/main/java/dev/brianweloba/servlet/CreateEvent.java +++ b/emmas/src/main/java/dev/brianweloba/servlet/CreateEvent.java @@ -7,11 +7,6 @@ import jakarta.servlet.http.*; import java.io.IOException; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; -import java.util.TimeZone; @WebServlet("/events/create") public class CreateEvent extends HttpServlet { diff --git a/emmas/src/main/java/dev/brianweloba/servlet/PredictionServlet.java b/emmas/src/main/java/dev/brianweloba/servlet/PredictionServlet.java index 263fc89..f23f7ef 100644 --- a/emmas/src/main/java/dev/brianweloba/servlet/PredictionServlet.java +++ b/emmas/src/main/java/dev/brianweloba/servlet/PredictionServlet.java @@ -47,7 +47,7 @@ public void init() throws ServletException { @Override protected void doPost( HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { + throws IOException { response.setContentType("application/json"); try { @@ -58,9 +58,8 @@ protected void doPost( event.setEventLocation(request.getParameter("eventLocation")); String capacityStr = request.getParameter("eventCapacity"); - int capacity = 0; try { - capacity = Integer.parseInt(capacityStr); + int capacity = Integer.parseInt(capacityStr); event.setEventCapacity(capacity); } catch (NumberFormatException e) { request.setAttribute("capacityError", "Invalid capacity value"); diff --git a/emmas/src/main/java/dev/brianweloba/util/DateUtils.java b/emmas/src/main/java/dev/brianweloba/util/DateUtils.java deleted file mode 100644 index 6a65dde..0000000 --- a/emmas/src/main/java/dev/brianweloba/util/DateUtils.java +++ /dev/null @@ -1,21 +0,0 @@ -package dev.brianweloba.util; - - -import java.util.Calendar; -import java.util.Date; - -public class DateUtils { - public static boolean isFutureDate(Date date) { - if (date == null) { - return false; - } - Calendar today = Calendar.getInstance(); - today.set(Calendar.HOUR_OF_DAY, 0); - today.set(Calendar.MINUTE, 0); - today.set(Calendar.SECOND, 0); - today.set(Calendar.MILLISECOND, 0); - - return date.after(today.getTime()); - } - } - diff --git a/emmas/src/main/webapp/WEB-INF/components/footer.jsp b/emmas/src/main/webapp/WEB-INF/components/footer.jsp index dc20aba..376a0b6 100644 --- a/emmas/src/main/webapp/WEB-INF/components/footer.jsp +++ b/emmas/src/main/webapp/WEB-INF/components/footer.jsp @@ -33,29 +33,29 @@ - + - + - - - + + + - - - + + +
From e47f6b0a302956653bf1f52468624c8cc79cdfe5 Mon Sep 17 00:00:00 2001 From: Brian-Weloba Date: Tue, 1 Apr 2025 17:05:09 +0100 Subject: [PATCH 3/3] Refactor event handling; implement EventService for building events from requests, enhance validation with ValidationUtil, and improve error handling in PredictionServlet and UpdateEvent --- .../java/dev/brianweloba/dao/EventDAO.java | 21 ++--- .../brianweloba/services/EventService.java | 34 ++++++++ .../dev/brianweloba/servlet/CreateEvent.java | 33 +++----- .../dev/brianweloba/servlet/EventServlet.java | 75 ++++-------------- .../servlet/PredictionServlet.java | 78 ++----------------- .../dev/brianweloba/servlet/RSVPServlet.java | 7 +- .../dev/brianweloba/servlet/UpdateEvent.java | 43 +++++----- .../dev/brianweloba/util/ValidationUtil.java | 57 ++++++++++++++ .../main/webapp/WEB-INF/views/prediction.jsp | 61 ++++++++++++--- .../src/main/webapp/WEB-INF/views/update.jsp | 4 +- emmas/src/main/webapp/css/styles.css | 9 --- 11 files changed, 201 insertions(+), 221 deletions(-) create mode 100644 emmas/src/main/java/dev/brianweloba/services/EventService.java create mode 100644 emmas/src/main/java/dev/brianweloba/util/ValidationUtil.java diff --git a/emmas/src/main/java/dev/brianweloba/dao/EventDAO.java b/emmas/src/main/java/dev/brianweloba/dao/EventDAO.java index d95d8d2..2713063 100644 --- a/emmas/src/main/java/dev/brianweloba/dao/EventDAO.java +++ b/emmas/src/main/java/dev/brianweloba/dao/EventDAO.java @@ -29,25 +29,19 @@ public Event create(Event event) { } public int countAll(){ - EntityManager manager = HibernateUtil.getEntityManager(); - try{ - return manager.createQuery("SELECT COUNT(e) FROM Event e",Long.class) + try (EntityManager manager = HibernateUtil.getEntityManager()) { + return manager.createQuery("SELECT COUNT(e) FROM Event e", Long.class) .getSingleResult() .intValue(); - }finally { - manager.close(); } } public List findPaginated(int startIndex, int pageSize){ - EntityManager manager = HibernateUtil.getEntityManager(); - try{ - return manager.createQuery("SELECT e FROM Event e ORDER BY e.eventDate",Event.class) + try (EntityManager manager = HibernateUtil.getEntityManager()) { + return manager.createQuery("SELECT e FROM Event e ORDER BY e.eventDate", Event.class) .setFirstResult(startIndex) .setMaxResults(pageSize) .getResultList(); - }finally { - manager.close(); } } @@ -82,7 +76,7 @@ public Event findByIdAndToken(Long id,String token){ query.setParameter("token", token); System.out.println("Token: " + token); System.out.println("Id: " + id); - System.out.println("Query: " + query.toString()); + System.out.println("Query: " + query); return query.getSingleResult(); }catch (Exception e) { if (manager.getTransaction().isActive()) { @@ -104,12 +98,12 @@ public List findAll() { } } - public boolean update(Event event,String token) { + public void update(Event event, String token) { EntityManager manager = HibernateUtil.getEntityManager(); try { Event eventToUpdate = findByIdAndToken(event.getId(),token); if(eventToUpdate == null){ - return false; + return; } manager.getTransaction().begin(); @@ -122,7 +116,6 @@ public boolean update(Event event,String token) { manager.merge(eventToUpdate); manager.getTransaction().commit(); - return true; } catch (Exception e) { if (manager.getTransaction().isActive()) { manager.getTransaction().rollback(); diff --git a/emmas/src/main/java/dev/brianweloba/services/EventService.java b/emmas/src/main/java/dev/brianweloba/services/EventService.java new file mode 100644 index 0000000..5ce7810 --- /dev/null +++ b/emmas/src/main/java/dev/brianweloba/services/EventService.java @@ -0,0 +1,34 @@ +package dev.brianweloba.services; + +import dev.brianweloba.model.Event; +import jakarta.servlet.http.HttpServletRequest; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +public class EventService { + public void buildEventFromRequest(HttpServletRequest request, Event event) { + event.setTitle(request.getParameter("title")); + event.setDescription(request.getParameter("description")); + event.setEventHost(request.getParameter("eventHost")); + event.setEventLocation(request.getParameter("eventLocation")); + + String capacityStr = request.getParameter("eventCapacity"); + try { + int capacity = Integer.parseInt(capacityStr); + event.setEventCapacity(capacity); + } catch (NumberFormatException e) { + request.setAttribute("capacityError", "Invalid capacity value"); + } + + String dateStr = request.getParameter("eventDate"); + try { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + Date eventDate = sdf.parse(dateStr); + event.setEventDate(eventDate); + } catch (ParseException e) { + request.setAttribute("dateError", "Invalid date format"); + } + } +} diff --git a/emmas/src/main/java/dev/brianweloba/servlet/CreateEvent.java b/emmas/src/main/java/dev/brianweloba/servlet/CreateEvent.java index 7d10ad0..b7d3530 100644 --- a/emmas/src/main/java/dev/brianweloba/servlet/CreateEvent.java +++ b/emmas/src/main/java/dev/brianweloba/servlet/CreateEvent.java @@ -20,7 +20,7 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) - throws IOException { + throws IOException, ServletException { HttpSession session = request.getSession(); Event event = (Event) session.getAttribute("event"); @@ -28,30 +28,15 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) response.sendRedirect(request.getContextPath() + "/events/create"); return; } -// event.setTitle(request.getParameter("title")); -// event.setEventHost(request.getParameter("eventHost")); -// event.setDescription(request.getParameter("description")); + event.setEventType(request.getParameter("eventType").toUpperCase()); -// event.setEventLocation(request.getParameter("location")); -// String capacityStr = request.getParameter("eventCapacity"); -// int capacity = 0; -// try { -// capacity = Integer.parseInt(capacityStr); -// event.setEventCapacity(capacity); -// } catch (NumberFormatException e) { -// request.setAttribute("capacityError", "Invalid capacity value"); -// } -// -// String dateString = request.getParameter("eventDate"); -// System.out.println("EventDate " + dateString); -// SimpleDateFormat formatter = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.ENGLISH); -// formatter.setTimeZone(TimeZone.getTimeZone("GMT")); -// try { -// Date eventDate = formatter.parse(dateString); -// event.setEventDate(eventDate); -// } catch (ParseException e) { -// throw new RuntimeException(e); -// } + + if(event.getEventType().isEmpty()){ + request.setAttribute("eventTypeError", "Event Type is empty"); + request.getRequestDispatcher("/WEB-INF/views/prediction.jsp").forward(request, response); + return; + } + event = eventDAO.create(event); session.removeAttribute("event"); diff --git a/emmas/src/main/java/dev/brianweloba/servlet/EventServlet.java b/emmas/src/main/java/dev/brianweloba/servlet/EventServlet.java index c7e8e61..ac6e0e2 100644 --- a/emmas/src/main/java/dev/brianweloba/servlet/EventServlet.java +++ b/emmas/src/main/java/dev/brianweloba/servlet/EventServlet.java @@ -1,20 +1,16 @@ package dev.brianweloba.servlet; -import java.io.IOException; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.List; - import dev.brianweloba.dao.EventDAO; import dev.brianweloba.model.Event; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; -import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; + @WebServlet("/events") public class EventServlet extends HttpServlet { private final EventDAO eventDAO = new EventDAO(); @@ -24,27 +20,23 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { int pageSize = 10; - int currentPage =1; - - try{ - String pageSizeParam = request.getParameter("size"); - if(pageSizeParam != null){ - pageSize = Integer.parseInt(pageSizeParam); - } + int currentPage = 1; - String pageParam = request.getParameter("page"); - if(pageParam!=null){ - currentPage = Integer.parseInt(pageParam); - } - }catch (NumberFormatException e){ + String pageSizeParam = request.getParameter("size"); + if (pageSizeParam != null) { + pageSize = Integer.parseInt(pageSizeParam); + } + String pageParam = request.getParameter("page"); + if (pageParam != null) { + currentPage = Integer.parseInt(pageParam); } - int startIndex = (currentPage-1)*pageSize; + int startIndex = (currentPage - 1) * pageSize; int totalEvents = eventDAO.countAll(); - int totalPages = (int) Math.ceil((double) totalEvents/pageSize); + int totalPages = (int) Math.ceil((double) totalEvents / pageSize); - List events = eventDAO.findPaginated(startIndex,pageSize); + List events = eventDAO.findPaginated(startIndex, pageSize); request.setAttribute("events", events); request.setAttribute("currentPage", currentPage); @@ -57,43 +49,4 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) request.setAttribute("events", events); request.getRequestDispatcher("/WEB-INF/views/events.jsp").forward(request, response); } - - @Override - protected void doPost(HttpServletRequest request, HttpServletResponse response) - throws IOException { - Long id = Long.parseLong(request.getParameter("id")); -// String token = request.getParameter("token"); - String token = getEditTokenFromCookies(request, id); - Event event = eventDAO.findByIdAndToken(id, token); - - event.setTitle(request.getParameter("title")); - event.setEventHost(request.getParameter("eventHost")); - event.setDescription(request.getParameter("description")); - event.setEventType(request.getParameter("eventType")); - event.setEventLocation(request.getParameter("location")); - event.setEventCapacity(Integer.parseInt(request.getParameter("eventCapacity"))); - - String dateString = request.getParameter("eventDate"); - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); - try { - Date eventDate = dateFormat.parse(dateString); - event.setEventDate(eventDate); - } catch (ParseException e) { - throw new RuntimeException(e); - } - eventDAO.update(event, token); - response.sendRedirect(request.getContextPath() + "/events"); - } - - private String getEditTokenFromCookies(HttpServletRequest request, Long eventId) { - Cookie[] cookies = request.getCookies(); - if (cookies != null) { - for (Cookie cookie : cookies) { - if (cookie.getName().equals("event_" + eventId + "_token")) { - return cookie.getValue(); - } - } - } - return null; - } } diff --git a/emmas/src/main/java/dev/brianweloba/servlet/PredictionServlet.java b/emmas/src/main/java/dev/brianweloba/servlet/PredictionServlet.java index f23f7ef..45f8352 100644 --- a/emmas/src/main/java/dev/brianweloba/servlet/PredictionServlet.java +++ b/emmas/src/main/java/dev/brianweloba/servlet/PredictionServlet.java @@ -2,28 +2,24 @@ import dev.brianweloba.dao.EventDAO; import dev.brianweloba.model.Event; +import dev.brianweloba.services.EventService; +import dev.brianweloba.util.ValidationUtil; import dev.brianweloba.weka.EventTypeClassifier; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import jakarta.validation.ConstraintViolation; -import jakarta.validation.Validation; -import jakarta.validation.Validator; -import jakarta.validation.ValidatorFactory; import java.io.IOException; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; import java.util.List; import java.util.Map; -import java.util.Set; + @WebServlet("/events/predict-type") public class PredictionServlet extends HttpServlet { private EventTypeClassifier classifier; + private final EventService eventService = new EventService(); @Override public void init() throws ServletException { @@ -52,62 +48,9 @@ protected void doPost( try { Event event = new Event(); - event.setTitle(request.getParameter("title")); - event.setDescription(request.getParameter("description")); - event.setEventHost(request.getParameter("eventHost")); - event.setEventLocation(request.getParameter("eventLocation")); - - String capacityStr = request.getParameter("eventCapacity"); - try { - int capacity = Integer.parseInt(capacityStr); - event.setEventCapacity(capacity); - } catch (NumberFormatException e) { - request.setAttribute("capacityError", "Invalid capacity value"); - } - - String dateStr = request.getParameter("eventDate"); - try { - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); - Date eventDate = sdf.parse(dateStr); - event.setEventDate(eventDate); - } catch (ParseException e) { - request.setAttribute("dateError", "Invalid date format"); - } - - Set> violations = validate(event); - - if (!violations.isEmpty()) { - for (ConstraintViolation violation : violations) { - String propertyPath = violation.getPropertyPath().toString(); - String message = violation.getMessage(); - - switch (propertyPath) { - case "title": - request.setAttribute("titleError", message); - break; - case "eventHost": - request.setAttribute("hostError", message); - break; - case "eventLocation": - request.setAttribute("locationError", message); - break; - case "eventCapacity": - request.setAttribute("capacityError", message); - break; - case "eventDate": - request.setAttribute("dateError", message); - break; - case "description": - request.setAttribute("descriptionError", message); - break; - } - } + eventService.buildEventFromRequest(request, event); - request.setAttribute("event", event); - - request.getRequestDispatcher("/WEB-INF/views/create.jsp").forward(request, response); - return; - } + if (ValidationUtil.validateEvent(request, response, event,"/WEB-INF/views/create.jsp")) return; String predictedType = classifier.predictEventType(event); Map probabilities = classifier.getPredictionProbabilities(event); @@ -123,13 +66,4 @@ protected void doPost( "{\"success\":false,\"error\":\"%s\"}", e)); } } - - - private Set> validate(Event event) { - Validator validator; - try (ValidatorFactory factory = Validation.buildDefaultValidatorFactory()) { - validator = factory.getValidator(); - } - return validator.validate(event); - } } diff --git a/emmas/src/main/java/dev/brianweloba/servlet/RSVPServlet.java b/emmas/src/main/java/dev/brianweloba/servlet/RSVPServlet.java index 4694fe6..ccf4678 100644 --- a/emmas/src/main/java/dev/brianweloba/servlet/RSVPServlet.java +++ b/emmas/src/main/java/dev/brianweloba/servlet/RSVPServlet.java @@ -22,11 +22,6 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) try { RSVP rsvp = new RSVP(); - System.out.println("Event ID: "+request.getParameter("eventId")); - System.out.println("Name: "+request.getParameter("name")); - System.out.println("Email: "+request.getParameter("email")); - System.out.println("Guests: "+request.getParameter("guests")); - rsvp.setName(request.getParameter("name")); rsvp.setEmail(request.getParameter("email")); rsvp.setGuests(Integer.parseInt(request.getParameter("guests"))); @@ -41,7 +36,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) throw new IllegalArgumentException("Guests must be a positive number"); } - rsvp = rsvpDAO.create(rsvp, Long.parseLong(request.getParameter("eventId"))); + rsvpDAO.create(rsvp, Long.parseLong(request.getParameter("eventId"))); jsonResponse.addProperty("success", true); jsonResponse.addProperty("message", "RSVP successful"); diff --git a/emmas/src/main/java/dev/brianweloba/servlet/UpdateEvent.java b/emmas/src/main/java/dev/brianweloba/servlet/UpdateEvent.java index 16cc33e..d173657 100644 --- a/emmas/src/main/java/dev/brianweloba/servlet/UpdateEvent.java +++ b/emmas/src/main/java/dev/brianweloba/servlet/UpdateEvent.java @@ -2,6 +2,8 @@ import dev.brianweloba.dao.EventDAO; import dev.brianweloba.model.Event; +import dev.brianweloba.services.EventService; +import dev.brianweloba.util.ValidationUtil; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.Cookie; @@ -14,57 +16,54 @@ @WebServlet("/events/update") public class UpdateEvent extends HttpServlet { private final EventDAO eventDAO = new EventDAO(); + private final EventService eventService = new EventService(); @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Long eventId = Long.parseLong(request.getParameter("id")); String token = getEditTokenFromCookies(request, eventId); + Event event = getEvent(request, response, token, eventId); + if (event == null) return; + + request.setAttribute("event", event); + request.getRequestDispatcher("/WEB-INF/views/update.jsp").forward(request, response); + } + + private Event getEvent(HttpServletRequest request, HttpServletResponse response, String token, Long eventId) throws ServletException, IOException { if(token == null) { request.setAttribute("error", "Invalid token"); request.getRequestDispatcher("/WEB-INF/views/error.jsp").forward(request, response); - return; + return null; } + Event event = eventDAO.findByIdAndToken(eventId, token); if (event == null) { request.setAttribute("error", "Event not found or you don't have permission to edit this event."); request.getRequestDispatcher("/WEB-INF/views/error.jsp").forward(request, response); - return; + return null; } - - request.setAttribute("event", event); - request.getRequestDispatcher("/WEB-INF/views/update.jsp").forward(request, response); + return event; } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { Long eventId = Long.parseLong(request.getParameter("eventId")); String token = getEditTokenFromCookies(request, eventId); - if(token == null) { - request.setAttribute("error", "Invalid token"); - request.getRequestDispatcher("/WEB-INF/views/error.jsp").forward(request, response); - return; - } - Event event = eventDAO.findByIdAndToken(eventId, token); - - if (event == null) { - request.setAttribute("error", "Event not found or you don't have permission to edit this event."); - request.getRequestDispatcher("/WEB-INF/views/error.jsp").forward(request, response); - return; - } + Event event = getEvent(request, response, token, eventId); + if (event == null) return; - event.setTitle(request.getParameter("title")); - event.setEventHost(request.getParameter("eventHost")); - event.setDescription(request.getParameter("description")); event.setEventType(request.getParameter("eventType")); - event.setEventLocation(request.getParameter("location")); - event.setEventCapacity(Integer.parseInt(request.getParameter("eventCapacity"))); + eventService.buildEventFromRequest(request, event); + + if(ValidationUtil.validateEvent(request,response,event,"/WEB-INF/views/update.jsp")) return; eventDAO.update(event, token); response.sendRedirect(request.getContextPath() + "/events"); } + private String getEditTokenFromCookies(HttpServletRequest request, Long eventId) { Cookie[] cookies = request.getCookies(); if (cookies != null) { diff --git a/emmas/src/main/java/dev/brianweloba/util/ValidationUtil.java b/emmas/src/main/java/dev/brianweloba/util/ValidationUtil.java new file mode 100644 index 0000000..87d2f5d --- /dev/null +++ b/emmas/src/main/java/dev/brianweloba/util/ValidationUtil.java @@ -0,0 +1,57 @@ +package dev.brianweloba.util; + +import dev.brianweloba.model.Event; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import jakarta.validation.ValidatorFactory; + +import java.io.IOException; +import java.util.Set; + +public class ValidationUtil { + public static boolean validateEvent(HttpServletRequest request, HttpServletResponse response, Event event,String path) throws ServletException, IOException { + Validator validator; + try (ValidatorFactory factory = Validation.buildDefaultValidatorFactory()) { + validator = factory.getValidator(); + } + Set> violations = validator.validate(event); + + if (!violations.isEmpty()) { + for (ConstraintViolation violation : violations) { + String propertyPath = violation.getPropertyPath().toString(); + String message = violation.getMessage(); + + switch (propertyPath) { + case "title": + request.setAttribute("titleError", message); + break; + case "eventHost": + request.setAttribute("hostError", message); + break; + case "eventLocation": + request.setAttribute("locationError", message); + break; + case "eventCapacity": + request.setAttribute("capacityError", message); + break; + case "eventDate": + request.setAttribute("dateError", message); + break; + case "description": + request.setAttribute("descriptionError", message); + break; + } + } + + request.setAttribute("event", event); + + request.getRequestDispatcher(path).forward(request, response); + return true; + } + return false; + } +} diff --git a/emmas/src/main/webapp/WEB-INF/views/prediction.jsp b/emmas/src/main/webapp/WEB-INF/views/prediction.jsp index 867abe3..99d80ba 100644 --- a/emmas/src/main/webapp/WEB-INF/views/prediction.jsp +++ b/emmas/src/main/webapp/WEB-INF/views/prediction.jsp @@ -5,6 +5,29 @@ Predict Event Type + <%@ include file="../components/navbar.jsp" %> @@ -17,13 +40,19 @@

Event Details

-

Event Title:

-

Host Name:

-

Event Date:

+

Event Title:

+

Host Name:

+

Event Date:

-

Capacity: people

-

Location:

+

Capacity: people

+

Location:

@@ -37,19 +66,24 @@
-

AI suggests:

+

AI suggests:

AI Powered
-
+
+ class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline ${not empty requestScope.eventTypeError ? 'border-red-500' : ''}"> + + ${requestScope.eventTypeError} +

You can modify the suggested type if needed

@@ -72,8 +106,12 @@ - - + + @@ -83,7 +121,8 @@
Event TypeConfidenceEvent + Type + + Confidence +
-
+
${Math.round(entry.value * 100)}%
diff --git a/emmas/src/main/webapp/WEB-INF/views/update.jsp b/emmas/src/main/webapp/WEB-INF/views/update.jsp index 92b2a18..82475ba 100644 --- a/emmas/src/main/webapp/WEB-INF/views/update.jsp +++ b/emmas/src/main/webapp/WEB-INF/views/update.jsp @@ -45,8 +45,8 @@ class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline">
- - Location +
diff --git a/emmas/src/main/webapp/css/styles.css b/emmas/src/main/webapp/css/styles.css index c272896..8eda671 100644 --- a/emmas/src/main/webapp/css/styles.css +++ b/emmas/src/main/webapp/css/styles.css @@ -1012,10 +1012,6 @@ --tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); } - .shadow-sm { - --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); - box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); - } .filter { filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,); } @@ -1158,11 +1154,6 @@ border-color: var(--color-cyan-950); } } - .focus\:border-transparent { - &:focus { - border-color: transparent; - } - } .focus\:ring-1 { &:focus { --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentColor);