diff --git a/.gitignore b/.gitignore index 2417caa..dc87723 100644 --- a/.gitignore +++ b/.gitignore @@ -54,4 +54,6 @@ node_modules resources/templates/css/** resources/templates/js/** resources/templates/fonts/** -dist \ No newline at end of file +dist + +.factorypath/ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..ff19f3e --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# help-the-midlands +Submission for HackTheMidlands 5.0 + +## Categories +- Making IT Good For Society +- Supporting The Fight Against COVID-19 +- Helping Your Local Community + +## Concept + +HelpTheMidlands is a web application designed to allow people to volunteer in their local communities by picking up shopping for those currently isolating due to coronavirus, or those who are older and may find it difficult to go to the shops. + +This app has been designed with simplicity in mind, as we find that many online stores make it confusing for the elderly to place an order then setup a delivery slot. + +Volunteers respond to requests made by supportees (*vulnerable people*) for food or other shopping. + +## Usage + +You can register as a **volunteer** or a **supportee** using your name, an email address and a password. + +Once logged in, the supportee makes a request (shopping list) for each item of shopping they need, with a note of their budget and their preferred store. (Could be the local corner shop as opposed to be a chain). + +A request is then sent out to nearby volunteers, who can then accept it and buy the shopping, delivering it to the vulnerable person. \ No newline at end of file diff --git a/dependency-reduced-pom.xml b/dependency-reduced-pom.xml index 774a654..9ee1ccd 100644 --- a/dependency-reduced-pom.xml +++ b/dependency-reduced-pom.xml @@ -1,53 +1,60 @@ - - 4.0.0 - com.hackthemidlands.processblinders - HackTheMidlands - 0.0.1 - - - - maven-compiler-plugin - 3.5.1 - - 1.8 - 1.8 - - - - maven-jar-plugin - 3.1.0 - - - - true - lib/ - com.hackthemidlands.processblinders.Main - - - - - - maven-shade-plugin - 2.4.3 - - - package - - shade - - - - - com.hackthemidlands.processblinders.Main - - - - - - - - + + 4.0.0 + com.hackthemidlands.processblinders + HackTheMidlands + 0.0.1 + + + + maven-compiler-plugin + 3.5.1 + + 1.8 + 1.8 + + + + maven-jar-plugin + 3.1.0 + + + + true + lib/ + com.hackthemidlands.processblinders.Main + + + + + + maven-shade-plugin + 2.4.3 + + + package + + shade + + + + + com.hackthemidlands.processblinders.Main + + + + + + + + + + + org.projectlombok + lombok + 1.18.16 + provided + + diff --git a/src/main/java/com/hackthemidlands/processblinders/Main.java b/src/main/java/com/hackthemidlands/processblinders/Main.java index d6497ef..f2e39b5 100644 --- a/src/main/java/com/hackthemidlands/processblinders/Main.java +++ b/src/main/java/com/hackthemidlands/processblinders/Main.java @@ -1,116 +1,83 @@ package com.hackthemidlands.processblinders; +import com.hackthemidlands.processblinders.api.Order; +import com.hackthemidlands.processblinders.api.OrderStatus; import com.hackthemidlands.processblinders.api.User; -import lombok.Getter; +import com.hackthemidlands.processblinders.pages.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import spark.Filter; -import spark.Request; -import spark.Response; +import spark.ModelAndView; import spark.Spark; +import spark.TemplateEngine; import spark.template.thymeleaf.ThymeleafTemplateEngine; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.Random; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import static com.hackthemidlands.processblinders.util.OrderUtil.*; +import static com.hackthemidlands.processblinders.util.UserUtil.*; import static spark.Spark.*; public final class Main { private static final Logger logger = LoggerFactory.getLogger(Main.class); - private static final Map loggedInUsers = new HashMap<>(); - - @Getter - private static final List allValidUsers = new ArrayList<>(); - - public static Filter setSession = (Request request, Response response) -> { - if (hasCookie(request)) { - String cookie = getCookie(request); - System.out.println(cookie); - User user = getUserFromEmail(cookie); - if (user != null) { - loggedInUsers.put(user.getEmail(), user); - } else { - response.redirect("/dev/fuck-off"); - } - } - }; - - public static boolean addNewUserToDatabase(User user) { - if (findUserFromDatabase(user.getEmail()) != null) { - return false; - } - allValidUsers.add(user); - return true; - } - - public static User findUserFromDatabase(String email) { - return allValidUsers.stream().filter(u -> u.getEmail().equalsIgnoreCase(email)).findFirst().orElse(null); - } - - public static boolean isLoggedIn(User user) { - return loggedInUsers.containsValue(user); - } public static void main(String[] args) { Spark.exception(Exception.class, (exception, request, response) -> exception.printStackTrace()); // allow spark to internally handle exceptions + final TemplateEngine templateEngine = new ThymeleafTemplateEngine(); staticFileLocation("/public"); port(8080); - allValidUsers.add(new User()); - allValidUsers.add(new User("test", "admin", "admin@admin.com", "pass")); - - get("/test/test", new TestViewRoute(), new ThymeleafTemplateEngine()); - get("/hello", (req, res) -> "Hello World"); - get("/test", (req, res) -> "timer"); - get("/goodbye/:name", (req, res) -> "See ya, " + req.params(":name")); - get("/thyme", new TestViewRoute(), new ThymeleafTemplateEngine()); - get("/support", new SupportViewRoute(), new ThymeleafTemplateEngine()); - get("/login/volunteer", new VolunteerViewRoute(), new ThymeleafTemplateEngine()); - get("/login/makeAccount", new MakeAccountViewRoute(), new ThymeleafTemplateEngine()); - path("/register", () -> { - post("", (re, rs) -> { - if (re.queryParams("validate").equalsIgnoreCase("Volunteer")) { + Random random = new Random(); + + getAllValidUsers().addAll(IntStream.range(0, 3).mapToObj(User::dummyVolunteer).collect(Collectors.toList())); // here i add the dummy volunteers 0, 1, 2 + getAllValidUsers().addAll(IntStream.range(0, 3).mapToObj(User::dummyUser).collect(Collectors.toList())); // here i add the dummy users 0, 1, 2 + getAllValidOrders().addAll(IntStream.range(0, 3) + .mapToObj(i -> Order.builder().shopList(new String[]{ + (random.nextInt(10) + i) + " tins of beans", (random.nextInt(i + 1) + 1) + " loaves of bread", (random.nextInt(i + 4) + i) + " pints of milk"}) + .id(++Order.maxId) + .user(getAllValidUsers().stream().filter(u -> !u.isVolunteer()).collect(Collectors.toList()).get(i)) + .maxPrice(69d).status(OrderStatus.PENDING) + .build()) + .collect(Collectors.toList())); + + get("/error", (re, rs) -> new ModelAndView(new HashMap<>(), "error"), new ThymeleafTemplateEngine()); - return "volunteer"; - } - return "not volunteer"; - }); + get("/", new FrontPage(), templateEngine); - get("", (re, rs) -> "I got a GET request silly"); + path("/orders", () -> { + ViewOrdersPage viewOrdersPage = new ViewOrdersPage(); + get("/view", viewOrdersPage, templateEngine); + + PlaceOrderPage placeOrderPage = new PlaceOrderPage(); + post("/new", placeOrderPage.post); + get("/new", placeOrderPage, templateEngine); }); - path("/dev", () -> { - before("/protected", setSession); - get("/protected", (req, res) -> { - User u = getUserFromEmail(getCookie(req)); - return "Your name is " + u.getFirstName() + " " + u.getLastName(); - }); - get("/fuck-off", (req, res) -> "You have been fucked off"); - get("/login", (req, res) -> { - loggedInUsers.put(new User().getEmail(), new User()); - System.err.println("YOU ARE SUPPOSED TO BE LOGGED IN HERE"); - setCookie(res, new User()); - return "You have been logged in."; - }); + + path("/commitTo", () -> { + }); - } - public static void setCookie(Response response, User user) { - response.cookie("/", "email", user.getEmail(), -1, false); - } + path("/settings", () -> { + SettingsPage settingsPage = new SettingsPage(); + get("", settingsPage, templateEngine); + post("", settingsPage.post); + }); - public static boolean hasCookie(Request request) { - return request.cookie("email") != null; - } + path("/login", () -> { + LoginPage loginPage = new LoginPage(); + get("", loginPage, templateEngine); + post("", loginPage.post); + }); - public static String getCookie(Request request) { - return request.cookie("email"); - } + path("/register", () -> { + RegisterPage registerPage = new RegisterPage(); + post("", registerPage.post); + get("", registerPage, templateEngine); + }); - public static User getUserFromEmail(String email) { - return findUserFromDatabase(email); + path("/dev", new DevPage().getRoutes); } - } \ No newline at end of file diff --git a/src/main/java/com/hackthemidlands/processblinders/MakeAccountViewRoute.java b/src/main/java/com/hackthemidlands/processblinders/MakeAccountViewRoute.java deleted file mode 100644 index 874fcb9..0000000 --- a/src/main/java/com/hackthemidlands/processblinders/MakeAccountViewRoute.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.hackthemidlands.processblinders; - -import spark.ModelAndView; -import spark.Request; -import spark.Response; -import spark.TemplateViewRoute; - -import java.util.HashMap; - -public class MakeAccountViewRoute implements TemplateViewRoute { - - @Override - public ModelAndView handle(Request request, Response response) throws Exception { - return new ModelAndView(new HashMap<>(), "makeAccount"); - } -} diff --git a/src/main/java/com/hackthemidlands/processblinders/TestViewRoute.java b/src/main/java/com/hackthemidlands/processblinders/TestViewRoute.java deleted file mode 100644 index 555d3a5..0000000 --- a/src/main/java/com/hackthemidlands/processblinders/TestViewRoute.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.hackthemidlands.processblinders; - -import spark.ModelAndView; -import spark.Request; -import spark.Response; -import spark.TemplateViewRoute; - -import java.time.Instant; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.time.temporal.ChronoUnit; -import java.util.HashMap; -import java.util.Map; - -public class TestViewRoute implements TemplateViewRoute { - - private int drones = 0; - - public ModelAndView handle(Request request, Response response) { - Map model = new HashMap<>(); - drones++; - model.put("drones", drones); - LocalDateTime dateTime = Instant.ofEpochMilli(System.currentTimeMillis()).atZone(ZoneId.systemDefault()).toLocalDateTime(); - dateTime = dateTime.plus(1, ChronoUnit.HOURS); - model.put("startTime", dateTime.toString()); - - return new ModelAndView(model, "main"); - } -} diff --git a/src/main/java/com/hackthemidlands/processblinders/VolunteerViewRoute.java b/src/main/java/com/hackthemidlands/processblinders/VolunteerViewRoute.java deleted file mode 100644 index 3085403..0000000 --- a/src/main/java/com/hackthemidlands/processblinders/VolunteerViewRoute.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.hackthemidlands.processblinders; - -import spark.ModelAndView; -import spark.Request; -import spark.Response; -import spark.TemplateViewRoute; - -import java.util.HashMap; - -public class VolunteerViewRoute implements TemplateViewRoute { - - @Override - public ModelAndView handle(Request request, Response response) throws Exception { - return new ModelAndView(new HashMap<>(), "volunteer"); - } -} diff --git a/src/main/java/com/hackthemidlands/processblinders/api/Order.java b/src/main/java/com/hackthemidlands/processblinders/api/Order.java index f4aada5..fada80c 100644 --- a/src/main/java/com/hackthemidlands/processblinders/api/Order.java +++ b/src/main/java/com/hackthemidlands/processblinders/api/Order.java @@ -1,15 +1,25 @@ package com.hackthemidlands.processblinders.api; +import lombok.Builder; import lombok.Data; -import java.util.ArrayList; -import java.util.List; - @Data +@Builder public class Order { - private List shopList = new ArrayList<>(); + + public static int maxId = -1; + + private String[] shopList; + private int id; private double maxPrice; - private String location; private OrderStatus status; + private User user; + private User volunteer; + private String priority; + + public int getID() { + return this.id; + } //time window? + // Time sent?? } diff --git a/src/main/java/com/hackthemidlands/processblinders/api/OrderStatus.java b/src/main/java/com/hackthemidlands/processblinders/api/OrderStatus.java index 6be7961..0cd7bb4 100644 --- a/src/main/java/com/hackthemidlands/processblinders/api/OrderStatus.java +++ b/src/main/java/com/hackthemidlands/processblinders/api/OrderStatus.java @@ -1,11 +1,17 @@ package com.hackthemidlands.processblinders.api; +import lombok.Getter; + +@Getter public enum OrderStatus { - PENDING(0), ACCEPTED(1), COMPLETED(2), CANCELLED(3); + PENDING(0, "Pending"), ACCEPTED(1, "Accepted"), COMPLETED(2, "Completed"), CANCELLED(3, "Cancelled"); + int i; + String string; - OrderStatus(int i) { + OrderStatus(int i, String string) { this.i = i; + this.string = string; } public OrderStatus getFromCode(int j) { @@ -22,4 +28,8 @@ public OrderStatus getFromCode(int j) { return null; } } + + public int getNum() { + return this.i; + } } diff --git a/src/main/java/com/hackthemidlands/processblinders/api/User.java b/src/main/java/com/hackthemidlands/processblinders/api/User.java index 15ad1c6..c41349d 100644 --- a/src/main/java/com/hackthemidlands/processblinders/api/User.java +++ b/src/main/java/com/hackthemidlands/processblinders/api/User.java @@ -1,30 +1,55 @@ package com.hackthemidlands.processblinders.api; +import lombok.Builder; import lombok.Data; @Data +@Builder public class User { + public static int maxId = -1; + private final int id; private String firstName; private String lastName; - private boolean isVolunteer; - private String email; private String password; + private String postcode; + + private boolean isVolunteer; + + public static User dummyVolunteer() { + return dummyVolunteer(0); + } + + public static User dummyUser() { + return dummyUser(0); + } - public User() { - this.firstName = "Default"; - this.lastName = "Lastname"; - this.email = "test@test.test"; - this.password = "password123"; + public static User dummyVolunteer(int i) { + maxId++; + return new UserBuilder() + .email("volunteer" + i + "@v.co") + .isVolunteer(true) + .firstName("Volunteer") + .lastName(i + "") + .password("password" + i) + .id(maxId) + .postcode("PO59 C0D" + i) + .build(); } - public User(String firstName, String lastName, String email, String password) { - this.firstName = firstName; - this.lastName = lastName; - this.email = email; - this.password = password; + public static User dummyUser(int i) { + maxId++; + return new UserBuilder() + .email("user" + i + "@u.co") + .isVolunteer(false) + .firstName("User") + .lastName(i + "") + .postcode("P057 C0D" + i) + .password("pass" + i) + .id(maxId) + .build(); } } diff --git a/src/main/java/com/hackthemidlands/processblinders/pages/DevPage.java b/src/main/java/com/hackthemidlands/processblinders/pages/DevPage.java new file mode 100644 index 0000000..136420c --- /dev/null +++ b/src/main/java/com/hackthemidlands/processblinders/pages/DevPage.java @@ -0,0 +1,41 @@ +package com.hackthemidlands.processblinders.pages; + +import com.hackthemidlands.processblinders.api.User; +import spark.RouteGroup; +import spark.template.thymeleaf.ThymeleafTemplateEngine; + +import static com.hackthemidlands.processblinders.util.CookieUtil.*; +import static com.hackthemidlands.processblinders.util.FilterUtil.*; +import static com.hackthemidlands.processblinders.util.UserUtil.*; +import static spark.Spark.before; +import static spark.Spark.get; + +public class DevPage { + + public RouteGroup getRoutes = () -> { + before("/protected", requiresLogin); + get("/protected", (req, res) -> { + User u = findUserFromDatabase(getCookie(req)); + if (u == null) return ""; + return "Your name is " + u.getFirstName() + " " + u.getLastName(); + }); + before("/volunteers-only", volunteerOnly); + get("/volunteers-only", (re, rs) -> { + User u = findUserFromDatabase(getCookie(re)); + if (u == null || !u.isVolunteer()) return ""; + return "Hello volunteer!"; + }); + get("/login", (req, res) -> { + User u = User.dummyUser(0); + getLoggedInUsers().put(u.getEmail(), u); + setCookie(res, u); + return "You have been logged as: " + u.getEmail(); + }); + get("/logout", (req, res) -> { + setCookie(res, User.builder().build()); + res.redirect("/login"); + return "You have been logged out."; + }); + get("/viewOrders", new ViewOrdersPage(), new ThymeleafTemplateEngine()); + }; +} diff --git a/src/main/java/com/hackthemidlands/processblinders/SupportViewRoute.java b/src/main/java/com/hackthemidlands/processblinders/pages/ErrorPage.java similarity index 57% rename from src/main/java/com/hackthemidlands/processblinders/SupportViewRoute.java rename to src/main/java/com/hackthemidlands/processblinders/pages/ErrorPage.java index 9d1dab8..5c98cae 100644 --- a/src/main/java/com/hackthemidlands/processblinders/SupportViewRoute.java +++ b/src/main/java/com/hackthemidlands/processblinders/pages/ErrorPage.java @@ -1,4 +1,4 @@ -package com.hackthemidlands.processblinders; +package com.hackthemidlands.processblinders.pages; import spark.ModelAndView; import spark.Request; @@ -7,10 +7,10 @@ import java.util.HashMap; -public class SupportViewRoute implements TemplateViewRoute { +public class ErrorPage implements TemplateViewRoute { @Override public ModelAndView handle(Request request, Response response) { - return new ModelAndView(new HashMap<>(), "support"); + return new ModelAndView(new HashMap<>(), "error"); } } diff --git a/src/main/java/com/hackthemidlands/processblinders/pages/FrontPage.java b/src/main/java/com/hackthemidlands/processblinders/pages/FrontPage.java new file mode 100644 index 0000000..75b6ec9 --- /dev/null +++ b/src/main/java/com/hackthemidlands/processblinders/pages/FrontPage.java @@ -0,0 +1,22 @@ +package com.hackthemidlands.processblinders.pages; + +import com.hackthemidlands.processblinders.util.CookieUtil; +import com.hackthemidlands.processblinders.util.UserUtil; +import spark.ModelAndView; +import spark.Request; +import spark.Response; +import spark.TemplateViewRoute; + +import javax.servlet.http.Cookie; +import java.util.HashMap; +import java.util.Map; + +public class FrontPage implements TemplateViewRoute { + + @Override + public ModelAndView handle(Request request, Response response) { + Map models = new HashMap<>(); + models.put("loggedIn", UserUtil.findUserFromDatabase(CookieUtil.getCookie(request)) != null); + return new ModelAndView(models, "index"); + } +} diff --git a/src/main/java/com/hackthemidlands/processblinders/pages/LoginPage.java b/src/main/java/com/hackthemidlands/processblinders/pages/LoginPage.java new file mode 100644 index 0000000..fada1ee --- /dev/null +++ b/src/main/java/com/hackthemidlands/processblinders/pages/LoginPage.java @@ -0,0 +1,44 @@ +package com.hackthemidlands.processblinders.pages; + +import com.hackthemidlands.processblinders.api.User; +import com.hackthemidlands.processblinders.util.UserUtil; +import spark.*; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Set; + +import static com.hackthemidlands.processblinders.util.CookieUtil.getCookie; +import static com.hackthemidlands.processblinders.util.CookieUtil.setCookie; +import static com.hackthemidlands.processblinders.util.UserUtil.findUserFromDatabase; + +public class LoginPage implements TemplateViewRoute { + + // HTTP POST + + public Route post = (Request request, Response response) -> { + Set params = request.queryParams(); + if (!params.containsAll(Arrays.asList("email", "password"))) { + // rs.redirect("/login"); + return "Invalid login credentials"; + } + User u = findUserFromDatabase(request.queryParams("email")); + if (u == null || !u.getPassword().equals(request.queryParams("password"))) { + return "Invalid login credentials"; + } + setCookie(response, u); + response.redirect("/orders/view"); + return "Successfully logged in as: " + u.getFirstName() + " " + u.getLastName(); + }; + + // HTTP GET + + @Override + public ModelAndView handle(Request request, Response response) { + if (UserUtil.findUserFromDatabase(getCookie(request)) != null) { + response.redirect("/orders/view"); + return new ModelAndView(new HashMap<>(), null); + } + return new ModelAndView(new HashMap<>(), "login"); + } +} diff --git a/src/main/java/com/hackthemidlands/processblinders/pages/PlaceOrderPage.java b/src/main/java/com/hackthemidlands/processblinders/pages/PlaceOrderPage.java new file mode 100644 index 0000000..d0756ab --- /dev/null +++ b/src/main/java/com/hackthemidlands/processblinders/pages/PlaceOrderPage.java @@ -0,0 +1,57 @@ +package com.hackthemidlands.processblinders.pages; + +import com.hackthemidlands.processblinders.api.OrderStatus; +import com.hackthemidlands.processblinders.api.User; +import com.hackthemidlands.processblinders.util.CookieUtil; +import com.hackthemidlands.processblinders.util.UserUtil; +import spark.*; + +import java.util.HashMap; +import java.util.Set; +import java.util.Arrays; + +import com.hackthemidlands.processblinders.util.RequestUtil; +import com.hackthemidlands.processblinders.api.Order; +import static com.hackthemidlands.processblinders.util.OrderUtil.*; + + +public class PlaceOrderPage implements TemplateViewRoute { + + @Override + public ModelAndView handle(Request request, Response response) { + User u = UserUtil.findUserFromDatabase(CookieUtil.getCookie(request)); + if (u == null) { + response.redirect("/error"); + return new ModelAndView(new HashMap<>(), null); + } + return new ModelAndView(new HashMap<>(), "orders-create"); + } + + + public Route post = (Request request, Response response) -> { + User u = UserUtil.findUserFromDatabase(CookieUtil.getCookie(request)); + if (u == null) { + response.redirect("/error"); + return ""; + } + if (!RequestUtil.checkIfAllQueryParamsArePresentAndNotNull(request, "items", "priority", "maxPrice")) { + // it means we do not have all of the complete form data, so we can send them back to the login page + response.redirect("/orders/view"); + return ""; + } + String items = request.queryParams("items"); + String[] itemsList = items.split("[\\r\\n]+"); + + Order o = Order.builder() + .shopList(itemsList) + .maxPrice(Integer.parseInt(request.queryParams("maxPrice"))) + .priority(request.queryParams("priority")) + .user(u) + .id(++Order.maxId) + .status(OrderStatus.PENDING) + .build(); + addNewOrderToDatabase(o); + response.redirect("/orders/view"); + return ""; + }; +} diff --git a/src/main/java/com/hackthemidlands/processblinders/pages/RegisterPage.java b/src/main/java/com/hackthemidlands/processblinders/pages/RegisterPage.java new file mode 100644 index 0000000..9f4c7df --- /dev/null +++ b/src/main/java/com/hackthemidlands/processblinders/pages/RegisterPage.java @@ -0,0 +1,54 @@ +package com.hackthemidlands.processblinders.pages; + +import com.hackthemidlands.processblinders.api.User; +import com.hackthemidlands.processblinders.util.RequestUtil; +import com.hackthemidlands.processblinders.util.UserUtil; +import spark.*; + +import java.util.HashMap; +import java.util.Set; + +import static com.hackthemidlands.processblinders.util.CookieUtil.getCookie; +import static com.hackthemidlands.processblinders.util.CookieUtil.setCookie; +import static com.hackthemidlands.processblinders.util.UserUtil.addNewUserToDatabase; + +public class RegisterPage implements TemplateViewRoute { + + // HTTP POST + + public Route post = (Request request, Response response) -> { + Set params = request.queryParams(); + if (!RequestUtil.checkIfAllQueryParamsArePresentAndNotNull(request, "fname", "lname", "validate", "email", "password1", "password2") || + ((RequestUtil.checkIfAllQueryParamsArePresentAndNotNull(request, "password1", "password2")) && + !request.queryParams("password1").equals(request.queryParams("password2")))) { + // it means we do not have all of the complete form data, so we can send them back to the login page + response.redirect("/register"); + return ""; + } + boolean volunteer = request.queryParams("validate").equalsIgnoreCase("I want to volunteer"); + User.maxId++; + User u = User.builder() + .firstName(request.queryParams("fname")) + .lastName(request.queryParams("lname")) + .isVolunteer(volunteer) + .email(request.queryParams("email")) + .password(request.queryParams("password1")) + .id(User.maxId) + .build(); + addNewUserToDatabase(u); + setCookie(response, u);// logs in the user + response.redirect("/orders/view"); + return ""; + }; + + // HTTP GET + + @Override + public ModelAndView handle(Request request, Response response) { + if (UserUtil.findUserFromDatabase(getCookie(request)) != null) { + response.redirect("/orders/view"); + return new ModelAndView(new HashMap<>(), null); + } + return new ModelAndView(new HashMap<>(), "/register"); + } +} diff --git a/src/main/java/com/hackthemidlands/processblinders/pages/SettingsPage.java b/src/main/java/com/hackthemidlands/processblinders/pages/SettingsPage.java new file mode 100644 index 0000000..c37a636 --- /dev/null +++ b/src/main/java/com/hackthemidlands/processblinders/pages/SettingsPage.java @@ -0,0 +1,55 @@ +package com.hackthemidlands.processblinders.pages; + +import com.hackthemidlands.processblinders.api.User; +import com.hackthemidlands.processblinders.util.RequestUtil; +import spark.*; + +import java.util.HashMap; +import java.util.Map; + +import static com.hackthemidlands.processblinders.util.CookieUtil.getCookie; +import static com.hackthemidlands.processblinders.util.CookieUtil.setCookie; +import static com.hackthemidlands.processblinders.util.UserUtil.findUserFromDatabase; +import static com.hackthemidlands.processblinders.util.UserUtil.updateUser; + +public class SettingsPage implements TemplateViewRoute { + + public Route post = (Request request, Response response) -> { + // DO CODE FOR UPDATING USER HERE + if (!RequestUtil.checkIfAllQueryParamsArePresentAndNotNull(request, "fname", "lname", "postcode", "email")) { + // it means we do not have all of the complete form data, so we can send them back to the login page + response.redirect("/settings"); + return ""; + } + + User u = findUserFromDatabase(getCookie(request)); + if (u == null) { + response.redirect("/login"); + return ""; + } + + String newName = request.queryParams("fname"); + String newSurname = request.queryParams("lname"); + String newEmail = request.queryParams("email"); + String newPostcode = request.queryParams("postcode"); + + User u2 = User.builder().firstName(newName).lastName(newSurname).email(newEmail).postcode(newPostcode).isVolunteer(u.isVolunteer()).id(u.getId()).password(u.getPassword()).build(); + updateUser(u2); + setCookie(response, u2); + response.redirect("/dev/protected"); + return ""; + }; + + @Override + public ModelAndView handle(Request request, Response response) { + Map models = new HashMap<>(); + User u = findUserFromDatabase(getCookie(request)); + if (u == null) { + response.redirect("/login"); + return new ModelAndView(new HashMap<>(), null); + } + models.put("user", u); + + return new ModelAndView(models, "settings"); + } +} diff --git a/src/main/java/com/hackthemidlands/processblinders/pages/ViewOrdersPage.java b/src/main/java/com/hackthemidlands/processblinders/pages/ViewOrdersPage.java new file mode 100644 index 0000000..5960b59 --- /dev/null +++ b/src/main/java/com/hackthemidlands/processblinders/pages/ViewOrdersPage.java @@ -0,0 +1,40 @@ +package com.hackthemidlands.processblinders.pages; + +import com.hackthemidlands.processblinders.api.User; +import com.hackthemidlands.processblinders.util.CookieUtil; +import com.hackthemidlands.processblinders.util.OrderUtil; +import com.hackthemidlands.processblinders.util.UserUtil; +import spark.ModelAndView; +import spark.Request; +import spark.Response; +import spark.TemplateViewRoute; + +import java.util.HashMap; +import java.util.Map; + +public class ViewOrdersPage implements TemplateViewRoute { + + @Override + public ModelAndView handle(Request request, Response response) { + User u = UserUtil.findUserFromDatabase(CookieUtil.getCookie(request)); + if (u == null) + return new ErrorPage().handle(request, response); // should be redirected anyway before this point is hit + HashMap models = new HashMap<>(); + models.put("user", u); + if (u.isVolunteer()) { + return volunteerPage(request, response, models); + } else { + return userPage(request, response, models); + } + } + + public ModelAndView volunteerPage(Request request, Response response, Map models) { + models.put("orders", OrderUtil.getAllPendingOrders()); + return new ModelAndView(models, "orders-view-volunteer"); + } + + public ModelAndView userPage(Request request, Response response, Map models) { + models.put("orders", OrderUtil.getAllOrdersForUser((User)models.get("user"))); + return new ModelAndView(models, "orders-view-user"); + } +} diff --git a/src/main/java/com/hackthemidlands/processblinders/util/CookieUtil.java b/src/main/java/com/hackthemidlands/processblinders/util/CookieUtil.java new file mode 100644 index 0000000..8e02bc8 --- /dev/null +++ b/src/main/java/com/hackthemidlands/processblinders/util/CookieUtil.java @@ -0,0 +1,21 @@ +package com.hackthemidlands.processblinders.util; + +import com.hackthemidlands.processblinders.api.User; +import spark.Request; +import spark.Response; + +public class CookieUtil { + + public static void setCookie(Response response, User user) { + response.cookie("/", "email", user.getEmail(), -1, false); + } + + public static boolean hasCookie(Request request) { + return request.cookie("email") != null; + } + + public static String getCookie(Request request) { + return request.cookie("email"); + } + +} diff --git a/src/main/java/com/hackthemidlands/processblinders/util/FilterUtil.java b/src/main/java/com/hackthemidlands/processblinders/util/FilterUtil.java new file mode 100644 index 0000000..1821935 --- /dev/null +++ b/src/main/java/com/hackthemidlands/processblinders/util/FilterUtil.java @@ -0,0 +1,63 @@ +package com.hackthemidlands.processblinders.util; + +import com.hackthemidlands.processblinders.api.User; +import spark.Filter; +import spark.Request; +import spark.Response; + +import static com.hackthemidlands.processblinders.util.CookieUtil.*; +import static com.hackthemidlands.processblinders.util.UserUtil.*; + +public class FilterUtil { + + // WARNING! THIS WILL ONLY REDIRECT THE USER, YOU WILL STILL NEED TO DDO A VALIDITY CHECK + // AND RETURN ""; IN YOUR PAGE CLASS. + + public static Filter requiresLogin = (Request request, Response response) -> { + if (hasCookie(request)) { + String cookie = getCookie(request); + User user = UserUtil.findUserFromDatabase(cookie); + if (user != null) { + getLoggedInUsers().put(user.getEmail(), user); + } else { + response.redirect("/login"); + } + } else { + response.redirect("/login"); + } + }; + + // WARNING! YOU NEED TO PUT A requiresLogin before you use this filter as it could work unexpectedly! + + public static Filter volunteerOnly = (Request request, Response response) -> { + if (!hasCookie(request)) { + response.redirect("/login"); + } else { + String cookie = getCookie(request); + User user = UserUtil.findUserFromDatabase(cookie); + if (user == null) { + response.redirect("/login"); + } else { + if (!user.isVolunteer()) { + response.redirect("/error"); + } + } + } + }; + + public static Filter clientOnly = (Request request, Response response) -> { + if (!hasCookie(request)) { + response.redirect("/login"); + } else { + String cookie = getCookie(request); + User user = UserUtil.findUserFromDatabase(cookie); + if (user == null) { + response.redirect("/login"); + } else { + if (user.isVolunteer()) { + response.redirect("/error"); + } + } + } + }; +} diff --git a/src/main/java/com/hackthemidlands/processblinders/util/OrderUtil.java b/src/main/java/com/hackthemidlands/processblinders/util/OrderUtil.java new file mode 100644 index 0000000..d2901d0 --- /dev/null +++ b/src/main/java/com/hackthemidlands/processblinders/util/OrderUtil.java @@ -0,0 +1,74 @@ +package com.hackthemidlands.processblinders.util; + +import com.hackthemidlands.processblinders.api.Order; +import com.hackthemidlands.processblinders.api.OrderStatus; +import com.hackthemidlands.processblinders.api.User; +import lombok.Getter; + + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class OrderUtil { + + @Getter + private static final List allValidOrders = new ArrayList<>(); + + public static boolean addNewOrderToDatabase(Order order) { + if (findOrderFromDatabase(order.getID()) != null) { + return false; + } + allValidOrders.add(order); + return true; + } + + public static void commitToOrder(){ + + } + + public static Order findOrderFromDatabase(int id) { + return allValidOrders.stream().filter(o -> o.getID() == id).findFirst().orElse(null); + } + + public static List getAllPendingOrders() { + return getAllOrdersWithStatus(OrderStatus.PENDING); + } + + public static List getAllOrdersWithStatus(OrderStatus status) { + return allValidOrders.stream().filter(o -> status.equals(o.getStatus())).collect(Collectors.toList()); + } + + public static boolean isPending(Order order) { + return order.getStatus().getNum() == 0; + } + + public static boolean clearVolunteer(int orderId, User u) { + if (u == null) return false; + Order o = findOrderFromDatabase(orderId); + if (o == null || o.getVolunteer() != u) return false; + o.setStatus(OrderStatus.PENDING); + o.setVolunteer(null); + return true; + } + + public static List getAllOrdersForUser(User u) { + return allValidOrders.stream().filter(o -> o.getUser().equals(u)).collect(Collectors.toList()); + } + + public static boolean setVolunteer(Order order, User u) { + if (order == null) return false; + if (u == null) { + order.setVolunteer(null); + order.setStatus(OrderStatus.PENDING); + } else { + // TODO: Extend logic to not allow people to claim an already claimed order... + if (!isPending(order)) { + return false; // can't assign. + } + order.setVolunteer(u); + order.setStatus(OrderStatus.ACCEPTED); + } + return true; // successful + } +} diff --git a/src/main/java/com/hackthemidlands/processblinders/util/RequestUtil.java b/src/main/java/com/hackthemidlands/processblinders/util/RequestUtil.java new file mode 100644 index 0000000..a434b88 --- /dev/null +++ b/src/main/java/com/hackthemidlands/processblinders/util/RequestUtil.java @@ -0,0 +1,19 @@ +package com.hackthemidlands.processblinders.util; + +import spark.Request; + +import java.util.Arrays; +import java.util.Set; + +public class RequestUtil { + + public static boolean checkIfAllQueryParamsArePresentAndNotNull(Request request, String... toCheck) { + if (!checkIfAllQueryParamsArePresent(request.queryParams(), toCheck)) return false; + for (String s : toCheck) if (request.queryParams(s) == null || request.queryParams(s).isEmpty()) return false; + return true; + } + + public static boolean checkIfAllQueryParamsArePresent(Set params, String... toCheck) { + return params.containsAll(Arrays.asList(toCheck)); + } +} diff --git a/src/main/java/com/hackthemidlands/processblinders/util/UserUtil.java b/src/main/java/com/hackthemidlands/processblinders/util/UserUtil.java new file mode 100644 index 0000000..079d286 --- /dev/null +++ b/src/main/java/com/hackthemidlands/processblinders/util/UserUtil.java @@ -0,0 +1,49 @@ +package com.hackthemidlands.processblinders.util; + +import com.hackthemidlands.processblinders.api.User; +import lombok.Getter; +import org.eclipse.jetty.websocket.servlet.UpgradeHttpServletRequest; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class UserUtil { + + @Getter + private static final Map loggedInUsers = new HashMap<>(); + + @Getter + private static final List allValidUsers = new ArrayList<>(); + + + public static boolean addNewUserToDatabase(User user) { + if (findUserFromDatabase(user.getEmail()) != null) { + return false; + } + allValidUsers.add(user); + return true; + } + + public static void updateUser(User user){ + allValidUsers.forEach(i -> { + if(i.getId() == user.getId()) { + i.setFirstName(user.getFirstName()); + i.setLastName(user.getLastName()); + i.setEmail(user.getEmail()); + i.setPassword(user.getPassword()); + i.setPostcode(user.getPostcode()); + i.setVolunteer(user.isVolunteer()); + } + }); + } + + public static User findUserFromDatabase(String email) { + return allValidUsers.stream().filter(u -> u.getEmail().equalsIgnoreCase(email)).findFirst().orElse(null); + } + + public static boolean isLoggedIn(User user) { + return loggedInUsers.containsValue(user); + } +} diff --git a/src/main/resources/public/style.css b/src/main/resources/public/style.css new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/public/tos.html b/src/main/resources/public/tos.html new file mode 100644 index 0000000..989fec4 --- /dev/null +++ b/src/main/resources/public/tos.html @@ -0,0 +1,13 @@ + + + + + Terms of Service + + +

TERMS OF SERVICE

+

By using this service you agree to the following terms:

+

1. You (the end user) aren't going to misuse the service for illegal or immoral activities... +
2. more boring legal stuff

+ + \ No newline at end of file diff --git a/src/main/resources/templates/error.html b/src/main/resources/templates/error.html new file mode 100644 index 0000000..48beeab --- /dev/null +++ b/src/main/resources/templates/error.html @@ -0,0 +1,19 @@ + + + + + Error + + + + + +

Sorry, you can't access this page

+

Login here

+ + \ No newline at end of file diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html new file mode 100644 index 0000000..1be4dc3 --- /dev/null +++ b/src/main/resources/templates/index.html @@ -0,0 +1,85 @@ + + +HelpTheMidlands + + + + + + + + + + +
+
+ HELP THE MIDLANDS +
+
+ +
+

ABOUT THIS PLATFORM

+

We're all in this together

+

HelpTheMidlands is an easy to use web application designed to facilitate communication between the people who + need support during these difficult times and the volunteers. + We created an intuitive interface that enables making grocery order for people who are self-isolating or unable + to go grocery shopping due to the high risk-exposure. + Volunteers can also easily view orders that have been made from people around them and choose which ones they + are able to help with. +

+
+
+

You can register as a volunteer or a supportee using just your name, an + email address and a password.


+
+ +
+

Volunteers are extremely important in the fight against the pandemic. Be part of the team !

+
+
+
+ +
+

Powered by the ProcessBlinders

+

By creating an account on this website you agree to our Terms of Service

+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/main.html b/src/main/resources/templates/login.html similarity index 52% rename from src/main/resources/templates/main.html rename to src/main/resources/templates/login.html index 91a1cf3..fd156a1 100644 --- a/src/main/resources/templates/main.html +++ b/src/main/resources/templates/login.html @@ -1,28 +1,7 @@ - - Volunteers + Login +

Who are we and what is our mission ? Find out here

Login


-
+
-
+





-

Don't have an account yet? Register here

+

Don't have an account yet? Register here

\ No newline at end of file diff --git a/src/main/resources/templates/makeAccount.html b/src/main/resources/templates/makeAccount.html deleted file mode 100644 index e3c012a..0000000 --- a/src/main/resources/templates/makeAccount.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - Register - - - - - - - -
-

Register


-
-
-
-
-


- - -
-
- - \ No newline at end of file diff --git a/src/main/resources/templates/orders-create.html b/src/main/resources/templates/orders-create.html new file mode 100644 index 0000000..dabfd4e --- /dev/null +++ b/src/main/resources/templates/orders-create.html @@ -0,0 +1,55 @@ + + + + + + Register + + + + + + +
+

Order


+
+
+ + + + + + + +


+ + +
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/orders-view-order.html b/src/main/resources/templates/orders-view-order.html new file mode 100644 index 0000000..c980322 --- /dev/null +++ b/src/main/resources/templates/orders-view-order.html @@ -0,0 +1,10 @@ + + + + + Place new order: + + +

View an order!

+ + \ No newline at end of file diff --git a/src/main/resources/templates/orders-view-user.html b/src/main/resources/templates/orders-view-user.html new file mode 100644 index 0000000..bf576e6 --- /dev/null +++ b/src/main/resources/templates/orders-view-user.html @@ -0,0 +1,94 @@ + + + + + + Welcome back ! + + + + + + + +

Welcome back to the user page!

+
+ + +
+
+ +
+
+

Orders


+
+ +

+
+
+

+
+
+

+
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/orders-view-volunteer.html b/src/main/resources/templates/orders-view-volunteer.html new file mode 100644 index 0000000..9f27edf --- /dev/null +++ b/src/main/resources/templates/orders-view-volunteer.html @@ -0,0 +1,53 @@ + + + + + Welcome back ! + + + + + +

Welcome back to the volunteer page !

+
+ + +
+ +
+

Available orders:



+
+

+

+
Items: +
+

+
+ +

+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/placeOrder.html b/src/main/resources/templates/placeOrder.html deleted file mode 100644 index 566549b..0000000 --- a/src/main/resources/templates/placeOrder.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - Title - - - - - \ No newline at end of file diff --git a/src/main/resources/templates/register.html b/src/main/resources/templates/register.html new file mode 100644 index 0000000..57ea83f --- /dev/null +++ b/src/main/resources/templates/register.html @@ -0,0 +1,65 @@ + + + + Register + + + + + + + +
+

Register


+
+
+
+
+
+
+


+ + +

+
+

Back to login

+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/settings.html b/src/main/resources/templates/settings.html new file mode 100644 index 0000000..87a4614 --- /dev/null +++ b/src/main/resources/templates/settings.html @@ -0,0 +1,27 @@ + + + + + Settings + + + + + +

Edit your account

+
+
+
+
+
+ +

+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/support.html b/src/main/resources/templates/support.html deleted file mode 100644 index 96981dd..0000000 --- a/src/main/resources/templates/support.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - Document - - - - - - - - - \ No newline at end of file diff --git a/src/main/resources/templates/volunteer.html b/src/main/resources/templates/volunteer.html deleted file mode 100644 index 9596126..0000000 --- a/src/main/resources/templates/volunteer.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - Volunteer - - -

Login


-
-
-

Don't have an account yet ? Register here

- - \ No newline at end of file