diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7fa3aae --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +# System Files + +.DS_Store + +# IDE specific files + +.idea +.vscode +*.iml + +# Maven files + +/target +*/test +.classpath +.project +.settings + +# Utility files +src/main/resources/config.json \ No newline at end of file diff --git a/README.md b/README.md index 8d9fc0c..e916309 100644 --- a/README.md +++ b/README.md @@ -1 +1,9 @@ -# quest_store_tl \ No newline at end of file +# Quest Store TML Production + +#### __Dear Codecoolers__, +The Creepy Guy, a Supreme Necromancer of Codecool Kingdom, has a trouble with economic management of his kingdom. +Incredible expansion of Codecool caused that's really hard to keep distribution national currency (Coolcoins) in analogy system, +based on cash contribution, so he hasn't enough time to creep his mentors... He choose and invoke. +You - the best programmers in the Universe of Code - to implement application, which will help him and mentors with coolcoins managment. + +![Login Page Sample](src/main/resources/media/images/login-page-sample.png) \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..6c489f1 --- /dev/null +++ b/pom.xml @@ -0,0 +1,135 @@ + + 4.0.0 + com.codecool.quest_store + quest_store_tl + jar + 1.0-SNAPSHOT + quest_store_tl + http://maven.apache.org + + + 1.8 + 1.8 + UTF-8 + + + + + + junit + junit + 4.12 + test + + + + org.postgresql + postgresql + 42.2.5 + + + + + commons-dbcp + commons-dbcp + 1.4 + + + + + com.google.code.gson + gson + 2.8.5 + + + + com.googlecode.json-simple + json-simple + 1.1.1 + + + + + org.flywaydb + flyway-core + 5.2.4 + + + + org.jtwig + jtwig-core + 5.87.0.RELEASE + + + + org.mockito + mockito-core + 2.11.0 + + + + + org.slf4j + slf4j-simple + 1.8.0-beta4 + + + + + org.slf4j + slf4j-api + 1.8.0-beta4 + + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.0 + + + + true + lib/ + com.codecool.quest_store.main.Main + + + + + + + org.codehaus.mojo + exec-maven-plugin + 1.2.1 + + com.codecool.quest_store.main.Main + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-dependencies + package + + copy-dependencies + + + ${project.build.directory} + false + true + + + + + + + + \ No newline at end of file diff --git a/src/main/java/com/codecool/quest_store/controllers/ArtifactsController.java b/src/main/java/com/codecool/quest_store/controllers/ArtifactsController.java new file mode 100644 index 0000000..8b3de79 --- /dev/null +++ b/src/main/java/com/codecool/quest_store/controllers/ArtifactsController.java @@ -0,0 +1,61 @@ +package com.codecool.quest_store.controllers; + +import com.codecool.quest_store.model.Item; +import com.codecool.quest_store.model.User; +import com.codecool.quest_store.service.ArtifactsService; +import com.codecool.quest_store.service.ServiceUtility; +import com.codecool.quest_store.service.UserService; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import org.jtwig.JtwigModel; +import org.jtwig.JtwigTemplate; + +import java.io.IOException; +import java.util.List; + +public class ArtifactsController implements HttpHandler { + + private static final String ARTIFACT_CONTEXT_PATH = "/artifacts"; + private ArtifactsService artifactsService; + private UserService userService; + + public ArtifactsController() { + this.artifactsService = new ArtifactsService(); + this.userService = new UserService(); + } + + @Override + public void handle(HttpExchange httpExchange) throws IOException { + + User activeUser = userService.getUserByCookie(httpExchange.getRequestHeaders().get("Cookie").get(0)); + + String method = httpExchange.getRequestMethod(); + if (method.equals("GET")){ + renderArtifacts(httpExchange, activeUser); + } else if (method.equals("POST")){ + String response = artifactsService.respondToPostMethod(httpExchange, activeUser); + ServiceUtility.redirectToContext(httpExchange, response, ARTIFACT_CONTEXT_PATH); + } + } + + private void renderArtifacts(HttpExchange httpExchange, User user) throws IOException { + List normalArtifacts = artifactsService.getNormalArtifacts(); + List magicArtifacts = artifactsService.getMagicArtifacts(); + int discount = artifactsService.getDiscount(); + + + JtwigTemplate template; + template = JtwigTemplate.classpathTemplate("templates/artifacts.twig"); + + JtwigModel model = JtwigModel.newModel(); + + model.with("normal_artifacts", normalArtifacts); + model.with("magic_artifacts", magicArtifacts); + model.with("discount", discount); + model.with("user", user); + + String response = template.render(model); + + ServiceUtility.sendResponse(httpExchange, response); + } +} diff --git a/src/main/java/com/codecool/quest_store/controllers/CreepyGuyController.java b/src/main/java/com/codecool/quest_store/controllers/CreepyGuyController.java new file mode 100644 index 0000000..03ab6c5 --- /dev/null +++ b/src/main/java/com/codecool/quest_store/controllers/CreepyGuyController.java @@ -0,0 +1,82 @@ +package com.codecool.quest_store.controllers; + +import java.util.Map; + +import java.io.IOException; + +import org.jtwig.JtwigModel; +import org.jtwig.JtwigTemplate; + +import com.codecool.quest_store.model.User; +import com.codecool.quest_store.model.UserDefaultPhoto; + +import com.codecool.quest_store.service.CreepyGuyService; +import com.codecool.quest_store.service.EmployeeService; +import com.codecool.quest_store.service.ServiceUtility; +import com.codecool.quest_store.service.UserService; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; + +public class CreepyGuyController implements HttpHandler { + + private EmployeeService employeeService; + private CreepyGuyService creepyGuyService; + private UserService userService; + + public CreepyGuyController() { + employeeService = new EmployeeService(); + creepyGuyService = new CreepyGuyService(); + userService = new UserService(); + } + + @Override + public void handle(HttpExchange httpExchange) throws IOException { + + String method = httpExchange.getRequestMethod(); + + if (method.equals("GET")) { + userService.getUserByCookie(httpExchange.getRequestHeaders().get("Cookie").get(0)); + renderCreepyGuy(httpExchange); + } + + if (method.equals("POST")) { + handlePOST(httpExchange); + } + } + + private void handlePOST(HttpExchange httpExchange) throws IOException { + Map inputs = ServiceUtility.getPOSTInputs(httpExchange); + + for (Map.Entry entry : inputs.entrySet()) { + + if (entry.getKey().contains("recruit-mentor-button")) { + handleCreateMentor(inputs); + + } else if (entry.getKey().contains("create-room-button")) { + handleCreateRoom(inputs); + } + } + ServiceUtility.redirectToContext(httpExchange, "", "/creepy-guy"); + } + + private void renderCreepyGuy(HttpExchange httpExchange) throws IOException { + JtwigTemplate template = JtwigTemplate.classpathTemplate("templates/creepy-guy.twig"); + JtwigModel model = JtwigModel.newModel(); + String response = template.render(model); + ServiceUtility.sendResponse(httpExchange, response); + } + + private void handleCreateMentor(Map inputs) { + String name = inputs.get("mentor-name"); + String surname = inputs.get("mentor-surname"); + String email = inputs.get("mentor-email"); + int userType = userService.getUserTypes().get("Mentor"); + employeeService.createUser(name, surname, email, userType, UserDefaultPhoto.MENTOR); + } + + private void handleCreateRoom(Map inputs) { + String name = inputs.get("room-name"); + creepyGuyService.createRoom(name); + } +} \ No newline at end of file diff --git a/src/main/java/com/codecool/quest_store/controllers/LoginController.java b/src/main/java/com/codecool/quest_store/controllers/LoginController.java new file mode 100644 index 0000000..faa27cc --- /dev/null +++ b/src/main/java/com/codecool/quest_store/controllers/LoginController.java @@ -0,0 +1,84 @@ +package com.codecool.quest_store.controllers; +import com.codecool.quest_store.model.User; + +import com.codecool.quest_store.service.LoginService; +import com.codecool.quest_store.service.ServiceUtility; +import com.codecool.quest_store.service.UserService; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; + +import org.jtwig.JtwigModel; +import org.jtwig.JtwigTemplate; + +import java.io.*; +import java.net.HttpCookie; +import java.util.Map; + +public class LoginController implements HttpHandler { + + private LoginService login; + private ServiceUtility utility; + private UserService userService; + private static final int STUDENT = 1; + private static final int MENTOR = 2; + private static final int CREEPUGUY = 3; + + public LoginController() { + login = new LoginService(); + utility = new ServiceUtility(); + userService = new UserService(); + } + + @Override + public void handle(HttpExchange httpExchange) throws IOException { + String response = ""; + String method = httpExchange.getRequestMethod(); + System.out.println(method); + + if (method.equals("GET")) { + JtwigTemplate template = JtwigTemplate.classpathTemplate("templates/login.twig"); + JtwigModel model = JtwigModel.newModel(); + + response = template.render(model); + httpExchange.sendResponseHeaders(200, response.getBytes().length); + + userService.deleteSession(httpExchange.getRequestHeaders().get("Cookie").get(0)); + } + + if (method.equals("POST")) { + + InputStreamReader isr = new InputStreamReader(httpExchange.getRequestBody(), "utf-8"); + BufferedReader br = new BufferedReader(isr); + String formData = br.readLine(); + Map inputs = utility.parseData(formData, ServiceUtility.AND); + + String nextUrl = ""; + + User user = login.getUser(inputs.get("name").toString(), inputs.get("password").toString()); + int userType = user.getTypeId(); + + if (!user.equals(null) && userType == STUDENT) { + nextUrl = "http://localhost:8000/student"; + } + if (!user.equals(null) && userType == MENTOR) { + nextUrl = "http://localhost:8000/mentor"; + } + if (!user.equals(null) && userType == CREEPUGUY) { + nextUrl = "http://localhost:8000/creepy-guy"; + } + + int session = login.generateNewSessionId(); + + login.createSession(session, user.getId()); + + httpExchange.getResponseHeaders().add("Location", nextUrl); + httpExchange.getResponseHeaders().add("Set-Cookie", + new HttpCookie("session", Integer.toString(session)).toString()); + + httpExchange.sendResponseHeaders(302, response.getBytes().length); + } + OutputStream os = httpExchange.getResponseBody(); + os.write(response.getBytes()); + os.close(); + } +} diff --git a/src/main/java/com/codecool/quest_store/controllers/MentorController.java b/src/main/java/com/codecool/quest_store/controllers/MentorController.java new file mode 100644 index 0000000..48c0f0b --- /dev/null +++ b/src/main/java/com/codecool/quest_store/controllers/MentorController.java @@ -0,0 +1,118 @@ +package com.codecool.quest_store.controllers; + +import java.util.Map; + +import java.io.IOException; + +import org.jtwig.JtwigModel; +import org.jtwig.JtwigTemplate; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; + +import com.codecool.quest_store.service.EmployeeService; +import com.codecool.quest_store.service.ItemService; +import com.codecool.quest_store.service.MentorService; +import com.codecool.quest_store.service.ServiceUtility; +import com.codecool.quest_store.service.UserService; + +import com.codecool.quest_store.model.UserDefaultPhoto; + +public class MentorController implements HttpHandler { + + private EmployeeService employeeService; + private MentorService mentorService; + private UserService userService; + private ItemService itemService; + + public MentorController() { + employeeService = new EmployeeService(); + mentorService = new MentorService(); + userService = new UserService(); + itemService = new ItemService(); + } + + @Override + public void handle(HttpExchange httpExchange) throws IOException { + + String method = httpExchange.getRequestMethod(); + + if (method.equals("GET")) { + userService.getUserByCookie(httpExchange.getRequestHeaders().get("Cookie").get(0)); + renderMentor(httpExchange); + } + + if (method.equals("POST")) { + handlePOST(httpExchange); + } + } + + private void handlePOST(HttpExchange httpExchange) throws IOException { + Map inputs = ServiceUtility.getPOSTInputs(httpExchange); + + for (Map.Entry entry : inputs.entrySet()) { + + if (entry.getKey().contains("recruit-student-button")) { + handleCreateCodecooler(inputs); + + } else if (entry.getKey().contains("create-quest-button")) { + handleCreateQuest(inputs); + + } else if (entry.getKey().contains("create-artifact-button")) { + handleCreateArtifact(inputs); + } + } + + ServiceUtility.redirectToContext(httpExchange, "", "/mentor"); + } + + private void renderMentor(HttpExchange httpExchange) throws IOException { + JtwigTemplate template = JtwigTemplate.classpathTemplate("templates/mentor.twig"); + JtwigModel model = JtwigModel.newModel(); + String response = template.render(model); + ServiceUtility.sendResponse(httpExchange, response); + } + + private void handleCreateCodecooler(Map inputs) { + String name = inputs.get("cc-name"); + String surname = inputs.get("cc-surname"); + String email = inputs.get("cc-email"); + int userType = userService.getUserTypes().get("Codecooler"); + employeeService.createUser(name, surname, email, userType, UserDefaultPhoto.CODECOOLER); + + } + + private void handleCreateQuest(Map inputs) { + String title = inputs.get("quest-name"); + String task = inputs.get("quest-task"); + int price = Integer.parseInt(inputs.get("quest-coins")); + int itemType = getQuestTypeFromInput(inputs); + mentorService.createItem(title, task, price, itemType); + } + + private int getQuestTypeFromInput(Map inputs) { + String itemType = inputs.get("quest-type-choice"); + if (itemType.equals("Basic")) { + return itemService.getItemTypes().get("Basic"); + } else { + return itemService.getItemTypes().get("Extra"); + } + } + + private void handleCreateArtifact(Map inputs) { + String title = inputs.get("artifact-name"); + String description = inputs.get("artifact-description"); + int price = Integer.parseInt(inputs.get("artifact-coins")); + int itemType = getArtifactTypeFromInput(inputs); + mentorService.createItem(title, description, price, itemType); + } + + private int getArtifactTypeFromInput(Map inputs) { + String itemType = inputs.get("artifact-type-choice"); + if (itemType.equals("Normal")) { + return itemService.getItemTypes().get("Normal"); + } else { + return itemService.getItemTypes().get("Magic"); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/codecool/quest_store/controllers/MentorsController.java b/src/main/java/com/codecool/quest_store/controllers/MentorsController.java new file mode 100644 index 0000000..057322d --- /dev/null +++ b/src/main/java/com/codecool/quest_store/controllers/MentorsController.java @@ -0,0 +1,53 @@ +package com.codecool.quest_store.controllers; + +import java.util.List; + +import java.io.IOException; + +import org.jtwig.JtwigModel; +import org.jtwig.JtwigTemplate; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; + +import com.codecool.quest_store.model.User; + +import com.codecool.quest_store.service.EmployeeService; +import com.codecool.quest_store.service.ServiceUtility; +import com.codecool.quest_store.service.UserService; + +public class MentorsController implements HttpHandler { + + private UserService userService; + private EmployeeService employeeService; + + public MentorsController() { + userService = new UserService(); + employeeService = new EmployeeService(); + } + + @Override + public void handle(HttpExchange httpExchange) throws IOException { + + String method = httpExchange.getRequestMethod(); + + if (method.equals("GET")) { + userService.getUserByCookie(httpExchange.getRequestHeaders().get("Cookie").get(0)); + renderMentor(httpExchange); + } + } + + private void createGETModel(JtwigModel model) { + int mentorType = userService.getUserTypes().get("Mentor"); + List mentors = employeeService.getUsers(mentorType); + model.with("mentors", mentors); + } + + private void renderMentor(HttpExchange httpExchange) throws IOException { + JtwigTemplate template = JtwigTemplate.classpathTemplate("templates/mentors.twig"); + JtwigModel model = JtwigModel.newModel(); + createGETModel(model); + String response = template.render(model); + ServiceUtility.sendResponse(httpExchange, response); + } +} \ No newline at end of file diff --git a/src/main/java/com/codecool/quest_store/controllers/QuestsController.java b/src/main/java/com/codecool/quest_store/controllers/QuestsController.java new file mode 100644 index 0000000..f9da524 --- /dev/null +++ b/src/main/java/com/codecool/quest_store/controllers/QuestsController.java @@ -0,0 +1,59 @@ +package com.codecool.quest_store.controllers; + +import com.codecool.quest_store.dao.DaoException; +import com.codecool.quest_store.model.Item; +import com.codecool.quest_store.model.User; +import com.codecool.quest_store.service.QuestService; +import com.codecool.quest_store.service.ServiceUtility; +import com.codecool.quest_store.service.UserService; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import org.jtwig.JtwigModel; +import org.jtwig.JtwigTemplate; + +import java.io.IOException; +import java.util.List; + +public class QuestsController implements HttpHandler { + + private static final String QUEST_CONTEXT_PATH = "/quests"; + private QuestService questService; + private UserService userService; + private User activeUser; + + public QuestsController(){ + this.questService = new QuestService(); + this.userService = new UserService(); + } + + @Override + public void handle(HttpExchange httpExchange) throws IOException { + + User activeUser = userService.getUserByCookie(httpExchange.getRequestHeaders().get("Cookie").get(0)); + + String method = httpExchange.getRequestMethod(); + if (method.equals("GET")){ + renderQuests(httpExchange, activeUser); + } else if (method.equals("POST")){ + String response = questService.respondToPostMethod(httpExchange, activeUser); + ServiceUtility.redirectToContext(httpExchange, response, QUEST_CONTEXT_PATH); + } + } + + private void renderQuests(HttpExchange httpExchange, User user) throws IOException{ + List basicQuests = questService.getBasicQuests(); + List extraQuests = questService.getExtraQuests(); + + JtwigTemplate template = JtwigTemplate.classpathTemplate("templates/quests.twig"); + JtwigModel model = JtwigModel.newModel(); + + model.with("basic_quests", basicQuests); + model.with("extra_quests", extraQuests); + model.with("user", user); + + String response = template.render(model); + + ServiceUtility.sendResponse(httpExchange, response); + } +} + diff --git a/src/main/java/com/codecool/quest_store/controllers/Static.java b/src/main/java/com/codecool/quest_store/controllers/Static.java new file mode 100644 index 0000000..4752426 --- /dev/null +++ b/src/main/java/com/codecool/quest_store/controllers/Static.java @@ -0,0 +1,70 @@ +package com.codecool.quest_store.controllers; + +import com.codecool.quest_store.helpers.MimeTypeResolver; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.URI; +import java.net.URL; + +public class Static implements HttpHandler { + @Override + public void handle(HttpExchange httpExchange) throws IOException { + + // get file path from url + URI uri = httpExchange.getRequestURI(); + + String path = "." + uri.getPath(); + + // get file from resources folder, see: https://www.mkyong.com/java/java-read-a-file-from-resources-folder/ + ClassLoader classLoader = getClass().getClassLoader(); + URL fileURL = classLoader.getResource(path); + + OutputStream os = httpExchange.getResponseBody(); + + if (fileURL == null) { + // Object does not exist or is not a file: reject with 404 error. + send404(httpExchange); + } else { + // Object exists and is a file: accept with response code 200. + sendFile(httpExchange, fileURL); + } + + } + + private void send404(HttpExchange httpExchange) throws IOException { + String response = "404 (Not Found)\n"; + httpExchange.sendResponseHeaders(404, response.length()); + OutputStream os = httpExchange.getResponseBody(); + os.write(response.toString().getBytes()); + os.close(); + } + + private void sendFile(HttpExchange httpExchange, URL fileURL) throws IOException { + // get the file + File file = new File(fileURL.getFile()); + // we need to find out the mime type of the file, see: https://en.wikipedia.org/wiki/Media_type + MimeTypeResolver resolver = new MimeTypeResolver(file); + String mime = resolver.getMimeType(); + + httpExchange.getResponseHeaders().set("Content-Type", mime); + httpExchange.sendResponseHeaders(200, 0); + + OutputStream os = httpExchange.getResponseBody(); + + // send the file + FileInputStream fs = new FileInputStream(file); + final byte[] buffer = new byte[0x10000]; + int count = 0; + while ((count = fs.read(buffer)) >= 0) { + os.write(buffer,0,count); + } + os.close(); + } + + +} diff --git a/src/main/java/com/codecool/quest_store/controllers/StudentController.java b/src/main/java/com/codecool/quest_store/controllers/StudentController.java new file mode 100644 index 0000000..37e8679 --- /dev/null +++ b/src/main/java/com/codecool/quest_store/controllers/StudentController.java @@ -0,0 +1,58 @@ +package com.codecool.quest_store.controllers; + +import com.codecool.quest_store.model.Item; +import com.codecool.quest_store.model.User; +import com.codecool.quest_store.service.ServiceUtility; +import com.codecool.quest_store.service.UserService; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import org.jtwig.JtwigModel; +import org.jtwig.JtwigTemplate; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.List; + +public class StudentController implements HttpHandler { + + private UserService userService; + + + public StudentController() { + userService = new UserService(); + } + + @Override + public void handle(HttpExchange httpExchange) throws IOException { + String method = httpExchange.getRequestMethod(); + System.out.println(method); + User student = userService.getUserByCookie(httpExchange.getRequestHeaders().get("Cookie").get(0)); + String response = ""; + if(method.equals("GET")) { + renderUser(httpExchange, student); + } + } + + private void renderUser(HttpExchange httpExchange, User student) throws IOException { + + JtwigTemplate template = JtwigTemplate.classpathTemplate("templates/student.twig"); + JtwigModel model = JtwigModel.newModel(); + + model.with("name", student.getName()); + model.with("surname", student.getSurname()); + model.with("email", student.getEmail()); + model.with("phone", student.getPhoneNumber()); + model.with("wallet", userService.getBalance(student)); + + List artifacts = userService.getUserArtifacts(student.getId()); + List basicQuests = userService.getUserBasicQuests(student.getId()); + List extraQuests = userService.getUserExtraQuests(student.getId()); + + model.with("artifacts", artifacts); + model.with("basic_quests", basicQuests); + model.with("extra_quests", extraQuests); + + String response = template.render(model); + ServiceUtility.sendResponse(httpExchange, response); + } +} \ No newline at end of file diff --git a/src/main/java/com/codecool/quest_store/controllers/StudentsController.java b/src/main/java/com/codecool/quest_store/controllers/StudentsController.java new file mode 100644 index 0000000..b9b543f --- /dev/null +++ b/src/main/java/com/codecool/quest_store/controllers/StudentsController.java @@ -0,0 +1,54 @@ +package com.codecool.quest_store.controllers; + +import java.util.List; + +import java.io.IOException; + +import org.jtwig.JtwigModel; +import org.jtwig.JtwigTemplate; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; + +import com.codecool.quest_store.model.User; + +import com.codecool.quest_store.service.EmployeeService; +import com.codecool.quest_store.service.ServiceUtility; +import com.codecool.quest_store.service.UserService; + +public class StudentsController implements HttpHandler { + + private UserService userService; + private EmployeeService employeeService; + + public StudentsController() { + userService = new UserService(); + employeeService = new EmployeeService(); + } + + @Override + public void handle(HttpExchange httpExchange) throws IOException { + + String method = httpExchange.getRequestMethod(); + + if (method.equals("GET")) { + userService.getUserByCookie(httpExchange.getRequestHeaders().get("Cookie").get(0)); + renderCodecoolers(httpExchange); + } + } + + private void createGETModel(JtwigModel model) { + int codecoolerType = userService.getUserTypes().get("Codecooler"); + List codecoolers = employeeService.getUsers(codecoolerType); + model.with("codecoolers", codecoolers); + model.with("balance", userService); + } + + private void renderCodecoolers(HttpExchange httpExchange) throws IOException { + JtwigTemplate template = JtwigTemplate.classpathTemplate("templates/students.twig"); + JtwigModel model = JtwigModel.newModel(); + createGETModel(model); + String response = template.render(model); + ServiceUtility.sendResponse(httpExchange, response); + } +} \ No newline at end of file diff --git a/src/main/java/com/codecool/quest_store/dao/Dao.java b/src/main/java/com/codecool/quest_store/dao/Dao.java new file mode 100644 index 0000000..4a2c732 --- /dev/null +++ b/src/main/java/com/codecool/quest_store/dao/Dao.java @@ -0,0 +1,26 @@ +package com.codecool.quest_store.dao; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +public interface Dao { + void create(T thing) throws DaoException; + void update(T thing) throws DaoException; + T extractFromResultSet(ResultSet resultSet) throws DaoException; + + + default List getListByResultSet(ResultSet resultSet) throws DaoException{ + List itemsList = new ArrayList<>(); + + try{ + while (resultSet.next()){ + itemsList.add(extractFromResultSet(resultSet)); + } + } catch (SQLException e){ + throw new DaoException("failed to convert result set into list", e); + } + return itemsList; + } +} diff --git a/src/main/java/com/codecool/quest_store/dao/DaoException.java b/src/main/java/com/codecool/quest_store/dao/DaoException.java new file mode 100644 index 0000000..c8b690f --- /dev/null +++ b/src/main/java/com/codecool/quest_store/dao/DaoException.java @@ -0,0 +1,16 @@ +package com.codecool.quest_store.dao; + +public class DaoException extends Exception { + + public DaoException(Throwable error){ + super(error); + } + + public DaoException(String errorMessage){ + super(errorMessage); + } + + public DaoException(String errorMessage, Throwable error){ + super(errorMessage, error); + } +} diff --git a/src/main/java/com/codecool/quest_store/dao/DatabaseConnector.java b/src/main/java/com/codecool/quest_store/dao/DatabaseConnector.java new file mode 100644 index 0000000..69646fa --- /dev/null +++ b/src/main/java/com/codecool/quest_store/dao/DatabaseConnector.java @@ -0,0 +1,46 @@ +package com.codecool.quest_store.dao; + +import com.codecool.quest_store.utility.ConfigFileParser; +import org.apache.commons.dbcp.BasicDataSource; +import org.json.simple.parser.ParseException; + +import java.io.IOException; +import java.sql.Connection; +import java.sql.SQLException; + +public class DatabaseConnector { + + private static BasicDataSource ds = new BasicDataSource(); + + + private DatabaseConnector(){ } + + static { + try{ + final String URL = ConfigFileParser.getDatabaseURL(); //TODO:config file needed + final String USER = ConfigFileParser.getDatabaseUser(); + final String PASSWORD = ConfigFileParser.getDatabasePassword(); + ds.setUrl(URL); + ds.setUsername(USER); + ds.setPassword(PASSWORD); + } catch (IOException e) { + System.out.println("Config file connection failed"); + e.printStackTrace(); + } catch (ParseException e){ + System.out.println("Unable to parse config file"); + e.printStackTrace(); + } + + ds.setMinIdle(5); + ds.setMaxIdle(10); + ds.setMaxOpenPreparedStatements(100); + } + + public static Connection getConnection() throws SQLException{ + return ds.getConnection(); + } + + public static BasicDataSource getDs() { + return ds; + } +} \ No newline at end of file diff --git a/src/main/java/com/codecool/quest_store/dao/FundingDao.java b/src/main/java/com/codecool/quest_store/dao/FundingDao.java new file mode 100644 index 0000000..398fe21 --- /dev/null +++ b/src/main/java/com/codecool/quest_store/dao/FundingDao.java @@ -0,0 +1,9 @@ +package com.codecool.quest_store.dao; + +import com.codecool.quest_store.model.Funding; + +public interface FundingDao extends Dao { + public int getFundingSequenceNextVal() throws DaoException; + + void updateFundingStatus(Funding funding, int statusId) throws DaoException; +} diff --git a/src/main/java/com/codecool/quest_store/dao/FundingDaoImpl.java b/src/main/java/com/codecool/quest_store/dao/FundingDaoImpl.java new file mode 100644 index 0000000..4a5e2a9 --- /dev/null +++ b/src/main/java/com/codecool/quest_store/dao/FundingDaoImpl.java @@ -0,0 +1,117 @@ +package com.codecool.quest_store.dao; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; + +import com.codecool.quest_store.model.Funding; + +public class FundingDaoImpl implements FundingDao { + + @Override + public void create(Funding funding) throws DaoException { + String query; + + if (funding.getTEAM_ID() != 0) { + query = "INSERT INTO fundings (id, item_id, team_id) " + + "VALUES (?, ?, ?)"; + } else { + query = "INSERT INTO fundings (id, item_id) " + + "VALUES (?, ?)"; + } + + try (Connection connection = DatabaseConnector.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement(query)) { + if (funding.getID() != 0){ + preparedStatement.setInt(1, funding.getID()); + } else { + preparedStatement.setInt(1, getFundingSequenceNextVal()); + } + preparedStatement.setInt(2, funding.getITEM_ID()); + if (funding.getTEAM_ID() != 0) { + preparedStatement.setInt(3, funding.getTEAM_ID()); + } + preparedStatement.executeUpdate(); + + } catch (SQLException e) { + throw new DaoException("Failed to create a funding\n" + e); + } + } + + @Override + public void update(Funding funding) throws DaoException { + String query = "UPDATE fundings " + + "SET item_id = ?, " + + "team_id = ? " + + "WHERE id = ?"; + + try (Connection connection = DatabaseConnector.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement(query)) { + + preparedStatement.setInt(1, funding.getITEM_ID()); + preparedStatement.setInt(2, funding.getTEAM_ID()); + preparedStatement.setInt(3, funding.getID()); + preparedStatement.executeUpdate(); + + } catch (SQLException e) { + throw new DaoException("Failed to update funding\n" + e); + } + } + + @Override + public Funding extractFromResultSet(ResultSet resultSet) throws DaoException { + int ID; + int ITEM_ID; + int TEAM_ID; + Funding funding; + + try { + ID = resultSet.getInt("id"); + ITEM_ID = resultSet.getInt("price"); + TEAM_ID = resultSet.getInt("type"); + } catch (SQLException e) { + throw new DaoException("Failed to get funding from result set\n" + e); + } + + funding = new Funding.Builder() + .withID(ID) + .withITEM_ID(ITEM_ID) + .withTEAM_ID(TEAM_ID) + .build(); + + return funding; + } + + public int getFundingSequenceNextVal() throws DaoException{ + String query = + "SELECT nextval('fundings_id_seq')"; + + try(Connection connection = DatabaseConnector.getConnection(); + PreparedStatement pstmt = connection.prepareStatement(query); + ResultSet rs = pstmt.executeQuery()){ + rs.next(); + return rs.getInt("nextval"); + }catch (SQLException e){ + throw new DaoException("Failed to get next Fundings sequence number", e); + } + } + + @Override + public void updateFundingStatus(Funding funding, int statusId) throws DaoException { + String query = + "INSERT INTO status_history (funding_id, status_id, timestamp) " + + "VALUES(?, ?, ?);"; + try(Connection connection = DatabaseConnector.getConnection(); + PreparedStatement pstmt = connection.prepareStatement(query)){ + pstmt.setInt(1, funding.getID()); + pstmt.setInt(2, statusId); + pstmt.setObject(3, OffsetDateTime.now(ZoneOffset.UTC)); + pstmt.executeUpdate(); + } catch (SQLException e){ + throw new DaoException("Failed to update funding status", e); + } + } +} diff --git a/src/main/java/com/codecool/quest_store/dao/ItemDao.java b/src/main/java/com/codecool/quest_store/dao/ItemDao.java new file mode 100644 index 0000000..17294f9 --- /dev/null +++ b/src/main/java/com/codecool/quest_store/dao/ItemDao.java @@ -0,0 +1,20 @@ +package com.codecool.quest_store.dao; + +import java.util.List; +import java.util.Map; + +import com.codecool.quest_store.model.Item; + +public interface ItemDao extends Dao { + + List getAllItems() throws DaoException; + + Item getItemById(int itemId) throws DaoException; + + int getDiscount() throws DaoException; + + void setDiscount(int newDiscount) throws DaoException; + + Map getItemTypes() throws DaoException; +} + diff --git a/src/main/java/com/codecool/quest_store/dao/ItemDaoImpl.java b/src/main/java/com/codecool/quest_store/dao/ItemDaoImpl.java new file mode 100644 index 0000000..b3fcf0a --- /dev/null +++ b/src/main/java/com/codecool/quest_store/dao/ItemDaoImpl.java @@ -0,0 +1,195 @@ +package com.codecool.quest_store.dao; + +import java.util.List; +import java.util.Map; +import java.util.HashMap; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +import com.codecool.quest_store.model.Item; + +public class ItemDaoImpl implements ItemDao { + + @Override + public void create(Item item) throws DaoException { + String query = "INSERT INTO items (price, title, description, item_type) " + + "VALUES (?, ?, ?, ?)"; + + try (Connection connection = DatabaseConnector.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement(query)) { + + preparedStatement.setInt(1, item.getPrice()); + preparedStatement.setString(2, item.getTitle()); + preparedStatement.setString(3, item.getDescription()); + preparedStatement.setInt(4, item.getType()); + preparedStatement.executeUpdate(); + + } catch (SQLException e) { + throw new DaoException("Failed to create an item\n" + e); + } + } + + @Override + public void update(Item item) throws DaoException { + String query = "UPDATE items " + + "SET price = ?, " + + "title = ?, " + + "description = ?, " + + "item_type = ? " + + "WHERE id = ?"; + + try (Connection connection = DatabaseConnector.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement(query)) { + + preparedStatement.setInt(1, item.getPrice()); + preparedStatement.setString(2, item.getTitle()); + preparedStatement.setString(3, item.getDescription()); + preparedStatement.setInt(4, item.getType()); + preparedStatement.setInt(5, item.getID()); + preparedStatement.executeUpdate(); + + } catch (SQLException e) { + throw new DaoException("Failed to update item\n" + e); + } + } + + @Override + public Item extractFromResultSet(ResultSet resultSet) throws DaoException { + int ID; + int price; + int type; + String title; + String description; + Item item; + + try { + ID = resultSet.getInt("id"); + price = resultSet.getInt("price"); + title = resultSet.getString("title"); + description = resultSet.getString("description"); + type = resultSet.getInt("item_type"); + } catch (SQLException e) { + throw new DaoException("Failed to get item from result set\n" + e); + } + + item = new Item.Builder() + .withID(ID) + .withPrice(price) + .withTitle(title) + .withDescription(description) + .withType(type) + .build(); + + return item; + } + + public List getAllItems() throws DaoException { + String query = + "SELECT * FROM items"; + List allArtifacts; + + try (Connection connection = DatabaseConnector.getConnection(); + PreparedStatement pstmt = connection.prepareStatement(query); + ResultSet rs = pstmt.executeQuery()) { + allArtifacts = getListByResultSet(rs); + } catch (SQLException e) { + throw new DaoException("Failed to get all items\n", e); + } + return allArtifacts; + } + + public Item getItemById(int itemId) throws DaoException { + String query = + "SELECT * FROM items WHERE id=?;"; + try (Connection connection = DatabaseConnector.getConnection(); + PreparedStatement pstmt = connection.prepareStatement(query)) { + pstmt.setInt(1, itemId); + try { + ResultSet rs = pstmt.executeQuery(); + return getListByResultSet(rs).get(0); + } catch (SQLException e) { + throw new DaoException("Failed to get item by id", e); + } + } catch (SQLException e) { + throw new DaoException("Failed to get item by id", e); + } + } + + @Override + public int getDiscount() throws DaoException { + String query = + "SELECT discount FROM discount;"; + + try (Connection connection = DatabaseConnector.getConnection(); + PreparedStatement pstmt = connection.prepareStatement(query); + ResultSet rs = pstmt.executeQuery()) { + rs.next(); + return rs.getInt("discount"); + } catch (SQLException e) { + throw new DaoException("Failed to get discount", e); + } + } + + @Override + public void setDiscount(int newDiscount) throws DaoException { + String query = + "UPDATE discount SET discount = ?;"; + + try (Connection connection = DatabaseConnector.getConnection(); + PreparedStatement pstmt = connection.prepareStatement(query)) { + pstmt.setInt(1, newDiscount); + pstmt.executeUpdate(); + } catch (SQLException e) { + throw new DaoException("Failed to update new discount", e); + } + } + + public List getUserItems(int user_id) throws DaoException { + String query = "SELECT * FROM items " + + "INNER JOIN fundings ON items.id = fundings.item_id " + + "INNER JOIN transactions ON transactions.funding_id = fundings.id " + + "INNER JOIN status_history ON status_history.funding_id = fundings.id " + + "INNER JOIN statuses ON statuses.id = status_history.status_id " + + "WHERE transactions.user_id = ? AND statuses.type = 'Pending';"; + try (Connection connection = DatabaseConnector.getConnection(); + PreparedStatement pstmt = connection.prepareStatement(query)) { + pstmt.setInt(1, user_id); + ResultSet rs = pstmt.executeQuery(); + + return getListByResultSet(rs); + + } catch (SQLException e) { + throw new DaoException("Failed to get item by id", e); + } + } + + @Override + public Map getItemTypes() throws DaoException { + String query = "SELECT id, grade FROM item_types"; + try (Connection connection = DatabaseConnector.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement(query)) { + return getItemTypesFrom(preparedStatement); + } catch (SQLException e) { + throw new DaoException("Failed to get item types."); + } + } + + private Map getItemTypesFrom(PreparedStatement preparedStatement) throws DaoException { + Map itemTypes = new HashMap<>(); + Integer id; + String itemGrade; + try (ResultSet resultSet = preparedStatement.executeQuery()) { + while (resultSet.next()) { + id = resultSet.getInt("id"); + itemGrade = resultSet.getString("grade"); + itemTypes.put(itemGrade, id); + } + } catch (SQLException e) { + throw new DaoException("Failed to populate map of item types"); + } + return itemTypes; + } +} \ No newline at end of file diff --git a/src/main/java/com/codecool/quest_store/dao/RoomDao.java b/src/main/java/com/codecool/quest_store/dao/RoomDao.java new file mode 100644 index 0000000..6471001 --- /dev/null +++ b/src/main/java/com/codecool/quest_store/dao/RoomDao.java @@ -0,0 +1,9 @@ +package com.codecool.quest_store.dao; + +import java.util.Map; + +public interface RoomDao { + + public Map getRoomTypes() throws DaoException; + +} \ No newline at end of file diff --git a/src/main/java/com/codecool/quest_store/dao/RoomDaoImpl.java b/src/main/java/com/codecool/quest_store/dao/RoomDaoImpl.java new file mode 100644 index 0000000..cc38de4 --- /dev/null +++ b/src/main/java/com/codecool/quest_store/dao/RoomDaoImpl.java @@ -0,0 +1,85 @@ +package com.codecool.quest_store.dao; + +import java.sql.*; +import java.util.HashMap; +import java.util.Map; + +import com.codecool.quest_store.model.Room; + +public class RoomDaoImpl implements Dao, RoomDao { + + @Override + public void create(Room room) throws DaoException { + String SQL = "INSERT INTO rooms (name) VALUES (?)"; + + try (Connection connection = DatabaseConnector.getConnection(); + PreparedStatement pstmt = connection.prepareStatement(SQL)) { + pstmt.setString(1, room.getRoomName()); + pstmt.executeUpdate(); + } catch (SQLException e){ + throw new DaoException("failed to create room " + room.getRoomName(), e); + } + + } + + @Override + public void update(Room room) throws DaoException { + + int id = room.getId(); + String newName = room.getRoomName(); + + String SQL = + "UPDATE rooms SET name = ? WHERE id = ?;"; + + try (Connection connection = DatabaseConnector.getConnection(); + PreparedStatement pstmt = connection.prepareStatement(SQL)){ + pstmt.setString(1, newName); + pstmt.setInt(2, id); + pstmt.executeUpdate(SQL); + } catch (SQLException e){ + throw new DaoException("failed to update room " + newName, e); + } + } + + @Override + public Room extractFromResultSet(ResultSet resultSet) throws DaoException { + try{ + int id = resultSet.getInt("id"); + String name = resultSet.getString("name"); + + return new Room.RoomBuilder() + .withId(id) + .withRoomName(name) + .build(); + } catch (SQLException e){ + throw new DaoException("failed to extract team from result set", e); + } + } + + @Override + public Map getRoomTypes() throws DaoException { + String query = "SELECT id, name FROM rooms"; + try (Connection connection = DatabaseConnector.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement(query)) { + return getRoomTypesFrom(preparedStatement); + } catch (SQLException e) { + throw new DaoException("Failed to get room types."); + } + } + + private Map getRoomTypesFrom(PreparedStatement preparedStatement) throws DaoException { + Map roomTypes = new HashMap<>(); + Integer id; + String roomType; + try (ResultSet resultSet = preparedStatement.executeQuery()) { + while (resultSet.next()) { + id = resultSet.getInt("id"); + roomType = resultSet.getString("name"); + roomTypes.put(roomType, id); + } + } catch (SQLException e) { + throw new DaoException("Failed to populate map of room types"); + } + return roomTypes; + } +} diff --git a/src/main/java/com/codecool/quest_store/dao/SessionDaoImpl.java b/src/main/java/com/codecool/quest_store/dao/SessionDaoImpl.java new file mode 100644 index 0000000..cb1a497 --- /dev/null +++ b/src/main/java/com/codecool/quest_store/dao/SessionDaoImpl.java @@ -0,0 +1,50 @@ +package com.codecool.quest_store.dao; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +public class SessionDaoImpl { + + public void createSession(int session, int userId) throws DaoException { + String query = "INSERT INTO sessions(session, user_id) VALUES(?, ?);"; + try (Connection connection = DatabaseConnector.getConnection(); + PreparedStatement statement = connection.prepareStatement(query)) { + statement.setInt(1, session); + statement.setInt(2, userId); + statement.executeUpdate(); + } catch(SQLException error) { + throw new DaoException("It's impossible to create a new session"); + } + } + + public void deleteSession(int session) throws DaoException { + String query = "DELETE FROM sessions WHERE session = ?;"; + try (Connection connection = DatabaseConnector.getConnection(); + PreparedStatement statement = connection.prepareStatement(query)) { + statement.setInt(1, session); + statement.executeUpdate(); + } catch(SQLException error) { + throw new DaoException("It's impossible to update this session"); + } + } + + public Integer getUserId(int session) throws DaoException { + String query = "SELECT user_id FROM sessions WHERE session = ?"; + try (Connection connection = DatabaseConnector.getConnection(); + PreparedStatement statement = connection.prepareStatement(query)) { + statement.setInt(1, session); + try (ResultSet rs = statement.executeQuery()) { + if (rs.next()) { + int user_id = rs.getInt("user_id"); + System.out.println(session); + return user_id; + } + } + } catch (SQLException error) { + throw new DaoException("It's impossible to update this session"); + } + return null; + } +} diff --git a/src/main/java/com/codecool/quest_store/dao/TeamDaoImpl.java b/src/main/java/com/codecool/quest_store/dao/TeamDaoImpl.java new file mode 100644 index 0000000..89a5f3c --- /dev/null +++ b/src/main/java/com/codecool/quest_store/dao/TeamDaoImpl.java @@ -0,0 +1,76 @@ +package com.codecool.quest_store.dao; + +import com.codecool.quest_store.model.Team; + +import java.sql.*; + +public class TeamDaoImpl implements Dao { + + @Override + public void create(Team thing) throws DaoException { + String newTeamName = thing.getTeamName(); + String newProjectName = thing.getProjectName(); + + String SQL = "INSERT INTO teams (name, project_name) VALUES (?,?)"; + + try (Connection connection = DatabaseConnector.getConnection(); + PreparedStatement pstmt = connection.prepareStatement(SQL)){ + pstmt.setString(1, newTeamName); + pstmt.setString(2, newProjectName); + pstmt.executeUpdate(); + } catch (SQLException e){ + throw new DaoException("failed to create team " + thing.getTeamName()); + } + + + } + + @Override + public void update(Team thing) throws DaoException { + int id = thing.getId(); + String newTeamName = thing.getTeamName(); + String newProjectName = thing.getProjectName(); + + String SQL = "UPDATE teams SET name = ?, project_name = ? WHERE id = ?;"; + + try (Connection connection = DatabaseConnector.getConnection(); + PreparedStatement pstmt = connection.prepareStatement(SQL)){ + pstmt.setString(1, newTeamName); + pstmt.setString(2, newProjectName); + pstmt.setInt(3, id); + pstmt.executeUpdate(); + } catch (SQLException e){ + throw new DaoException("failed to update team " + newTeamName, e); + } + } + + @Override + public Team extractFromResultSet(ResultSet resultSet) throws DaoException { + try { + int id = resultSet.getInt("id"); + String teamName = resultSet.getString("name"); + String projectName = resultSet.getString("project_name"); + + return new Team.TeamBuilder() + .withId(id) + .withTeamName(teamName) + .withProjectName(projectName) + .build(); + } catch (SQLException e){ + throw new DaoException("failed to extract team from result set", e); + } + } + + public Team getById(int id) throws DaoException{ + String SQL = "SELECT * FROM teams WHERE id = " + id; + + try (Connection connection = DatabaseConnector.getConnection(); + Statement stmt = connection.createStatement(); + ResultSet resultSet = stmt.executeQuery(SQL)){ + return getListByResultSet(resultSet).get(0); + } catch (SQLException e){ + throw new DaoException("failed to get team by id " + id, e); + } + + } +} diff --git a/src/main/java/com/codecool/quest_store/dao/TransactionDao.java b/src/main/java/com/codecool/quest_store/dao/TransactionDao.java new file mode 100644 index 0000000..9cd105b --- /dev/null +++ b/src/main/java/com/codecool/quest_store/dao/TransactionDao.java @@ -0,0 +1,11 @@ +package com.codecool.quest_store.dao; + +import com.codecool.quest_store.model.Transaction; +import com.codecool.quest_store.model.User; + +public interface TransactionDao { + + public int getPriceSumOfRealizedQuests(User user) throws DaoException; + + public int getPriceSumOfPurchasedArtifacts(User user) throws DaoException; +} \ No newline at end of file diff --git a/src/main/java/com/codecool/quest_store/dao/TransactionDaoImpl.java b/src/main/java/com/codecool/quest_store/dao/TransactionDaoImpl.java new file mode 100644 index 0000000..592a52b --- /dev/null +++ b/src/main/java/com/codecool/quest_store/dao/TransactionDaoImpl.java @@ -0,0 +1,136 @@ +package com.codecool.quest_store.dao; + +import java.sql.*; + +import java.time.OffsetDateTime; + +import com.codecool.quest_store.model.Transaction; +import com.codecool.quest_store.model.User; + +public class TransactionDaoImpl implements TransactionDao, Dao { + + @Override + public void create(Transaction transaction) throws DaoException { + String query = "INSERT INTO transactions (funding_id, user_id, timestamp, paid_amount) " + + "VALUES (?, ?, ?, ?)"; + + try (Connection connection = DatabaseConnector.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement(query)) { + + preparedStatement.setInt(1, transaction.getFUNDING_ID()); + preparedStatement.setInt(2, transaction.getUSER_ID()); + preparedStatement.setObject(3, transaction.getTIMESTAMP(), Types.TIMESTAMP_WITH_TIMEZONE); + preparedStatement.setInt(4, transaction.getPAID_AMOUNT()); + preparedStatement.executeUpdate(); + + } catch (SQLException e) { + throw new DaoException("Failed to create a transaction\n" + e); + } + } + + @Override + public void update(Transaction transaction) throws DaoException { + String query = "UPDATE transactions " + + "SET funding_id = ?, " + + "user_id = ?, " + + "timestamp = ?, " + + "paid_amount = ? " + + "WHERE id = ?"; + + try (Connection connection = DatabaseConnector.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement(query)) { + + preparedStatement.setInt(1, transaction.getFUNDING_ID()); + preparedStatement.setInt(2, transaction.getUSER_ID()); + preparedStatement.setObject(3, transaction.getTIMESTAMP()); + preparedStatement.setInt(4, transaction.getPAID_AMOUNT()); + preparedStatement.setInt(5, transaction.getID()); + preparedStatement.executeUpdate(); + + } catch (SQLException e) { + throw new DaoException("Failed to update the transaction's status\n" + e); + } + } + + @Override + public Transaction extractFromResultSet(ResultSet resultSet) throws DaoException { + int ID; + int FUNDING_ID; + int USER_ID; + OffsetDateTime TIMESTAMP; + int PAID_AMOUNT; + Transaction transaction; + + try { + ID = resultSet.getInt("id"); + FUNDING_ID = resultSet.getInt("funding_id"); + USER_ID = resultSet.getInt("user_id"); + TIMESTAMP = resultSet.getObject("timestamp", OffsetDateTime.class); + PAID_AMOUNT = resultSet.getInt("paid_amount"); + } catch (SQLException e) { + throw new DaoException("Failed to get transaction from result set\n" + e); + } + + transaction = new Transaction.Builder() + .withID(ID) + .withFUNDING_ID(FUNDING_ID) + .withUSER_ID(USER_ID) + .withTIMESTAMP(TIMESTAMP) + .withPAID_AMOUNT(PAID_AMOUNT) + .build(); + + return transaction; + } + + @Override + public int getPriceSumOfRealizedQuests(User user) throws DaoException { + int userId = user.getId(); + String query = "SELECT SUM(paid_amount) FROM transactions " + + "INNER JOIN fundings " + + "ON transactions.funding_id = fundings.id " + + "INNER JOIN status_history " + + "ON fundings.id = status_history.funding_id " + + "INNER JOIN items " + + "ON fundings.item_id = items.id " + + "WHERE transactions.user_id = ? " + + "AND items.item_type IN (3,4) AND status_history.status_id != 4;"; + return getSumOfPrices(userId, query); + } + + @Override + public int getPriceSumOfPurchasedArtifacts(User user) throws DaoException { + int userId = user.getId(); + String query = "SELECT SUM(paid_amount) FROM transactions " + + "INNER JOIN fundings " + + "ON transactions.funding_id = fundings.id " + + "INNER JOIN status_history " + + "ON fundings.id = status_history.funding_id " + + "INNER JOIN items " + + "ON fundings.item_id = items.id " + + "WHERE transactions.user_id = ? " + + "AND items.item_type IN (1,2) AND status_history.status_id != 4;"; + return getSumOfPrices(userId, query); + } + + private int getSumOfPrices(int userId, String query) throws DaoException { + int sumOfPrices = 0; + + try (Connection connection = DatabaseConnector.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement(query)) { + + preparedStatement.setInt(1, userId); + try (ResultSet resultSet = preparedStatement.executeQuery()) { + + if (resultSet.next()) { + sumOfPrices = resultSet.getInt("sum"); + } + } + + } catch (SQLException e) { + throw new DaoException("Failed to calculate the price sum of items\n" + e); + } + return sumOfPrices; + } + + +} \ No newline at end of file diff --git a/src/main/java/com/codecool/quest_store/dao/UserDao.java b/src/main/java/com/codecool/quest_store/dao/UserDao.java new file mode 100644 index 0000000..c0183bd --- /dev/null +++ b/src/main/java/com/codecool/quest_store/dao/UserDao.java @@ -0,0 +1,13 @@ +package com.codecool.quest_store.dao; + +import java.util.List; +import java.util.Map; + +import com.codecool.quest_store.model.User; + +public interface UserDao { + + List getUsersByType(int userType) throws DaoException; + + Map getUserTypes() throws DaoException; +} diff --git a/src/main/java/com/codecool/quest_store/dao/UserDaoImpl.java b/src/main/java/com/codecool/quest_store/dao/UserDaoImpl.java new file mode 100644 index 0000000..70fd2b6 --- /dev/null +++ b/src/main/java/com/codecool/quest_store/dao/UserDaoImpl.java @@ -0,0 +1,218 @@ +package com.codecool.quest_store.dao; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import java.sql.*; + +import com.codecool.quest_store.model.User; + +public class UserDaoImpl implements UserDao, Dao { + + @Override + public List getUsersByType(int userType) throws DaoException { + User user; + List users = new ArrayList<>(); + + String query = "SELECT * FROM users WHERE user_type_id = " + userType; + + try (Connection connection = DatabaseConnector.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement(query); + ResultSet resultSet = preparedStatement.executeQuery()) { + + while (resultSet.next()) { + int id = resultSet.getInt("id"); + String name = resultSet.getString("name"); + String surname = resultSet.getString("surname"); + String phoneNumber = resultSet.getString("phone_number"); + String email = resultSet.getString("email"); + String password = resultSet.getString("password"); + String photo = resultSet.getString("photo"); + int typeId = resultSet.getInt("user_type_id"); + int roomId = resultSet.getInt("room_id"); + int teamId = resultSet.getInt("team_id"); + user = new User.UserBuilder() + .withId(id) + .withName(name) + .withSurname(surname) + .withPhoneNumber(phoneNumber) + .withEmail(email) + .withPassword(password) + .withPhoto(photo) + .withTypeId(typeId) + .withRoomId(roomId) + .withTeamId(teamId) + .build(); + users.add(user); + } + + } catch(SQLException error){ + throw new DaoException("Failed get users by user type", error); + } + return users; + } + + @Override + public void create(User user) throws DaoException { + String query = "INSERT INTO users(name, surname, phone_number, email, password, " + + "photo, user_type_id, room_id) " + + "VALUES(?, ?, ?, ?, ?, ?, ?, ?);"; + + try (Connection connection = DatabaseConnector.getConnection(); + PreparedStatement statement = connection.prepareStatement(query)) { + setRequiredStatements(statement, user); + statement.executeUpdate(); + + } catch(SQLException error){ + throw new DaoException("Your have some mistake during creation a new user", error); + } + } + + private void setRequiredStatements(PreparedStatement statement, User user) throws DaoException { + try { + statement.setString(1, user.getName()); + statement.setString(2, user.getSurname()); + statement.setString(3, user.getPhoneNumber()); + statement.setString(4, user.getEmail()); + statement.setString(5, user.getPassword()); + statement.setString(6, user.getPhoto()); + statement.setInt(7, user.getTypeId()); + statement.setInt(8, user.getRoomId()); + } catch (SQLException e) { + throw new DaoException("Failed to set user's statements"); + } + } + + public void update(User user) throws DaoException { + String query = "UPDATE users SET name = ?, surname = ?, phone_number = ?, email = ?, password = ?, " + + "photo = ?, user_type_id = ?, room_id = ?, team_id = ? WHERE id = ?"; + + try (Connection connection = DatabaseConnector.getConnection(); + PreparedStatement statement = connection.prepareStatement(query)) { + setRequiredStatements(statement, user); + statement.setInt(9, user.getTeamId()); + statement.setInt(10, user.getId()); + statement.executeUpdate(); + + } catch(SQLException error){ + throw new DaoException("You can't update a user", error); + } + } + + public User getUser(int userId) throws DaoException { + String query = "SELECT * FROM users WHERE id = ?"; + try (Connection connection = DatabaseConnector.getConnection(); + PreparedStatement statement = connection.prepareStatement(query)) { + statement.setInt(1, userId); + ResultSet rs = statement.executeQuery(); + return getListByResultSet(rs).get(0); + } catch(SQLException error){ + throw new DaoException("You can't update a user", error); + } + } + + @Override + public User extractFromResultSet(ResultSet resultSet) throws DaoException { + int id; + String name; + String surname; + String phoneNumber; + String email; + String password; + String photo; + int userTypeId; + int roomId; + int teamId; + User user; + + try { + id = resultSet.getInt("id"); + name = resultSet.getString("name"); + surname = resultSet.getString("surname"); + phoneNumber = resultSet.getString("phone_number"); + email = resultSet.getString("email"); + password = resultSet.getString("password"); + photo = resultSet.getString("photo"); + userTypeId = resultSet.getInt("user_type_id"); + roomId = resultSet.getInt("room_id"); + teamId = resultSet.getInt("team_id"); + + } catch (SQLException e) { + throw new DaoException("Failed to get item from result set\n" + e); + } + + user = new User.UserBuilder() + .withId(id) + .withName(name) + .withSurname(surname) + .withPhoneNumber(phoneNumber) + .withEmail(email) + .withPassword(password) + .withPhoto(photo) + .withTypeId(userTypeId) + .withRoomId(roomId) + .withTeamId(teamId) + .build(); + + return user; + } + + + public User getIdAndUserType(String name, String password) throws DaoException { + + User user; + + String query = "SELECT * FROM users WHERE name LIKE ? AND password LIKE ?;"; + + try (Connection connection = DatabaseConnector.getConnection(); + PreparedStatement statement = connection.prepareStatement(query)) { + statement.setString(1, name); + statement.setString(2, password); + try(ResultSet rs = statement.executeQuery()) { + while (rs.next()) { + int id = rs.getInt("id"); + int userType = rs.getInt("user_type_id"); + user = new User.UserBuilder() + .withId(id) + .withTypeId(userType) + .build(); + return user; + } + } + } catch(SQLException error) { + throw new DaoException("There isn't an applicant with data: " + name + " " + password); + } + return null; + } + + @Override + public Map getUserTypes() throws DaoException { + String query = "SELECT id, type FROM user_types"; + try (Connection connection = DatabaseConnector.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement(query)) { + return getUserTypesFrom(preparedStatement); + } catch (SQLException e) { + throw new DaoException("Failed to get user types."); + } + } + + private Map getUserTypesFrom(PreparedStatement preparedStatement) throws DaoException { + Map userTypes = new HashMap<>(); + Integer id; + String userType; + try (ResultSet resultSet = preparedStatement.executeQuery()) { + while (resultSet.next()) { + id = resultSet.getInt("id"); + userType = resultSet.getString("type"); + userTypes.put(userType, id); + } + } catch (SQLException e) { + throw new DaoException("Failed to populate map of user types"); + } + return userTypes; + } +} + + diff --git a/src/main/java/com/codecool/quest_store/helpers/MimeTypeResolver.java b/src/main/java/com/codecool/quest_store/helpers/MimeTypeResolver.java new file mode 100644 index 0000000..2a0e495 --- /dev/null +++ b/src/main/java/com/codecool/quest_store/helpers/MimeTypeResolver.java @@ -0,0 +1,24 @@ +package com.codecool.quest_store.helpers; + +import java.io.File; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class MimeTypeResolver { + private File file; + + public MimeTypeResolver(File file) { + this.file = file; + } + + public String getMimeType() { + return MimeTypes.mimeTypeMapping.get(getFileExtension().toLowerCase()); + } + + public String getFileExtension(){ + Pattern pattern = Pattern.compile("\\.(\\w+)$"); + Matcher matcher = pattern.matcher(file.getName()); + matcher.find(); + return matcher.group(1); + } +} diff --git a/src/main/java/com/codecool/quest_store/helpers/MimeTypes.java b/src/main/java/com/codecool/quest_store/helpers/MimeTypes.java new file mode 100644 index 0000000..aed9d53 --- /dev/null +++ b/src/main/java/com/codecool/quest_store/helpers/MimeTypes.java @@ -0,0 +1,304 @@ +package com.codecool.quest_store.helpers; + +// Copyright (c) 2003-2009, Jodd Team (jodd.org). All Rights Reserved. + + +import java.util.HashMap; + +/** + * Map file extensions to MIME types. Based on the Apache mime.types file. + * http://www.iana.org/assignments/media-types/ + */ +public class MimeTypes { + + public static final String MIME_APPLICATION_ANDREW_INSET = "application/andrew-inset"; + public static final String MIME_APPLICATION_JSON = "application/json"; + public static final String MIME_APPLICATION_ZIP = "application/zip"; + public static final String MIME_APPLICATION_X_GZIP = "application/x-gzip"; + public static final String MIME_APPLICATION_TGZ = "application/tgz"; + public static final String MIME_APPLICATION_MSWORD = "application/msword"; + public static final String MIME_APPLICATION_POSTSCRIPT = "application/postscript"; + public static final String MIME_APPLICATION_PDF = "application/pdf"; + public static final String MIME_APPLICATION_JNLP = "application/jnlp"; + public static final String MIME_APPLICATION_MAC_BINHEX40 = "application/mac-binhex40"; + public static final String MIME_APPLICATION_MAC_COMPACTPRO = "application/mac-compactpro"; + public static final String MIME_APPLICATION_MATHML_XML = "application/mathml+xml"; + public static final String MIME_APPLICATION_OCTET_STREAM = "application/octet-stream"; + public static final String MIME_APPLICATION_ODA = "application/oda"; + public static final String MIME_APPLICATION_RDF_XML = "application/rdf+xml"; + public static final String MIME_APPLICATION_JAVA_ARCHIVE = "application/java-archive"; + public static final String MIME_APPLICATION_RDF_SMIL = "application/smil"; + public static final String MIME_APPLICATION_SRGS = "application/srgs"; + public static final String MIME_APPLICATION_SRGS_XML = "application/srgs+xml"; + public static final String MIME_APPLICATION_VND_MIF = "application/vnd.mif"; + public static final String MIME_APPLICATION_VND_MSEXCEL = "application/vnd.ms-excel"; + public static final String MIME_APPLICATION_VND_MSPOWERPOINT= "application/vnd.ms-powerpoint"; + public static final String MIME_APPLICATION_VND_RNREALMEDIA = "application/vnd.rn-realmedia"; + public static final String MIME_APPLICATION_X_BCPIO = "application/x-bcpio"; + public static final String MIME_APPLICATION_X_CDLINK = "application/x-cdlink"; + public static final String MIME_APPLICATION_X_CHESS_PGN = "application/x-chess-pgn"; + public static final String MIME_APPLICATION_X_CPIO = "application/x-cpio"; + public static final String MIME_APPLICATION_X_CSH = "application/x-csh"; + public static final String MIME_APPLICATION_X_DIRECTOR = "application/x-director"; + public static final String MIME_APPLICATION_X_DVI = "application/x-dvi"; + public static final String MIME_APPLICATION_X_FUTURESPLASH = "application/x-futuresplash"; + public static final String MIME_APPLICATION_X_GTAR = "application/x-gtar"; + public static final String MIME_APPLICATION_X_HDF = "application/x-hdf"; + public static final String MIME_APPLICATION_X_JAVASCRIPT = "application/javascript"; + public static final String MIME_APPLICATION_X_KOAN = "application/x-koan"; + public static final String MIME_APPLICATION_X_LATEX = "application/x-latex"; + public static final String MIME_APPLICATION_X_NETCDF = "application/x-netcdf"; + public static final String MIME_APPLICATION_X_OGG = "application/x-ogg"; + public static final String MIME_APPLICATION_X_SH = "application/x-sh"; + public static final String MIME_APPLICATION_X_SHAR = "application/x-shar"; + public static final String MIME_APPLICATION_X_SHOCKWAVE_FLASH = "application/x-shockwave-flash"; + public static final String MIME_APPLICATION_X_STUFFIT = "application/x-stuffit"; + public static final String MIME_APPLICATION_X_SV4CPIO = "application/x-sv4cpio"; + public static final String MIME_APPLICATION_X_SV4CRC = "application/x-sv4crc"; + public static final String MIME_APPLICATION_X_TAR = "application/x-tar"; + public static final String MIME_APPLICATION_X_RAR_COMPRESSED= "application/x-rar-compressed"; + public static final String MIME_APPLICATION_X_TCL = "application/x-tcl"; + public static final String MIME_APPLICATION_X_TEX = "application/x-tex"; + public static final String MIME_APPLICATION_X_TEXINFO = "application/x-texinfo"; + public static final String MIME_APPLICATION_X_TROFF = "application/x-troff"; + public static final String MIME_APPLICATION_X_TROFF_MAN = "application/x-troff-man"; + public static final String MIME_APPLICATION_X_TROFF_ME = "application/x-troff-me"; + public static final String MIME_APPLICATION_X_TROFF_MS = "application/x-troff-ms"; + public static final String MIME_APPLICATION_X_USTAR = "application/x-ustar"; + public static final String MIME_APPLICATION_X_WAIS_SOURCE = "application/x-wais-source"; + public static final String MIME_APPLICATION_VND_MOZZILLA_XUL_XML = "application/vnd.mozilla.xul+xml"; + public static final String MIME_APPLICATION_XHTML_XML = "application/xhtml+xml"; + public static final String MIME_APPLICATION_XSLT_XML = "application/xslt+xml"; + public static final String MIME_APPLICATION_XML = "application/xml"; + public static final String MIME_APPLICATION_XML_DTD = "application/xml-dtd"; + public static final String MIME_IMAGE_BMP = "image/bmp"; + public static final String MIME_IMAGE_CGM = "image/cgm"; + public static final String MIME_IMAGE_GIF = "image/gif"; + public static final String MIME_IMAGE_IEF = "image/ief"; + public static final String MIME_IMAGE_JPEG = "image/jpeg"; + public static final String MIME_IMAGE_TIFF = "image/tiff"; + public static final String MIME_IMAGE_PNG = "image/png"; + public static final String MIME_IMAGE_SVG_XML = "image/svg+xml"; + public static final String MIME_IMAGE_VND_DJVU = "image/vnd.djvu"; + public static final String MIME_IMAGE_WAP_WBMP = "image/vnd.wap.wbmp"; + public static final String MIME_IMAGE_X_CMU_RASTER = "image/x-cmu-raster"; + public static final String MIME_IMAGE_X_ICON = "image/x-icon"; + public static final String MIME_IMAGE_X_PORTABLE_ANYMAP = "image/x-portable-anymap"; + public static final String MIME_IMAGE_X_PORTABLE_BITMAP = "image/x-portable-bitmap"; + public static final String MIME_IMAGE_X_PORTABLE_GRAYMAP = "image/x-portable-graymap"; + public static final String MIME_IMAGE_X_PORTABLE_PIXMAP = "image/x-portable-pixmap"; + public static final String MIME_IMAGE_X_RGB = "image/x-rgb"; + public static final String MIME_AUDIO_BASIC = "audio/basic"; + public static final String MIME_AUDIO_MIDI = "audio/midi"; + public static final String MIME_AUDIO_MPEG = "audio/mpeg"; + public static final String MIME_AUDIO_X_AIFF = "audio/x-aiff"; + public static final String MIME_AUDIO_X_MPEGURL = "audio/x-mpegurl"; + public static final String MIME_AUDIO_X_PN_REALAUDIO = "audio/x-pn-realaudio"; + public static final String MIME_AUDIO_X_WAV = "audio/x-wav"; + public static final String MIME_CHEMICAL_X_PDB = "chemical/x-pdb"; + public static final String MIME_CHEMICAL_X_XYZ = "chemical/x-xyz"; + public static final String MIME_MODEL_IGES = "model/iges"; + public static final String MIME_MODEL_MESH = "model/mesh"; + public static final String MIME_MODEL_VRLM = "model/vrml"; + public static final String MIME_TEXT_PLAIN = "text/plain"; + public static final String MIME_TEXT_RICHTEXT = "text/richtext"; + public static final String MIME_TEXT_RTF = "text/rtf"; + public static final String MIME_TEXT_HTML = "text/html"; + public static final String MIME_TEXT_CALENDAR = "text/calendar"; + public static final String MIME_TEXT_CSS = "text/css"; + public static final String MIME_TEXT_SGML = "text/sgml"; + public static final String MIME_TEXT_TAB_SEPARATED_VALUES = "text/tab-separated-values"; + public static final String MIME_TEXT_VND_WAP_XML = "text/vnd.wap.wml"; + public static final String MIME_TEXT_VND_WAP_WMLSCRIPT = "text/vnd.wap.wmlscript"; + public static final String MIME_TEXT_X_SETEXT = "text/x-setext"; + public static final String MIME_TEXT_X_COMPONENT = "text/x-component"; + public static final String MIME_VIDEO_QUICKTIME = "video/quicktime"; + public static final String MIME_VIDEO_MPEG = "video/mpeg"; + public static final String MIME_VIDEO_VND_MPEGURL = "video/vnd.mpegurl"; + public static final String MIME_VIDEO_X_MSVIDEO = "video/x-msvideo"; + public static final String MIME_VIDEO_X_MS_WMV = "video/x-ms-wmv"; + public static final String MIME_VIDEO_X_SGI_MOVIE = "video/x-sgi-movie"; + public static final String MIME_X_CONFERENCE_X_COOLTALK = "x-conference/x-cooltalk"; + + public static HashMap mimeTypeMapping; + + static { + mimeTypeMapping = new HashMap(200) { + private void put1(String key, String value) { + if (put(key, value) != null) { + throw new IllegalArgumentException("Duplicated extension: " + key); + } + } + { + put1("xul", MIME_APPLICATION_VND_MOZZILLA_XUL_XML); + put1("json", MIME_APPLICATION_JSON); + put1("ice", MIME_X_CONFERENCE_X_COOLTALK); + put1("movie", MIME_VIDEO_X_SGI_MOVIE); + put1("avi", MIME_VIDEO_X_MSVIDEO); + put1("wmv", MIME_VIDEO_X_MS_WMV); + put1("m4u", MIME_VIDEO_VND_MPEGURL); + put1("mxu", MIME_VIDEO_VND_MPEGURL); + put1("htc", MIME_TEXT_X_COMPONENT); + put1("etx", MIME_TEXT_X_SETEXT); + put1("wmls", MIME_TEXT_VND_WAP_WMLSCRIPT); + put1("wml", MIME_TEXT_VND_WAP_XML); + put1("tsv", MIME_TEXT_TAB_SEPARATED_VALUES); + put1("sgm", MIME_TEXT_SGML); + put1("sgml", MIME_TEXT_SGML); + put1("css", MIME_TEXT_CSS); + put1("ifb", MIME_TEXT_CALENDAR); + put1("ics", MIME_TEXT_CALENDAR); + put1("wrl", MIME_MODEL_VRLM); + put1("vrlm", MIME_MODEL_VRLM); + put1("silo", MIME_MODEL_MESH); + put1("mesh", MIME_MODEL_MESH); + put1("msh", MIME_MODEL_MESH); + put1("iges", MIME_MODEL_IGES); + put1("igs", MIME_MODEL_IGES); + put1("rgb", MIME_IMAGE_X_RGB); + put1("ppm", MIME_IMAGE_X_PORTABLE_PIXMAP); + put1("pgm", MIME_IMAGE_X_PORTABLE_GRAYMAP); + put1("pbm", MIME_IMAGE_X_PORTABLE_BITMAP); + put1("pnm", MIME_IMAGE_X_PORTABLE_ANYMAP); + put1("ico", MIME_IMAGE_X_ICON); + put1("ras", MIME_IMAGE_X_CMU_RASTER); + put1("wbmp", MIME_IMAGE_WAP_WBMP); + put1("djv", MIME_IMAGE_VND_DJVU); + put1("djvu", MIME_IMAGE_VND_DJVU); + put1("svg", MIME_IMAGE_SVG_XML); + put1("ief", MIME_IMAGE_IEF); + put1("cgm", MIME_IMAGE_CGM); + put1("bmp", MIME_IMAGE_BMP); + put1("xyz", MIME_CHEMICAL_X_XYZ); + put1("pdb", MIME_CHEMICAL_X_PDB); + put1("ra", MIME_AUDIO_X_PN_REALAUDIO); + put1("ram", MIME_AUDIO_X_PN_REALAUDIO); + put1("m3u", MIME_AUDIO_X_MPEGURL); + put1("aifc", MIME_AUDIO_X_AIFF); + put1("aif", MIME_AUDIO_X_AIFF); + put1("aiff", MIME_AUDIO_X_AIFF); + put1("mp3", MIME_AUDIO_MPEG); + put1("mp2", MIME_AUDIO_MPEG); + put1("mp1", MIME_AUDIO_MPEG); + put1("mpga", MIME_AUDIO_MPEG); + put1("kar", MIME_AUDIO_MIDI); + put1("mid", MIME_AUDIO_MIDI); + put1("midi", MIME_AUDIO_MIDI); + put1("dtd", MIME_APPLICATION_XML_DTD); + put1("xsl", MIME_APPLICATION_XML); + put1("xml", MIME_APPLICATION_XML); + put1("xslt", MIME_APPLICATION_XSLT_XML); + put1("xht", MIME_APPLICATION_XHTML_XML); + put1("xhtml", MIME_APPLICATION_XHTML_XML); + put1("src", MIME_APPLICATION_X_WAIS_SOURCE); + put1("ustar", MIME_APPLICATION_X_USTAR); + put1("ms", MIME_APPLICATION_X_TROFF_MS); + put1("me", MIME_APPLICATION_X_TROFF_ME); + put1("man", MIME_APPLICATION_X_TROFF_MAN); + put1("roff", MIME_APPLICATION_X_TROFF); + put1("tr", MIME_APPLICATION_X_TROFF); + put1("t", MIME_APPLICATION_X_TROFF); + put1("texi", MIME_APPLICATION_X_TEXINFO); + put1("texinfo", MIME_APPLICATION_X_TEXINFO); + put1("tex", MIME_APPLICATION_X_TEX); + put1("tcl", MIME_APPLICATION_X_TCL); + put1("sv4crc", MIME_APPLICATION_X_SV4CRC); + put1("sv4cpio", MIME_APPLICATION_X_SV4CPIO); + put1("sit", MIME_APPLICATION_X_STUFFIT); + put1("swf", MIME_APPLICATION_X_SHOCKWAVE_FLASH); + put1("shar", MIME_APPLICATION_X_SHAR); + put1("sh", MIME_APPLICATION_X_SH); + put1("cdf", MIME_APPLICATION_X_NETCDF); + put1("nc", MIME_APPLICATION_X_NETCDF); + put1("latex", MIME_APPLICATION_X_LATEX); + put1("skm", MIME_APPLICATION_X_KOAN); + put1("skt", MIME_APPLICATION_X_KOAN); + put1("skd", MIME_APPLICATION_X_KOAN); + put1("skp", MIME_APPLICATION_X_KOAN); + put1("js", MIME_APPLICATION_X_JAVASCRIPT); + put1("hdf", MIME_APPLICATION_X_HDF); + put1("gtar", MIME_APPLICATION_X_GTAR); + put1("spl", MIME_APPLICATION_X_FUTURESPLASH); + put1("dvi", MIME_APPLICATION_X_DVI); + put1("dxr", MIME_APPLICATION_X_DIRECTOR); + put1("dir", MIME_APPLICATION_X_DIRECTOR); + put1("dcr", MIME_APPLICATION_X_DIRECTOR); + put1("csh", MIME_APPLICATION_X_CSH); + put1("cpio", MIME_APPLICATION_X_CPIO); + put1("pgn", MIME_APPLICATION_X_CHESS_PGN); + put1("vcd", MIME_APPLICATION_X_CDLINK); + put1("bcpio", MIME_APPLICATION_X_BCPIO); + put1("rm", MIME_APPLICATION_VND_RNREALMEDIA); + put1("ppt", MIME_APPLICATION_VND_MSPOWERPOINT); + put1("mif", MIME_APPLICATION_VND_MIF); + put1("grxml", MIME_APPLICATION_SRGS_XML); + put1("gram", MIME_APPLICATION_SRGS); + put1("smil", MIME_APPLICATION_RDF_SMIL); + put1("smi", MIME_APPLICATION_RDF_SMIL); + put1("rdf", MIME_APPLICATION_RDF_XML); + put1("ogg", MIME_APPLICATION_X_OGG); + put1("oda", MIME_APPLICATION_ODA); + put1("dmg", MIME_APPLICATION_OCTET_STREAM); + put1("lzh", MIME_APPLICATION_OCTET_STREAM); + put1("so", MIME_APPLICATION_OCTET_STREAM); + put1("lha", MIME_APPLICATION_OCTET_STREAM); + put1("dms", MIME_APPLICATION_OCTET_STREAM); + put1("bin", MIME_APPLICATION_OCTET_STREAM); + put1("mathml", MIME_APPLICATION_MATHML_XML); + put1("cpt", MIME_APPLICATION_MAC_COMPACTPRO); + put1("hqx", MIME_APPLICATION_MAC_BINHEX40); + put1("jnlp", MIME_APPLICATION_JNLP); + put1("ez", MIME_APPLICATION_ANDREW_INSET); + put1("txt", MIME_TEXT_PLAIN); + put1("ini", MIME_TEXT_PLAIN); + put1("c", MIME_TEXT_PLAIN); + put1("h", MIME_TEXT_PLAIN); + put1("cpp", MIME_TEXT_PLAIN); + put1("cxx", MIME_TEXT_PLAIN); + put1("cc", MIME_TEXT_PLAIN); + put1("chh", MIME_TEXT_PLAIN); + put1("java", MIME_TEXT_PLAIN); + put1("csv", MIME_TEXT_PLAIN); + put1("bat", MIME_TEXT_PLAIN); + put1("cmd", MIME_TEXT_PLAIN); + put1("asc", MIME_TEXT_PLAIN); + put1("rtf", MIME_TEXT_RTF); + put1("rtx", MIME_TEXT_RICHTEXT); + put1("html", MIME_TEXT_HTML); + put1("htm", MIME_TEXT_HTML); + put1("zip", MIME_APPLICATION_ZIP); + put1("rar", MIME_APPLICATION_X_RAR_COMPRESSED); + put1("gzip", MIME_APPLICATION_X_GZIP); + put1("gz", MIME_APPLICATION_X_GZIP); + put1("tgz", MIME_APPLICATION_TGZ); + put1("tar", MIME_APPLICATION_X_TAR); + put1("gif", MIME_IMAGE_GIF); + put1("jpeg", MIME_IMAGE_JPEG); + put1("jpg", MIME_IMAGE_JPEG); + put1("jpe", MIME_IMAGE_JPEG); + put1("tiff", MIME_IMAGE_TIFF); + put1("tif", MIME_IMAGE_TIFF); + put1("png", MIME_IMAGE_PNG); + put1("au", MIME_AUDIO_BASIC); + put1("snd", MIME_AUDIO_BASIC); + put1("wav", MIME_AUDIO_X_WAV); + put1("mov", MIME_VIDEO_QUICKTIME); + put1("qt", MIME_VIDEO_QUICKTIME); + put1("mpeg", MIME_VIDEO_MPEG); + put1("mpg", MIME_VIDEO_MPEG); + put1("mpe", MIME_VIDEO_MPEG); + put1("abs", MIME_VIDEO_MPEG); + put1("doc", MIME_APPLICATION_MSWORD); + put1("xls", MIME_APPLICATION_VND_MSEXCEL); + put1("eps", MIME_APPLICATION_POSTSCRIPT); + put1("ai", MIME_APPLICATION_POSTSCRIPT); + put1("ps", MIME_APPLICATION_POSTSCRIPT); + put1("pdf", MIME_APPLICATION_PDF); + put1("exe", MIME_APPLICATION_OCTET_STREAM); + put1("dll", MIME_APPLICATION_OCTET_STREAM); + put1("class", MIME_APPLICATION_OCTET_STREAM); + put1("jar", MIME_APPLICATION_JAVA_ARCHIVE); + }}; + } +} + diff --git a/src/main/java/com/codecool/quest_store/main/Main.java b/src/main/java/com/codecool/quest_store/main/Main.java new file mode 100644 index 0000000..c38435a --- /dev/null +++ b/src/main/java/com/codecool/quest_store/main/Main.java @@ -0,0 +1,28 @@ +package com.codecool.quest_store.main; + +import com.codecool.quest_store.controllers.*; +import com.codecool.quest_store.utility.FlywayMigration; +import com.sun.net.httpserver.HttpServer; + +import java.net.InetSocketAddress; + +public class Main { + public static void main( String[] args ) throws Exception { + FlywayMigration.migrateDatabase(); +// http://localhost:8000/login + HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0); + + server.createContext("/static", new Static()); + server.createContext("/login", new LoginController()); + server.createContext("/student", new StudentController()); + server.createContext("/mentor", new MentorController()); + server.createContext("/creepy-guy", new CreepyGuyController()); + server.createContext("/artifacts", new ArtifactsController()); + server.createContext("/quests", new QuestsController()); + server.createContext("/mentors", new MentorsController()); + server.createContext("/codecoolers", new StudentsController()); + server.setExecutor(null); + + server.start(); + } +} \ No newline at end of file diff --git a/src/main/java/com/codecool/quest_store/model/Funding.java b/src/main/java/com/codecool/quest_store/model/Funding.java new file mode 100644 index 0000000..4b400f0 --- /dev/null +++ b/src/main/java/com/codecool/quest_store/model/Funding.java @@ -0,0 +1,53 @@ +package com.codecool.quest_store.model; + +public class Funding { + + private final int ID; + private final int ITEM_ID; + private final int TEAM_ID; + + private Funding(Builder builder) { + this.ID = builder.ID; + this.ITEM_ID = builder.ITEM_ID; + this.TEAM_ID = builder.TEAM_ID; + } + + public int getID() { + return ID; + } + + public int getITEM_ID() { + return ITEM_ID; + } + + public int getTEAM_ID() { + return TEAM_ID; + } + + + + public static class Builder { + private int ID; + private int ITEM_ID; + private int TEAM_ID; + + public Builder withID(int ID) { + this.ID = ID; + return this; + } + + public Builder withITEM_ID(int ITEM_ID) { + this.ITEM_ID = ITEM_ID; + return this; + } + + public Builder withTEAM_ID(int TEAM_ID) { + this.TEAM_ID = TEAM_ID; + return this; + } + + public Funding build() { + return new Funding(this); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/codecool/quest_store/model/Item.java b/src/main/java/com/codecool/quest_store/model/Item.java new file mode 100644 index 0000000..9ac23ff --- /dev/null +++ b/src/main/java/com/codecool/quest_store/model/Item.java @@ -0,0 +1,90 @@ +package com.codecool.quest_store.model; + +public class Item { + + private final int ID; + private int price; + private int discountedPrice; + private String title; + private String description; + private int type; + + private Item(Builder builder) { + this.ID = builder.ID; + this.price = builder.price; + this.title = builder.title; + this.description = builder.description; + this.type = builder.type; + } + + private Item(Builder builder, float discount) { + this.ID = builder.ID; + this.price = builder.price; +// this.discountedPrice = getDiscountedPrice(discount); + this.title = builder.title; + this.description = builder.description; + this.type = builder.type; + } + + public int getID() { + return ID; + } + + public int getPrice() { + return price; + } + + public int getDiscountedPrice(int discount){ + return Math.round(price * (100-discount)/100); + } + + public String getTitle() { + return title; + } + + public String getDescription() { + return description; + } + + public int getType() { + return type; + } + + + public static class Builder { + private int ID; + private int price; + private String title; + private String description; + private int type; + + public Builder withID(int ID) { + this.ID = ID; + return this; + } + + public Builder withPrice(int price) { + this.price = price; + return this; + } + + public Builder withTitle(String title) { + this.title = title; + return this; + } + + public Builder withDescription(String description) { + this.description = description; + return this; + } + + public Builder withType(int type) { + this.type = type; + return this; + } + + public Item build() { + return new Item(this); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/codecool/quest_store/model/Level.java b/src/main/java/com/codecool/quest_store/model/Level.java new file mode 100644 index 0000000..0035056 --- /dev/null +++ b/src/main/java/com/codecool/quest_store/model/Level.java @@ -0,0 +1,4 @@ +package com.codecool.quest_store.model; + +public class Level { +} diff --git a/src/main/java/com/codecool/quest_store/model/Room.java b/src/main/java/com/codecool/quest_store/model/Room.java new file mode 100644 index 0000000..dfdf9d7 --- /dev/null +++ b/src/main/java/com/codecool/quest_store/model/Room.java @@ -0,0 +1,39 @@ +package com.codecool.quest_store.model; + +public class Room { + + private final int id; + private String roomName; + + public Room(RoomBuilder roomBuilder) { + this.id = roomBuilder.id; + this.roomName = roomBuilder.roomName; + } + + public int getId() { + return id; + } + + public String getRoomName() { + return roomName; + } + + public static class RoomBuilder { + private int id; + private String roomName; + + public RoomBuilder withId(int id) { + this.id = id; + return this; + } + + public RoomBuilder withRoomName(String roomName) { + this.roomName = roomName; + return this; + } + + public Room build() { + return new Room(this); + } + } +} diff --git a/src/main/java/com/codecool/quest_store/model/StatusHistory.java b/src/main/java/com/codecool/quest_store/model/StatusHistory.java new file mode 100644 index 0000000..423a3ac --- /dev/null +++ b/src/main/java/com/codecool/quest_store/model/StatusHistory.java @@ -0,0 +1,53 @@ +package com.codecool.quest_store.model; + +import java.time.OffsetDateTime; + +public class StatusHistory { + + private final int FUNDING_ID; + private final OffsetDateTime TIMESTAMP; + private final int STATUS_ID; + + private StatusHistory(Builder builder) { + this.FUNDING_ID = builder.FUNDING_ID; + this.TIMESTAMP = builder.TIMESTAMP; + this.STATUS_ID = builder.STATUS_ID; + } + + public int getFUNDING_ID() { + return FUNDING_ID; + } + + public OffsetDateTime getTIMESTAMP() { + return TIMESTAMP; + } + + public int getSTATUS_ID() { + return STATUS_ID; + } + + public static class Builder { + private int FUNDING_ID; + private OffsetDateTime TIMESTAMP; + private int STATUS_ID; + + public Builder withFUNDING_ID(int FUNDING_ID) { + this.FUNDING_ID = FUNDING_ID; + return this; + } + + public Builder withTIMESTAMP(OffsetDateTime TIMESTAMP) { + this.TIMESTAMP = TIMESTAMP; + return this; + } + + public Builder withSTATUS_ID(int STATUS_ID) { + this.STATUS_ID = STATUS_ID; + return this; + } + + public StatusHistory build() { + return new StatusHistory(this); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/codecool/quest_store/model/Team.java b/src/main/java/com/codecool/quest_store/model/Team.java new file mode 100644 index 0000000..c58f40d --- /dev/null +++ b/src/main/java/com/codecool/quest_store/model/Team.java @@ -0,0 +1,52 @@ +package com.codecool.quest_store.model; + +public class Team { + + private final int id; + private String teamName; + private String projectName; + + public Team(TeamBuilder teamBuilder) { + this.id = teamBuilder.id; + this.teamName = teamBuilder.teamName; + this.projectName = teamBuilder.projectName; + } + + public int getId() { + return id; + } + + public String getTeamName() { + return teamName; + } + + public String getProjectName() { + return projectName; + } + + public static class TeamBuilder{ + private int id; + private String teamName; + private String projectName; + + public TeamBuilder withId(int id){ + this.id = id; + return this; + } + + public TeamBuilder withTeamName(String teamName){ + this.teamName = teamName; + return this; + } + + public TeamBuilder withProjectName(String projectName){ + this.projectName = projectName; + return this; + } + + public Team build(){ + return new Team(this); + } + + } +} \ No newline at end of file diff --git a/src/main/java/com/codecool/quest_store/model/Transaction.java b/src/main/java/com/codecool/quest_store/model/Transaction.java new file mode 100644 index 0000000..40e3c9a --- /dev/null +++ b/src/main/java/com/codecool/quest_store/model/Transaction.java @@ -0,0 +1,83 @@ +package com.codecool.quest_store.model; + +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; + +public class Transaction { + + private final int ID; + private final int FUNDING_ID; + private final int USER_ID; + private final OffsetDateTime TIMESTAMP; + private final int PAID_AMOUNT; + + private Transaction(Builder builder) { + this.ID = builder.ID; + this.FUNDING_ID = builder.FUNDING_ID; + this.USER_ID = builder.USER_ID; + this.TIMESTAMP = builder.TIMESTAMP; + this.PAID_AMOUNT = builder.PAID_AMOUNT; + } + + public int getID() { + return ID; + } + + public int getFUNDING_ID() { + return FUNDING_ID; + } + + public int getUSER_ID() { + return USER_ID; + } + + public OffsetDateTime getTIMESTAMP() { + return TIMESTAMP; + } + + public String getFormattedDate() { + String format = "dd/MM/yy E hh:mm a"; + return TIMESTAMP.format(DateTimeFormatter.ofPattern(format)); + } + + public int getPAID_AMOUNT() { + return PAID_AMOUNT; + } + + public static class Builder { + private int ID; + private int FUNDING_ID; + private int USER_ID; + private OffsetDateTime TIMESTAMP; + private int PAID_AMOUNT; + + public Builder withID(int ID) { + this.ID = ID; + return this; + } + + public Builder withFUNDING_ID(int FUNDING_ID) { + this.FUNDING_ID = FUNDING_ID; + return this; + } + + public Builder withUSER_ID(int USER_ID) { + this.USER_ID = USER_ID; + return this; + } + + public Builder withTIMESTAMP(OffsetDateTime TIMESTAMP) { + this.TIMESTAMP = TIMESTAMP; + return this; + } + + public Builder withPAID_AMOUNT(int PAID_AMOUNT) { + this.PAID_AMOUNT = PAID_AMOUNT; + return this; + } + + public Transaction build() { + return new Transaction(this); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/codecool/quest_store/model/User.java b/src/main/java/com/codecool/quest_store/model/User.java new file mode 100644 index 0000000..df5d9bc --- /dev/null +++ b/src/main/java/com/codecool/quest_store/model/User.java @@ -0,0 +1,171 @@ +package com.codecool.quest_store.model; + +public class User { + private final int id; + private String name; + private String surname; + private String phoneNumber; + private String email; + private String password; + private String photo; + private int typeId; + private int roomId; + private int teamId; + + + public User(UserBuilder builder) { + this.id = builder.id; + this.name = builder.name; + this.surname = builder.surname; + this.phoneNumber = builder.phoneNumber; + this.email = builder.email; + this.password = builder.password; + this.photo = builder.photo; + this.typeId = builder.typeId; + this.roomId = builder.roomId; + this.teamId = builder.teamId; + } + + public int getId(){ + return id; + } + + public String getName() { + return name; + } + + public String getSurname() { + return surname; + } + + public String getPhoneNumber() { + return phoneNumber; + } + + public String getEmail() { + return email; + } + + public String getPassword() { + return password; + } + + public String getPhoto() { + return photo; + } + + public int getTypeId() { + return typeId; + } + + public int getRoomId() { + return roomId; + } + + public int getTeamId() { + return teamId; + } + + public void setName(String name) { + this.name = name; + } + + public void setSurname(String surname) { + this.surname = surname; + } + + public void setPhoneNumber(String phoneNumber) { + this.phoneNumber = phoneNumber; + } + + public void setEmail(String email) { + this.email = email; + } + + public void setPassword(String password) { + this.password = password; + } + + public void setPhoto(String photo) { + this.photo = photo; + } + + public void setTypeId(int typeId) { + this.typeId = typeId; + } + + public void setRoomId(int roomId) { + this.roomId = roomId; + } + + public void setTeamId(int teamId) { + this.teamId = teamId; + } + + public static class UserBuilder { + private int id; + private String name; + private String surname; + private String phoneNumber; + private String email; + private String password; + private String photo; + private int typeId; + private int roomId; + private int teamId; + + public UserBuilder withId(int id) { + this.id = id; + return this; + } + + public UserBuilder withName(String name) { + this.name = name; + return this; + } + + public UserBuilder withSurname(String surname) { + this.surname = surname; + return this; + } + + public UserBuilder withPhoneNumber(String phoneNumber) { + this.phoneNumber = phoneNumber; + return this; + } + + public UserBuilder withEmail(String email) { + this.email = email; + return this; + } + + public UserBuilder withPassword(String password) { + this.password = password; + return this; + } + + public UserBuilder withPhoto(String photo) { + this.photo = photo; + return this; + } + + public UserBuilder withTypeId(int typeId) { + this.typeId = typeId; + return this; + } + + public UserBuilder withRoomId(int roomId) { + this.roomId = roomId; + return this; + } + + public UserBuilder withTeamId(int teamId) { + this.teamId = teamId; + return this; + } + + public User build() { + return new User(this); + } + } +} diff --git a/src/main/java/com/codecool/quest_store/model/UserDefaultPhoto.java b/src/main/java/com/codecool/quest_store/model/UserDefaultPhoto.java new file mode 100644 index 0000000..27f94b1 --- /dev/null +++ b/src/main/java/com/codecool/quest_store/model/UserDefaultPhoto.java @@ -0,0 +1,19 @@ +package com.codecool.quest_store.model; + +public enum UserDefaultPhoto { + + CREEPY_GUY("../static/assets/images/user-icons/creepy-guy.png"), + MENTOR("../static/assets/images/user-icons/mentor.png"), + CODECOOLER("../static/assets/images/user-icons/codecooler.png"); + + private String userPhoto; + + private UserDefaultPhoto(String userPhoto) { + this.userPhoto = userPhoto; + } + + public String getUserPhoto() { + return this.userPhoto; + } +} + diff --git a/src/main/java/com/codecool/quest_store/service/ArtifactsService.java b/src/main/java/com/codecool/quest_store/service/ArtifactsService.java new file mode 100644 index 0000000..9ca2129 --- /dev/null +++ b/src/main/java/com/codecool/quest_store/service/ArtifactsService.java @@ -0,0 +1,116 @@ +package com.codecool.quest_store.service; + +import com.codecool.quest_store.dao.*; +import com.codecool.quest_store.model.Funding; +import com.codecool.quest_store.model.Item; +import com.codecool.quest_store.model.User; +import com.sun.net.httpserver.HttpExchange; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.List; +import java.util.Map; + +public class ArtifactsService { + + private ItemDao itemDAO; + private TransactionDao transactionDao; + private ItemService itemService; + public static final int NORMAL_ARTIFACT_TYPE = 1; + public static final int MAGIC_ARTIFACT_TYPE = 2; + + + public ArtifactsService() { + this.itemDAO = new ItemDaoImpl(); + this.transactionDao = new TransactionDaoImpl(); + this.itemService = new ItemService(); + } + + public List getNormalArtifacts() { + return itemService.getAllItemsOfType(NORMAL_ARTIFACT_TYPE); + } + + + public List getMagicArtifacts() { + return itemService.getAllItemsOfType(MAGIC_ARTIFACT_TYPE); + } + + public String respondToPostMethod(HttpExchange httpExchange, User user) throws IOException { + String postData = new BufferedReader(new InputStreamReader(httpExchange.getRequestBody())).readLine(); + Map postMap = ServiceUtility.parseData(postData, "&"); + + if (postMap.keySet().contains("artifactId") && user.getTypeId() == 1) { + int artifactId = Integer.parseInt(postMap.get("artifactId")); + try { + return handleArtifactPurchase(user, itemDAO.getItemById(artifactId)); + } catch (DaoException e) { + e.printStackTrace(); + return e.getMessage(); + } + } else if (postMap.keySet().contains("newDiscount") && user.getTypeId() == 2) { + int newDiscount = Integer.parseInt(postMap.get("newDiscount")); + try { + return handleDiscountChange(newDiscount); + } catch (DaoException e) { + e.printStackTrace(); + return e.getMessage(); + } + } return "Invalid request"; + } + + private String handleDiscountChange(int newDiscount) throws DaoException { + itemDAO.setDiscount(newDiscount); + return "Discount changed"; + } + + private String handleArtifactPurchase(User user, Item artifact) throws DaoException { + if (artifact.getType() == 1) { + return handleIndividualPurchase(user, artifact); + } else { + return handleTeamPurchase(); //descoped from this sprint + } + } + + + private String handleIndividualPurchase(User user, Item artifact) throws DaoException { + if (canAffordPurchase(user, artifact)) { + Funding newFunding = itemService.registerNewFunding(user, artifact); + itemService.registerNewTransaction(newFunding, user); + itemService.updateFundingStatusAsPending(newFunding); + return "Artifact purchased"; +// need to update funding status? or can it auto-update + } + return insufficientFundsResponse(); + } + + + private String insufficientFundsResponse() { + System.out.println("Insufficient funds"); + return "Insufficient funds"; + } + + + private boolean canAffordPurchase(User user, Item artifact) throws DaoException { + int balance = + transactionDao.getPriceSumOfRealizedQuests(user) + - transactionDao.getPriceSumOfPurchasedArtifacts(user); +// System.out.println("Balance = " + balance + ", price = " + artifact.getPrice()); + return balance > artifact.getDiscountedPrice(itemDAO.getDiscount()); + } + + private String handleTeamPurchase() { + return ""; + } + + public int getDiscount() { + int discount; + try { + discount = itemDAO.getDiscount(); + } catch (DaoException e) { + discount = 0; + e.printStackTrace(); + } + return discount; + } +} diff --git a/src/main/java/com/codecool/quest_store/service/CreepyGuyService.java b/src/main/java/com/codecool/quest_store/service/CreepyGuyService.java new file mode 100644 index 0000000..613c14b --- /dev/null +++ b/src/main/java/com/codecool/quest_store/service/CreepyGuyService.java @@ -0,0 +1,33 @@ +package com.codecool.quest_store.service; + +import com.codecool.quest_store.dao.Dao; +import com.codecool.quest_store.dao.DaoException; +import com.codecool.quest_store.dao.RoomDaoImpl; + +import com.codecool.quest_store.model.Room; + +import com.codecool.quest_store.view.View; + +public class CreepyGuyService { + + private Dao roomDao; + private View view; + + public CreepyGuyService() { + roomDao = new RoomDaoImpl(); + view = new View(); + } + + public void createRoom(String name) { + Room room = new Room.RoomBuilder() + .withRoomName(name) + .build(); + + try { + roomDao.create(room); + view.printSuccess("Room has been created."); + } catch (DaoException e) { + view.printError(e.getMessage()); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/codecool/quest_store/service/EmployeeService.java b/src/main/java/com/codecool/quest_store/service/EmployeeService.java new file mode 100644 index 0000000..7eddeb4 --- /dev/null +++ b/src/main/java/com/codecool/quest_store/service/EmployeeService.java @@ -0,0 +1,74 @@ +package com.codecool.quest_store.service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import com.codecool.quest_store.dao.Dao; +import com.codecool.quest_store.dao.DaoException; +import com.codecool.quest_store.dao.RoomDao; +import com.codecool.quest_store.dao.RoomDaoImpl; +import com.codecool.quest_store.dao.UserDao; +import com.codecool.quest_store.dao.UserDaoImpl; + +import com.codecool.quest_store.model.User; + +import com.codecool.quest_store.model.UserDefaultPhoto; +import com.codecool.quest_store.view.View; + +public class EmployeeService { + + private Dao dao; + private UserDao userDao; + private RoomDao roomDao; + private View view; + + public EmployeeService() { + dao = new UserDaoImpl(); + userDao = new UserDaoImpl(); + roomDao = new RoomDaoImpl(); + view = new View(); + } + + public void createUser(String name, String surname, String email, int userType, UserDefaultPhoto USER_PHOTO) { + User user = new User.UserBuilder() + .withName(name) + .withSurname(surname) + .withPhoneNumber(null) + .withEmail(email) + .withPassword("123") + .withPhoto(USER_PHOTO.getUserPhoto()) + .withTypeId(userType) + .withRoomId(getRoomTypes().get("ProgBasic")) + .build(); + + try { + dao.create(user); + view.printSuccess("User has been created."); + } catch (DaoException e) { + view.printError(e.getMessage()); + } + } + + public List getUsers(int userType) { + List users = new ArrayList<>(); + + try { + users = userDao.getUsersByType(userType); + view.printSuccess("Successfully retrieved users."); + } catch (DaoException e) { + view.printError(e.getMessage()); + } + return users; + } + + private Map getRoomTypes() { + Map roomTypes = null; + try { + roomTypes = roomDao.getRoomTypes(); + } catch (DaoException e) { + view.printError("Failed to get ProgBasic's type of room"); + } + return roomTypes; + } +} \ No newline at end of file diff --git a/src/main/java/com/codecool/quest_store/service/ItemService.java b/src/main/java/com/codecool/quest_store/service/ItemService.java new file mode 100644 index 0000000..0c2db61 --- /dev/null +++ b/src/main/java/com/codecool/quest_store/service/ItemService.java @@ -0,0 +1,124 @@ +package com.codecool.quest_store.service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; + +import org.apache.commons.lang3.ArrayUtils; + +import com.codecool.quest_store.dao.*; +import com.codecool.quest_store.model.Funding; +import com.codecool.quest_store.model.Item; +import com.codecool.quest_store.model.Transaction; +import com.codecool.quest_store.model.User; +import com.codecool.quest_store.view.View; + +public class ItemService { + + private ItemDao itemDAO; + private TransactionDao transactionDao; + private FundingDao fundingDao; + private View view; + + private static final int[] ARTIFACT_TYPES = {1, 2}; + private static final int[] QUEST_TYPES = {3, 4}; + + public ItemService() { + this.itemDAO = new ItemDaoImpl(); + this.transactionDao = new TransactionDaoImpl(); + this.fundingDao = new FundingDaoImpl(); + view = new View(); + } + + public List getAllItemsOfType(int itemType) { + List itemsOfType = new ArrayList<>(); + List allItems = new ArrayList<>(); + try { + allItems = itemDAO.getAllItems(); + } catch (DaoException e) { + e.printStackTrace(); + } + for (Item item : allItems) { + if (item.getType() == itemType) itemsOfType.add(item); + } + return itemsOfType; + } + + public List getItemsByType(int itemType, List items) { + List itemsOfType = new ArrayList<>(); + List allItems = items; + + for (Item item : allItems) { + if (item.getType() == itemType) itemsOfType.add(item); + } + return itemsOfType; + } + + public Item getItemById(int id) throws DaoException { + return itemDAO.getItemById(id); + } + + public void registerNewTransaction(Funding funding, User user) throws DaoException { + Transaction newTransaction; + Item item = itemDAO.getItemById(funding.getITEM_ID()); + if (isArtifact(item)) { + newTransaction = new Transaction.Builder() + .withFUNDING_ID(funding.getID()) + .withUSER_ID(user.getId()) + .withTIMESTAMP(OffsetDateTime.now(ZoneOffset.UTC)) + .withPAID_AMOUNT(item.getDiscountedPrice(itemDAO.getDiscount())) + .build(); + } else { + newTransaction = new Transaction.Builder() + .withFUNDING_ID(funding.getID()) + .withUSER_ID(user.getId()) + .withTIMESTAMP(OffsetDateTime.now(ZoneOffset.UTC)) + .withPAID_AMOUNT(item.getPrice()) + .build(); + } + ((Dao) transactionDao).create(newTransaction); + } + + private boolean isArtifact(Item item) { + return ArrayUtils.contains(ARTIFACT_TYPES, item.getType()); + } + + private boolean isQuest(Item item) { + return ArrayUtils.contains(QUEST_TYPES, item.getType()); + } + + public Funding registerNewFunding(User user, Item item) throws DaoException { + int newFundingId = fundingDao.getFundingSequenceNextVal(); + Funding newFunding; + if (user.getTeamId() != 0) { + newFunding = new Funding.Builder() + .withID(newFundingId) + .withITEM_ID(item.getID()) + .withTEAM_ID(user.getTeamId()) + .build(); + } else { + newFunding = new Funding.Builder() + .withID(newFundingId) + .withITEM_ID(item.getID()) + .build(); + } + fundingDao.create(newFunding); + return newFunding; + } + + public void updateFundingStatusAsPending(Funding funding) throws DaoException { + fundingDao.updateFundingStatus(funding, 2); + } + + public Map getItemTypes() { + Map itemTypes = null; + try { + itemTypes = itemDAO.getItemTypes(); + } catch (DaoException e) { + view.printError(e.getMessage()); + } + return itemTypes; + } +} diff --git a/src/main/java/com/codecool/quest_store/service/LoginService.java b/src/main/java/com/codecool/quest_store/service/LoginService.java new file mode 100644 index 0000000..ba2697b --- /dev/null +++ b/src/main/java/com/codecool/quest_store/service/LoginService.java @@ -0,0 +1,45 @@ +package com.codecool.quest_store.service; + +import com.codecool.quest_store.dao.DaoException; +import com.codecool.quest_store.dao.SessionDaoImpl; +import com.codecool.quest_store.dao.UserDaoImpl; +import com.codecool.quest_store.model.User; + +import java.security.SecureRandom; + +public class LoginService { + + UserDaoImpl userDao; + SessionDaoImpl sessionDao; + + public LoginService() { + userDao = new UserDaoImpl(); + sessionDao = new SessionDaoImpl(); + } + + public User getUser(String name, String password) { + try { + return userDao.getIdAndUserType(name, password); + } catch (DaoException error) { + error.printStackTrace(); + } + return null; + } + + public void createSession(int session, int userId) { + try { + sessionDao.createSession(session, userId); + } catch (DaoException error) { + error.printStackTrace(); + } + } + + public void deleteSession(int session) throws DaoException{ + sessionDao.deleteSession(session); + } + + public int generateNewSessionId() { + SecureRandom secureRandom = new SecureRandom(); + return secureRandom.nextInt(); + } +} diff --git a/src/main/java/com/codecool/quest_store/service/MentorService.java b/src/main/java/com/codecool/quest_store/service/MentorService.java new file mode 100644 index 0000000..c6ffe81 --- /dev/null +++ b/src/main/java/com/codecool/quest_store/service/MentorService.java @@ -0,0 +1,36 @@ +package com.codecool.quest_store.service; + +import com.codecool.quest_store.dao.Dao; +import com.codecool.quest_store.dao.DaoException; +import com.codecool.quest_store.dao.ItemDaoImpl; + +import com.codecool.quest_store.model.Item; + +import com.codecool.quest_store.view.View; + +public class MentorService { + + private Dao itemDao; + private View view; + + public MentorService() { + itemDao = new ItemDaoImpl(); + view = new View(); + } + + public void createItem(String title, String description, int price, int itemType) { + Item item = new Item.Builder() + .withTitle(title) + .withDescription(description) + .withPrice(price) + .withType(itemType) + .build(); + + try { + itemDao.create(item); + view.printSuccess("Item has been created"); + } catch (DaoException e) { + view.printError(e.getMessage()); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/codecool/quest_store/service/QuestService.java b/src/main/java/com/codecool/quest_store/service/QuestService.java new file mode 100644 index 0000000..3daf0b7 --- /dev/null +++ b/src/main/java/com/codecool/quest_store/service/QuestService.java @@ -0,0 +1,65 @@ +package com.codecool.quest_store.service; + +import com.codecool.quest_store.dao.*; +import com.codecool.quest_store.model.Funding; +import com.codecool.quest_store.model.Item; +import com.codecool.quest_store.model.User; +import com.sun.net.httpserver.HttpExchange; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.List; +import java.util.Map; + +public class QuestService { + + + private ItemDao itemDAO; + private TransactionDao transactionDao; + private FundingDao fundingDao; + private ServiceUtility serviceUtility; + private ItemService itemService; + public static final int BASIC_QUEST_TYPE = 3; + public static final int EXTRA_QUEST_TYPE = 4; + + public QuestService(){ + this.itemDAO = new ItemDaoImpl(); + this.transactionDao = new TransactionDaoImpl(); + this.fundingDao = new FundingDaoImpl(); + this.serviceUtility = new ServiceUtility(); + this.itemService = new ItemService(); + } + + public String respondToPostMethod(HttpExchange httpExchange, User user) throws IOException { + String postData = new BufferedReader(new InputStreamReader(httpExchange.getRequestBody())).readLine(); + Map postMap = serviceUtility.parseData(postData, "&"); + + if (user.getTypeId() == 1) { + int questId = Integer.parseInt(postMap.get("questId")); + try { + return handleQuestClaim(user, itemDAO.getItemById(questId)); + } catch (DaoException e) { + e.printStackTrace(); + return e.getMessage(); + } + } + return "Invalid request"; + } + + private String handleQuestClaim(User user, Item quest) throws DaoException { + Funding newFunding = itemService.registerNewFunding(user, quest); + itemService.registerNewTransaction(newFunding, user); + itemService.updateFundingStatusAsPending(newFunding); + return ""; + } + + public List getBasicQuests() { + return itemService.getAllItemsOfType(BASIC_QUEST_TYPE); + } + + public List getExtraQuests() { + return itemService.getAllItemsOfType(EXTRA_QUEST_TYPE); + } + +} diff --git a/src/main/java/com/codecool/quest_store/service/ServiceUtility.java b/src/main/java/com/codecool/quest_store/service/ServiceUtility.java new file mode 100644 index 0000000..e5b89ed --- /dev/null +++ b/src/main/java/com/codecool/quest_store/service/ServiceUtility.java @@ -0,0 +1,55 @@ +package com.codecool.quest_store.service; + +import com.sun.net.httpserver.HttpExchange; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +public class ServiceUtility { + + public static final String AND = "&"; + public static final String SEMICOLON = "; "; + + public static Map parseData(String formData, String parsingSign) throws UnsupportedEncodingException { + Map map = new HashMap<>(); + String[] pairs = formData.split(parsingSign); + for(String pair : pairs){ + String[] keyValue = pair.split("="); + String value = URLDecoder.decode(keyValue[1], "UTF-8"); + map.put(keyValue[0], value); + } + return map; + } + + public static void sendResponse(HttpExchange httpExchange, String response) throws IOException { + httpExchange.sendResponseHeaders(200, response.getBytes().length); + OutputStream os = httpExchange.getResponseBody(); + os.write(response.getBytes()); + os.close(); + } + + public static void redirectToContext(HttpExchange httpExchange, String response, String contextPath) throws IOException{ + httpExchange.getResponseHeaders().set("Location", contextPath); + + httpExchange.sendResponseHeaders(302, response.getBytes().length); + + OutputStream outputStream = httpExchange.getResponseBody(); + outputStream.write(response.getBytes(Charset.forName("UTF-8"))); + outputStream.close(); + } + + public static Map getPOSTInputs(HttpExchange httpExchange) throws IOException { + InputStreamReader inputStreamReader = new InputStreamReader(httpExchange.getRequestBody(), StandardCharsets.UTF_8); + BufferedReader bufferedReader = new BufferedReader(inputStreamReader); + String data = bufferedReader.readLine(); + return ServiceUtility.parseData(data, ServiceUtility.AND); + } +} diff --git a/src/main/java/com/codecool/quest_store/service/UserService.java b/src/main/java/com/codecool/quest_store/service/UserService.java new file mode 100644 index 0000000..b44a438 --- /dev/null +++ b/src/main/java/com/codecool/quest_store/service/UserService.java @@ -0,0 +1,107 @@ +package com.codecool.quest_store.service; + +import java.io.UnsupportedEncodingException; +import java.util.List; +import java.util.Map; + +import com.codecool.quest_store.dao.*; +import com.codecool.quest_store.model.Item; +import com.codecool.quest_store.model.User; +import com.codecool.quest_store.view.View; + +public class UserService { + private UserDaoImpl userDao; + private SessionDaoImpl sessionDao; + private ItemDaoImpl itemDao; + private ItemService itemService; + private TransactionDaoImpl transactionDao; + private LoginService loginService; + private View view; + + public UserService() { + userDao = new UserDaoImpl(); + sessionDao = new SessionDaoImpl(); + itemDao = new ItemDaoImpl(); + itemService = new ItemService(); + transactionDao = new TransactionDaoImpl(); + loginService = new LoginService(); + view = new View(); + } + + private User getUser(int userId) throws DaoException { + return userDao.getUser(userId); + } + + private Integer getUserId(int session) throws DaoException { + return sessionDao.getUserId(session); + } + + private Integer getSessionFromCookie(String cookie) throws UnsupportedEncodingException { + if(!(Integer.valueOf(ServiceUtility.parseData(cookie, ServiceUtility.SEMICOLON).get("session") + .replace("\"", "")) == null)) { + return Integer.valueOf(ServiceUtility.parseData(cookie, ServiceUtility.SEMICOLON).get("session") + .replace("\"", "")); + } + return null; + } + + public User getUserByCookie(String cookie) { + try { + int session = getSessionFromCookie(cookie); + return getUser(getUserId(session)); + } + catch(UnsupportedEncodingException | DaoException error){ + view.printError(error.getMessage()); + } + return null; + } + + private List getUserItems(int userId) { + try { + return itemDao.getUserItems(userId); + } catch (DaoException error) { + view.printError(error.getMessage()); + } + return null; + } + + public List getUserArtifacts(int userId) { + return itemService.getItemsByType(ArtifactsService.NORMAL_ARTIFACT_TYPE, getUserItems(userId)); + } + + public List getUserBasicQuests(int userId) { + return itemService.getItemsByType(QuestService.BASIC_QUEST_TYPE, getUserItems(userId)); + } + + public List getUserExtraQuests(int userId) { + return itemService.getItemsByType(QuestService.EXTRA_QUEST_TYPE, getUserItems(userId)); + } + + public Integer getBalance(User user) { + try { + return transactionDao.getPriceSumOfRealizedQuests(user) + - transactionDao.getPriceSumOfPurchasedArtifacts(user); + } catch (DaoException error) { + view.printError(error.getMessage()); + } + return null; + } + + public void deleteSession(String cookie) { + try{ + loginService.deleteSession(getSessionFromCookie(cookie)); + } catch (UnsupportedEncodingException | DaoException error) { + view.printError(error.getMessage()); + } + } + + public Map getUserTypes() { + Map userTypes = null; + try { + userTypes = userDao.getUserTypes(); + } catch (DaoException e) { + view.printError(e.getMessage()); + } + return userTypes; + } +} diff --git a/src/main/java/com/codecool/quest_store/utility/ConfigFileParser.java b/src/main/java/com/codecool/quest_store/utility/ConfigFileParser.java new file mode 100644 index 0000000..1ef7dd9 --- /dev/null +++ b/src/main/java/com/codecool/quest_store/utility/ConfigFileParser.java @@ -0,0 +1,45 @@ +package com.codecool.quest_store.utility; + +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import java.io.FileReader; +import java.io.IOException; + +public class ConfigFileParser { + + private static final String CONFIG_FILE_PATH = "src/main/resources/config.json"; + + + public static String getDatabaseURL() throws IOException, ParseException { + + JSONObject jsonObject = getJsonObjectFromConfigFile(); + + return ((JSONObject) jsonObject.get("databaseCredentials")).get("url").toString(); +} + + public static String getDatabaseUser() throws IOException, ParseException { + + JSONObject jsonObject = getJsonObjectFromConfigFile(); + + return ((JSONObject) jsonObject.get("databaseCredentials")).get("user").toString(); +} + + public static String getDatabasePassword() throws IOException, ParseException { + + JSONObject jsonObject = getJsonObjectFromConfigFile(); + + return ((JSONObject) jsonObject.get("databaseCredentials")).get("password").toString(); +} + + + private static JSONObject getJsonObjectFromConfigFile() throws IOException, ParseException { + FileReader fileReader = new FileReader(CONFIG_FILE_PATH); + JSONParser jsonParser = new JSONParser(); + + Object object = jsonParser.parse(fileReader); + + return (JSONObject) object; + } +} diff --git a/src/main/java/com/codecool/quest_store/utility/FlywayMigration.java b/src/main/java/com/codecool/quest_store/utility/FlywayMigration.java new file mode 100644 index 0000000..64a1680 --- /dev/null +++ b/src/main/java/com/codecool/quest_store/utility/FlywayMigration.java @@ -0,0 +1,19 @@ +package com.codecool.quest_store.utility; + +import com.codecool.quest_store.dao.DatabaseConnector; +import org.flywaydb.core.Flyway; + +import javax.sql.DataSource; + +public class FlywayMigration { + + public static void migrateDatabase(){ + + DataSource dataSource = DatabaseConnector.getDs(); + Flyway flyway = Flyway.configure().dataSource(dataSource).load(); + + flyway.migrate(); + System.out.println("Flyway: database migration complete"); + + } +} diff --git a/src/main/java/com/codecool/quest_store/view/View.java b/src/main/java/com/codecool/quest_store/view/View.java new file mode 100644 index 0000000..e59e84b --- /dev/null +++ b/src/main/java/com/codecool/quest_store/view/View.java @@ -0,0 +1,18 @@ +package com.codecool.quest_store.view; + +public class View { + + private void print(String message) { + System.out.println(message); + } + + public void printError(String message) { + System.err.println(message); + } + + public void printSuccess(String message) { + final String GREEN = "\u001B[32m"; + final String RESET = "\u001B[0m"; + print(GREEN + message + RESET); + } +} \ No newline at end of file diff --git a/src/main/resources/db/migration/V10__create_discount_table.sql b/src/main/resources/db/migration/V10__create_discount_table.sql new file mode 100644 index 0000000..6b33393 --- /dev/null +++ b/src/main/resources/db/migration/V10__create_discount_table.sql @@ -0,0 +1,6 @@ +CREATE TABLE discount +( + id serial, + discount float, + PRIMARY KEY (id) +); \ No newline at end of file diff --git a/src/main/resources/db/migration/V11__add_item_to_student.sql b/src/main/resources/db/migration/V11__add_item_to_student.sql new file mode 100644 index 0000000..be9de11 --- /dev/null +++ b/src/main/resources/db/migration/V11__add_item_to_student.sql @@ -0,0 +1,25 @@ +INSERT INTO fundings(item_id, team_id) +VALUES(14, null);-- + +INSERT INTO fundings(item_id, team_id) +VALUES(1, null); + +INSERT INTO transactions(funding_id, user_id, timestamp, paid_amount) +VALUES(1, 1, null, 50); + +INSERT INTO transactions(funding_id, user_id, timestamp, paid_amount) +VALUES(2, 1, null, 100); + +INSERT INTO status_history(funding_id, status_id, timestamp) +VALUES(1, 2, null); + +INSERT INTO status_history(funding_id, status_id, timestamp) +VALUES(2, 2, null); + +SELECT * FROM items +INNER JOIN fundings ON items.id = fundings.item_id +INNER JOIN transactions ON transactions.funding_id = fundings.id +INNER JOIN status_history ON status_history.funding_id = fundings.id +INNER JOIN statuses ON statuses.id = status_history.status_id +WHERE transactions.user_id = 1 +AND statuses.type = 'Pending'; \ No newline at end of file diff --git a/src/main/resources/db/migration/V12__add_initial_discount.sql b/src/main/resources/db/migration/V12__add_initial_discount.sql new file mode 100644 index 0000000..769c1da --- /dev/null +++ b/src/main/resources/db/migration/V12__add_initial_discount.sql @@ -0,0 +1,2 @@ +INSERT INTO discount (discount) +VALUES (0); \ No newline at end of file diff --git a/src/main/resources/db/migration/V1__create_database.sql b/src/main/resources/db/migration/V1__create_database.sql new file mode 100644 index 0000000..631fd5f --- /dev/null +++ b/src/main/resources/db/migration/V1__create_database.sql @@ -0,0 +1,178 @@ +--user_types +CREATE TABLE user_types +( + id serial, + type text, + PRIMARY KEY (id) +); +INSERT INTO user_types(type) VALUES('Codecooler'); +INSERT INTO user_types(type) VALUES('Mentor'); +INSERT INTO user_types(type) VALUES('Creepy Guy'); + +--item_types +CREATE TABLE item_types +( + id serial, + type text, + grade text, + PRIMARY KEY (id) +); +INSERT INTO item_types(type, grade) VALUES('Artifact', 'Normal'); +INSERT INTO item_types(type, grade) VALUES('Artifact', 'Magic'); +INSERT INTO item_types(type, grade) VALUES('Quest', 'Basic'); +INSERT INTO item_types(type, grade) VALUES('Quest', 'Extra'); + +--rooms +CREATE TABLE rooms +( + id serial, + name text, + PRIMARY KEY (id) +); +INSERT INTO rooms(name) VALUES('ProgBasic'); +INSERT INTO rooms(name) VALUES('Java'); +INSERT INTO rooms(name) VALUES('Web'); +INSERT INTO rooms(name) VALUES('Advanced'); + +--levels +CREATE TABLE levels +( + id serial, + name text, +level_from int, +level_to int, + PRIMARY KEY (id) +); +INSERT INTO levels(name, level_from, level_to) VALUES('junior', 0, 2000); +INSERT INTO levels(name, level_from, level_to) VALUES('medium', 2001, 4000); +INSERT INTO levels(name, level_from, level_to) VALUES('senior', 4001, 6000); + +--statuses +CREATE TABLE statuses +( + id serial, + type text, + PRIMARY KEY (id) +); +INSERT INTO statuses(type) VALUES('In progress'); +INSERT INTO statuses(type) VALUES('Pending'); +INSERT INTO statuses(type) VALUES('Realized'); +INSERT INTO statuses(type) VALUES('Rejected'); + +--teams +CREATE TABLE teams +( + id serial, + name text, + project_name text, + PRIMARY KEY (id) +); +INSERT INTO teams(name, project_name) VALUES('foxes', 'Slack'); +INSERT INTO teams(name, project_name) VALUES('bears', 'Quest store'); +INSERT INTO teams(name, project_name) VALUES('sharks', 'Klondike'); + +--users +CREATE TABLE users +( + id serial, + name text, + surname text, + phone_number text, + email text, + password text, + photo text, + id_user_type int, + id_room int, + id_team int, + PRIMARY KEY (id), + FOREIGN KEY (id_user_type) REFERENCES user_types (id), + FOREIGN KEY (id_team) REFERENCES teams (id), + FOREIGN KEY (id_room) REFERENCES rooms (id) +); + +INSERT INTO users(name, surname, phone_number, email, password, photo, id_user_type, id_team, id_room) +VALUES('Tatiana', 'Slonimskaia', '881', '@123', '123', '', 1, 1, 1); + +--map_of_rooms +CREATE TABLE map_of_rooms +( + id serial, + id_user int, + id_room int, + PRIMARY KEY (id), + FOREIGN KEY (id_user) REFERENCES users (id), + FOREIGN KEY (id_room) REFERENCES rooms (id) +); + +--items +CREATE TABLE items +( + id serial, + price int, + title text, + description text, + item_type int, + PRIMARY KEY (id), + FOREIGN KEY (item_type) REFERENCES item_types (id) +); + +INSERT INTO items(price, title, description, item_type) +VALUES(100, 'Exploring a dungeon', 'Finishing a Teamwork week', 3); +INSERT INTO items(price, title, description, item_type) +VALUES(100, 'Solving the magic puzzle', 'Finishing an SI assignment', 3); +INSERT INTO items(price, title, description, item_type) +VALUES(500, 'Slaying a dragon', 'Passing a Checkpoint', 3); +INSERT INTO items(price, title, description, item_type) +VALUES(50, 'Spot trap', 'Spot a major mistake in the assignment', 4); +INSERT INTO items(price, title, description, item_type) +VALUES(100, 'Taming a pet', 'Doing a demo about a pet project', 4); +INSERT INTO items(price, title, description, item_type) +VALUES(100, 'Recruiting some n00bs', 'Taking part in the student screening process', 4); +INSERT INTO items(price, title, description, item_type) +VALUES(400, 'Forging weapons', 'Organizing a workshop for other students', 4); +INSERT INTO items(price, title, description, item_type) +VALUES(300, 'Master the mornings', 'Attend 1 months without being late', 4); +INSERT INTO items(price, title, description, item_type) +VALUES(500, 'Fast as an unicorn', 'Deliver 4 consecutive SI week assignments on time', 4); +INSERT INTO items(price, title, description, item_type) +VALUES(500, 'Achiever', 'Set up a SMART goal accepted by a mentor, then achieve it', 4); +INSERT INTO items(price, title, description, item_type) +VALUES(500, 'Fortune', 'Students choose the best project of the week. Selected team scores', 4); +INSERT INTO items(price, title, description, item_type) +VALUES(500, 'Creating an enchanted scroll', 'Creating extra material for the current TW/SI topic (should be revised by mentors)', 4); +INSERT INTO items(price, title, description, item_type) +VALUES(500, 'Enter the arena', 'Do a presentation on a meet-up', 4); +INSERT INTO items(price, title, description, item_type) +VALUES(50, 'Combat training', 'Private mentoring', 1); +INSERT INTO items(price, title, description, item_type) +VALUES(300, 'Sanctuary', 'You can spend a day in home office', 1); +INSERT INTO items(price, title, description, item_type) +VALUES(500, 'Time Travel', 'extend SI week assignment deadline by one day', 1); +INSERT INTO items(price, title, description, item_type) +VALUES(1000, 'Circle of Sorcery', '60 min workshop by a mentor(s) of the chosen topic', 2); +INSERT INTO items(price, title, description, item_type) +VALUES(1000, 'Summon Code Elemental', 'mentor joins a students team for a one hour', 2); +INSERT INTO items(price, title, description, item_type) +VALUES(500, 'Tome of knowledge', 'Extra material for the current topic', 2); +INSERT INTO items(price, title, description, item_type) +VALUES(5000, 'Transform mentors', 'All mentors should dress up as pirates (or just funny) for the day', 2); +INSERT INTO items(price, title, description, item_type) +VALUES(30000, 'Teleport ', 'The whole course goes to an off-school program instead for a day', 2); + +--transactions +CREATE TABLE transactions +( + id serial, + id_funding int, + id_user int, + id_team int, + id_item int, + id_status int, + timestamp text, + coins_amount int, + PRIMARY KEY (id), + FOREIGN KEY (id_user) REFERENCES users (id), + FOREIGN KEY (id_team) REFERENCES teams (id), + FOREIGN KEY (id_item) REFERENCES items (id), + FOREIGN KEY (id_status) REFERENCES statuses (id) +); \ No newline at end of file diff --git a/src/main/resources/db/migration/V2__create_dummy_table.sql b/src/main/resources/db/migration/V2__create_dummy_table.sql new file mode 100644 index 0000000..0751ab2 --- /dev/null +++ b/src/main/resources/db/migration/V2__create_dummy_table.sql @@ -0,0 +1,5 @@ +create table dummyTable +( + id int, + primary key (id) +); diff --git a/src/main/resources/db/migration/V3__alter_coins_amount_column.sql b/src/main/resources/db/migration/V3__alter_coins_amount_column.sql new file mode 100644 index 0000000..def0b83 --- /dev/null +++ b/src/main/resources/db/migration/V3__alter_coins_amount_column.sql @@ -0,0 +1,2 @@ +ALTER TABLE transactions + RENAME COLUMN coins_amount TO paid_amount; \ No newline at end of file diff --git a/src/main/resources/db/migration/V4__rename_columns_with_id.sql b/src/main/resources/db/migration/V4__rename_columns_with_id.sql new file mode 100644 index 0000000..e2a49e1 --- /dev/null +++ b/src/main/resources/db/migration/V4__rename_columns_with_id.sql @@ -0,0 +1,20 @@ +ALTER TABLE map_of_rooms + RENAME COLUMN id_user TO user_id; + +ALTER TABLE map_of_rooms + RENAME COLUMN id_room TO room_id; + +ALTER TABLE transactions + RENAME COLUMN id_funding TO funding_id; + +ALTER TABLE transactions + RENAME COLUMN id_user TO user_id; + +ALTER TABLE users + RENAME COLUMN id_user_type TO user_type_id; + +ALTER TABLE users + RENAME COLUMN id_room TO room_id; + +ALTER TABLE users + RENAME COLUMN id_team TO team_id; \ No newline at end of file diff --git a/src/main/resources/db/migration/V5__drop_columns.sql b/src/main/resources/db/migration/V5__drop_columns.sql new file mode 100644 index 0000000..a37f845 --- /dev/null +++ b/src/main/resources/db/migration/V5__drop_columns.sql @@ -0,0 +1,7 @@ +ALTER TABLE levels + DROP COLUMN level_to; + +ALTER TABLE transactions + DROP COLUMN id_team, + DROP COLUMN id_status, + DROP COLUMN id_item; \ No newline at end of file diff --git a/src/main/resources/db/migration/V6__alter_data_type_of_timestamp.sql b/src/main/resources/db/migration/V6__alter_data_type_of_timestamp.sql new file mode 100644 index 0000000..2d7be9d --- /dev/null +++ b/src/main/resources/db/migration/V6__alter_data_type_of_timestamp.sql @@ -0,0 +1,2 @@ +ALTER TABLE transactions + ALTER COLUMN timestamp TYPE timestamptz USING "timestamp"::timestamp with time zone; \ No newline at end of file diff --git a/src/main/resources/db/migration/V7__create_fundings_status_history_tables.sql b/src/main/resources/db/migration/V7__create_fundings_status_history_tables.sql new file mode 100644 index 0000000..6175718 --- /dev/null +++ b/src/main/resources/db/migration/V7__create_fundings_status_history_tables.sql @@ -0,0 +1,18 @@ +CREATE TABLE fundings ( + id serial, + item_id int, + team_id int, + PRIMARY KEY (id), + FOREIGN KEY (item_id) REFERENCES items (id), + FOREIGN KEY (team_id) REFERENCES teams (id) +); + +CREATE TABLE status_history ( + id serial, + funding_id int, + status_id int, + timestamp timestamptz, + PRIMARY KEY (id), + FOREIGN KEY (funding_id) REFERENCES fundings (id), + FOREIGN KEY (status_id) REFERENCES statuses (id) +); \ No newline at end of file diff --git a/src/main/resources/db/migration/V8__add_users_into_users.sql b/src/main/resources/db/migration/V8__add_users_into_users.sql new file mode 100644 index 0000000..238197a --- /dev/null +++ b/src/main/resources/db/migration/V8__add_users_into_users.sql @@ -0,0 +1,23 @@ +INSERT INTO users +(name, surname, phone_number, email, password, photo, user_type_id, room_id, team_id) +VALUES ('Liz', 'Ch', '881 417 236', 'liz@codecool.com', '123', '', 1, 1, 1); + +INSERT INTO users +(name, surname, phone_number, email, password, photo, user_type_id, room_id, team_id) +VALUES ('Marek', 'Szotek', '881 417 123', 'marek@codecool.com', '123', '', 1, 1, 1); + +INSERT INTO users +(name, surname, phone_number, email, password, photo, user_type_id, room_id, team_id) +VALUES ('Mateusz', 'Ostafil', '881 417 999', 'mateusz@codecool.com', '123', '', 2, 1, 1); + +INSERT INTO users +(name, surname, phone_number, email, password, photo, user_type_id, room_id, team_id) +VALUES ('Konrad', 'Gadzina', '881 417 888', 'konrad@codecool.com', '123', '', 2, 1, 1); + +INSERT INTO users +(name, surname, phone_number, email, password, photo, user_type_id, room_id, team_id) +VALUES ('Piotr', 'Tomaszewski', '881 417 777', 'piotr@codecool.com', '123', '', 2, 1, 1); + +INSERT INTO users +(name, surname, phone_number, email, password, photo, user_type_id, room_id, team_id) +VALUES ('Jerzy', 'Madraus', '881 417 666', 'jerzy@codecool.com', '123', '', 3, 1, 1); \ No newline at end of file diff --git a/src/main/resources/db/migration/V9__create_session_table.sql b/src/main/resources/db/migration/V9__create_session_table.sql new file mode 100644 index 0000000..33a47ca --- /dev/null +++ b/src/main/resources/db/migration/V9__create_session_table.sql @@ -0,0 +1,8 @@ +CREATE TABLE sessions +( + id serial, + session int, + user_id int, + PRIMARY KEY (id), + FOREIGN KEY (user_id) REFERENCES users (id) +); \ No newline at end of file diff --git a/src/main/resources/media/images/login-page-sample.png b/src/main/resources/media/images/login-page-sample.png new file mode 100644 index 0000000..3b4fb12 Binary files /dev/null and b/src/main/resources/media/images/login-page-sample.png differ diff --git a/src/main/resources/sql/queries.sql b/src/main/resources/sql/queries.sql new file mode 100644 index 0000000..ef0934e --- /dev/null +++ b/src/main/resources/sql/queries.sql @@ -0,0 +1,187 @@ +--user_types +CREATE TABLE user_types +( + id serial, + type text, + PRIMARY KEY (id) +); +INSERT INTO user_types(type) VALUES('Codecooler'); +INSERT INTO user_types(type) VALUES('Mentor'); +INSERT INTO user_types(type) VALUES('Creepy Guy'); + +--item_types +CREATE TABLE item_types +( + id serial, + type text, + grade text, + PRIMARY KEY (id) +); +INSERT INTO item_types(type, grade) VALUES('Artifact', 'Normal'); +INSERT INTO item_types(type, grade) VALUES('Artifact', 'Magic'); +INSERT INTO item_types(type, grade) VALUES('Quest', 'Basic'); +INSERT INTO item_types(type, grade) VALUES('Quest', 'Extra'); + +--rooms +CREATE TABLE rooms +( + id serial, + name text, + PRIMARY KEY (id) +); +INSERT INTO rooms(name) VALUES('ProgBasic'); +INSERT INTO rooms(name) VALUES('Java'); +INSERT INTO rooms(name) VALUES('Web'); +INSERT INTO rooms(name) VALUES('Advanced'); + +--levels +CREATE TABLE levels +( + id serial, + name text, +level_from int, +level_to int, + PRIMARY KEY (id) +); +INSERT INTO levels(name, level_from, level_to) VALUES('junior', 0, 2000); +INSERT INTO levels(name, level_from, level_to) VALUES('medium', 2001, 4000); +INSERT INTO levels(name, level_from, level_to) VALUES('senior', 4001, 6000); + +--statuses +CREATE TABLE statuses +( + id serial, + type text, + PRIMARY KEY (id) +); +INSERT INTO statuses(type) VALUES('In progress'); +INSERT INTO statuses(type) VALUES('Pending'); +INSERT INTO statuses(type) VALUES('Realized'); +INSERT INTO statuses(type) VALUES('Rejected'); + +--teams +CREATE TABLE teams +( + id serial, + name text, + project_name text, + PRIMARY KEY (id) +); +INSERT INTO teams(name, project_name) VALUES('foxes', 'Slack'); +INSERT INTO teams(name, project_name) VALUES('bears', 'Quest store'); +INSERT INTO teams(name, project_name) VALUES('sharks', 'Klondike'); + +--users +CREATE TABLE users +( + id serial, + name text, + surname text, + phone_number text, + email text, + password text, + photo text, + user_type_id int, + room_id int, + team_id int, + PRIMARY KEY (id), + FOREIGN KEY (id_user_type) REFERENCES user_types (id), + FOREIGN KEY (id_team) REFERENCES teams (id), + FOREIGN KEY (id_room) REFERENCES rooms (id) +); + +INSERT INTO users(name, surname, phone_number, email, password, photo, id_user_type, id_team, id_room) +VALUES('Tatiana', 'Slonimskaia', '881', '@123', '123', '', 1, 1, 1); + +--map_of_rooms +CREATE TABLE map_of_rooms +( + id serial, + id_user int, + id_room int, + PRIMARY KEY (id), + FOREIGN KEY (id_user) REFERENCES users (id), + FOREIGN KEY (id_room) REFERENCES rooms (id) +); + +--items +CREATE TABLE items +( + id serial, + price int, + title text, + description text, + item_type int, + PRIMARY KEY (id), + FOREIGN KEY (item_type) REFERENCES item_types (id) +); + +INSERT INTO items(price, title, description, item_type) +VALUES(100, 'Exploring a dungeon', 'Finishing a Teamwork week', 3); +INSERT INTO items(price, title, description, item_type) +VALUES(100, 'Solving the magic puzzle', 'Finishing an SI assignment', 3); +INSERT INTO items(price, title, description, item_type) +VALUES(500, 'Slaying a dragon', 'Passing a Checkpoint', 3); +INSERT INTO items(price, title, description, item_type) +VALUES(50, 'Spot trap', 'Spot a major mistake in the assignment', 4); +INSERT INTO items(price, title, description, item_type) +VALUES(100, 'Taming a pet', 'Doing a demo about a pet project', 4); +INSERT INTO items(price, title, description, item_type) +VALUES(100, 'Recruiting some n00bs', 'Taking part in the student screening process', 4); +INSERT INTO items(price, title, description, item_type) +VALUES(400, 'Forging weapons', 'Organizing a workshop for other students', 4); +INSERT INTO items(price, title, description, item_type) +VALUES(300, 'Master the mornings', 'Attend 1 months without being late', 4); +INSERT INTO items(price, title, description, item_type) +VALUES(500, 'Fast as an unicorn', 'Deliver 4 consecutive SI week assignments on time', 4); +INSERT INTO items(price, title, description, item_type) +VALUES(500, 'Achiever', 'Set up a SMART goal accepted by a mentor, then achieve it', 4); +INSERT INTO items(price, title, description, item_type) +VALUES(500, 'Fortune', 'Students choose the best project of the week. Selected team scores', 4); +INSERT INTO items(price, title, description, item_type) +VALUES(500, 'Creating an enchanted scroll', 'Creating extra material for the current TW/SI topic (should be revised by mentors)', 4); +INSERT INTO items(price, title, description, item_type) +VALUES(500, 'Enter the arena', 'Do a presentation on a meet-up', 4); +INSERT INTO items(price, title, description, item_type) +VALUES(50, 'Combat training', 'Private mentoring', 1); +INSERT INTO items(price, title, description, item_type) +VALUES(300, 'Sanctuary', 'You can spend a day in home office', 1); +INSERT INTO items(price, title, description, item_type) +VALUES(500, 'Time Travel', 'extend SI week assignment deadline by one day', 1); +INSERT INTO items(price, title, description, item_type) +VALUES(1000, 'Circle of Sorcery', '60 min workshop by a mentor(s) of the chosen topic', 2); +INSERT INTO items(price, title, description, item_type) +VALUES(1000, 'Summon Code Elemental', 'mentor joins a students team for a one hour', 2); +INSERT INTO items(price, title, description, item_type) +VALUES(500, 'Tome of knowledge', 'Extra material for the current topic', 2); +INSERT INTO items(price, title, description, item_type) +VALUES(5000, 'Transform mentors', 'All mentors should dress up as pirates (or just funny) for the day', 2); +INSERT INTO items(price, title, description, item_type) +VALUES(30000, 'Teleport ', 'The whole course goes to an off-school program instead for a day', 2); + +--transactions +CREATE TABLE transactions +( + id serial, + id_funding int, + id_user int, + id_team int, + id_item int, + id_status int, + timestamp text, + paid_amount int, + PRIMARY KEY (id), + FOREIGN KEY (id_user) REFERENCES users (id), + FOREIGN KEY (id_team) REFERENCES teams (id), + FOREIGN KEY (id_item) REFERENCES items (id), + FOREIGN KEY (id_status) REFERENCES statuses (id) +); + +--get all items of user +SELECT * FROM items +INNER JOIN fundings ON items.id = fundings.item_id +INNER JOIN transactions ON items.id = fundings.item_id +INNER JOIN status_history ON fundings.id = status_history.funding_id +INNER JOIN statuses ON status_history.status_id = statuses.id +WHERE transactions.user_id = ? +AND statuses.type = 'Realized'; \ No newline at end of file diff --git a/src/main/resources/static/artifacts.html b/src/main/resources/static/artifacts.html new file mode 100644 index 0000000..d1da6fd --- /dev/null +++ b/src/main/resources/static/artifacts.html @@ -0,0 +1,135 @@ + + + + + + + Artifacts + + + + + + + + + +
+
+
+ +
+ +
+ +
+
+
+ +
+
+ +
+

Current discount: 10%

+
+ + + +
+
+ +
+ +
+ + + +
+ +
+ Artifact Image +
+ +
+ 9999999999 + Pile of coins +
+ +
+

Title

+
+ +
+

Description of artifact

+
+ +
+ +
+ +
+ + + +
+ +
+ Artifact Image +
+ +
+ 9999 + Pile of coins +
+ +
+

Title

+
+ +
+

Description of artifact

+
+ +
+ +
+ +
+ +
+ +
+ +
+ + + +
+ + + + \ No newline at end of file diff --git a/src/main/resources/static/assets/images/artifact-icons/artifact-coins.png b/src/main/resources/static/assets/images/artifact-icons/artifact-coins.png new file mode 100644 index 0000000..3fcf270 Binary files /dev/null and b/src/main/resources/static/assets/images/artifact-icons/artifact-coins.png differ diff --git a/src/main/resources/static/assets/images/artifact-icons/artifact1.png b/src/main/resources/static/assets/images/artifact-icons/artifact1.png new file mode 100644 index 0000000..a3e883f Binary files /dev/null and b/src/main/resources/static/assets/images/artifact-icons/artifact1.png differ diff --git a/src/main/resources/static/assets/images/artifact-icons/artifact2.png b/src/main/resources/static/assets/images/artifact-icons/artifact2.png new file mode 100644 index 0000000..37ad361 Binary files /dev/null and b/src/main/resources/static/assets/images/artifact-icons/artifact2.png differ diff --git a/src/main/resources/static/assets/images/artifact-icons/artifact3.png b/src/main/resources/static/assets/images/artifact-icons/artifact3.png new file mode 100644 index 0000000..7818fb0 Binary files /dev/null and b/src/main/resources/static/assets/images/artifact-icons/artifact3.png differ diff --git a/src/main/resources/static/assets/images/artifact-icons/artifact4.png b/src/main/resources/static/assets/images/artifact-icons/artifact4.png new file mode 100644 index 0000000..7a0979c Binary files /dev/null and b/src/main/resources/static/assets/images/artifact-icons/artifact4.png differ diff --git a/src/main/resources/static/assets/images/artifact-icons/artifact5.png b/src/main/resources/static/assets/images/artifact-icons/artifact5.png new file mode 100644 index 0000000..98ae158 Binary files /dev/null and b/src/main/resources/static/assets/images/artifact-icons/artifact5.png differ diff --git a/src/main/resources/static/assets/images/artifact-icons/artifact6.png b/src/main/resources/static/assets/images/artifact-icons/artifact6.png new file mode 100644 index 0000000..1e39aa8 Binary files /dev/null and b/src/main/resources/static/assets/images/artifact-icons/artifact6.png differ diff --git a/src/main/resources/static/assets/images/creepy-guy/create-room.png b/src/main/resources/static/assets/images/creepy-guy/create-room.png new file mode 100644 index 0000000..6fe3d4c Binary files /dev/null and b/src/main/resources/static/assets/images/creepy-guy/create-room.png differ diff --git a/src/main/resources/static/assets/images/creepy-guy/creep-on-mentors.png b/src/main/resources/static/assets/images/creepy-guy/creep-on-mentors.png new file mode 100644 index 0000000..1b69d0d Binary files /dev/null and b/src/main/resources/static/assets/images/creepy-guy/creep-on-mentors.png differ diff --git a/src/main/resources/static/assets/images/creepy-guy/edit-levels.png b/src/main/resources/static/assets/images/creepy-guy/edit-levels.png new file mode 100644 index 0000000..c2bc06b Binary files /dev/null and b/src/main/resources/static/assets/images/creepy-guy/edit-levels.png differ diff --git a/src/main/resources/static/assets/images/creepy-guy/recruit-mentor.png b/src/main/resources/static/assets/images/creepy-guy/recruit-mentor.png new file mode 100644 index 0000000..f51ec92 Binary files /dev/null and b/src/main/resources/static/assets/images/creepy-guy/recruit-mentor.png differ diff --git a/src/main/resources/static/assets/images/logo/favicon.ico b/src/main/resources/static/assets/images/logo/favicon.ico new file mode 100644 index 0000000..77fc072 Binary files /dev/null and b/src/main/resources/static/assets/images/logo/favicon.ico differ diff --git a/src/main/resources/static/assets/images/logo/logo-footer.png b/src/main/resources/static/assets/images/logo/logo-footer.png new file mode 100644 index 0000000..8724350 Binary files /dev/null and b/src/main/resources/static/assets/images/logo/logo-footer.png differ diff --git a/src/main/resources/static/assets/images/logo/logo.png b/src/main/resources/static/assets/images/logo/logo.png new file mode 100644 index 0000000..0ba2aac Binary files /dev/null and b/src/main/resources/static/assets/images/logo/logo.png differ diff --git a/src/main/resources/static/assets/images/mentor/create-artifact.png b/src/main/resources/static/assets/images/mentor/create-artifact.png new file mode 100644 index 0000000..06ae433 Binary files /dev/null and b/src/main/resources/static/assets/images/mentor/create-artifact.png differ diff --git a/src/main/resources/static/assets/images/mentor/create-quest.png b/src/main/resources/static/assets/images/mentor/create-quest.png new file mode 100644 index 0000000..0bc568b Binary files /dev/null and b/src/main/resources/static/assets/images/mentor/create-quest.png differ diff --git a/src/main/resources/static/assets/images/mentor/create-team.png b/src/main/resources/static/assets/images/mentor/create-team.png new file mode 100644 index 0000000..293c6b1 Binary files /dev/null and b/src/main/resources/static/assets/images/mentor/create-team.png differ diff --git a/src/main/resources/static/assets/images/mentor/recruit-student.png b/src/main/resources/static/assets/images/mentor/recruit-student.png new file mode 100644 index 0000000..a0bf17e Binary files /dev/null and b/src/main/resources/static/assets/images/mentor/recruit-student.png differ diff --git a/src/main/resources/static/assets/images/mentor/review-artifacts.png b/src/main/resources/static/assets/images/mentor/review-artifacts.png new file mode 100644 index 0000000..a12de38 Binary files /dev/null and b/src/main/resources/static/assets/images/mentor/review-artifacts.png differ diff --git a/src/main/resources/static/assets/images/mentor/review-quests.png b/src/main/resources/static/assets/images/mentor/review-quests.png new file mode 100644 index 0000000..62e43ed Binary files /dev/null and b/src/main/resources/static/assets/images/mentor/review-quests.png differ diff --git a/src/main/resources/static/assets/images/mentor/view-artifacts.png b/src/main/resources/static/assets/images/mentor/view-artifacts.png new file mode 100644 index 0000000..202b6ba Binary files /dev/null and b/src/main/resources/static/assets/images/mentor/view-artifacts.png differ diff --git a/src/main/resources/static/assets/images/mentor/view-quests.png b/src/main/resources/static/assets/images/mentor/view-quests.png new file mode 100644 index 0000000..d1951e8 Binary files /dev/null and b/src/main/resources/static/assets/images/mentor/view-quests.png differ diff --git a/src/main/resources/static/assets/images/mentor/view-students.png b/src/main/resources/static/assets/images/mentor/view-students.png new file mode 100644 index 0000000..d3cdf4b Binary files /dev/null and b/src/main/resources/static/assets/images/mentor/view-students.png differ diff --git a/src/main/resources/static/assets/images/mentor/view-teams.png b/src/main/resources/static/assets/images/mentor/view-teams.png new file mode 100644 index 0000000..40c8346 Binary files /dev/null and b/src/main/resources/static/assets/images/mentor/view-teams.png differ diff --git a/src/main/resources/static/assets/images/navigation-icons/icon-github.png b/src/main/resources/static/assets/images/navigation-icons/icon-github.png new file mode 100644 index 0000000..6ee2f65 Binary files /dev/null and b/src/main/resources/static/assets/images/navigation-icons/icon-github.png differ diff --git a/src/main/resources/static/assets/images/navigation-icons/icon-home.png b/src/main/resources/static/assets/images/navigation-icons/icon-home.png new file mode 100644 index 0000000..58b047f Binary files /dev/null and b/src/main/resources/static/assets/images/navigation-icons/icon-home.png differ diff --git a/src/main/resources/static/assets/images/navigation-icons/icon-logout.png b/src/main/resources/static/assets/images/navigation-icons/icon-logout.png new file mode 100644 index 0000000..a103dde Binary files /dev/null and b/src/main/resources/static/assets/images/navigation-icons/icon-logout.png differ diff --git a/src/main/resources/static/assets/images/navigation-icons/icon-search.png b/src/main/resources/static/assets/images/navigation-icons/icon-search.png new file mode 100644 index 0000000..ec522a6 Binary files /dev/null and b/src/main/resources/static/assets/images/navigation-icons/icon-search.png differ diff --git a/src/main/resources/static/assets/images/quest-icons/basic-quest.png b/src/main/resources/static/assets/images/quest-icons/basic-quest.png new file mode 100644 index 0000000..a7e43aa Binary files /dev/null and b/src/main/resources/static/assets/images/quest-icons/basic-quest.png differ diff --git a/src/main/resources/static/assets/images/quest-icons/extra-quest.png b/src/main/resources/static/assets/images/quest-icons/extra-quest.png new file mode 100644 index 0000000..1ad418e Binary files /dev/null and b/src/main/resources/static/assets/images/quest-icons/extra-quest.png differ diff --git a/src/main/resources/static/assets/images/quest-icons/pile-of-coins.png b/src/main/resources/static/assets/images/quest-icons/pile-of-coins.png new file mode 100644 index 0000000..8a4d9f8 Binary files /dev/null and b/src/main/resources/static/assets/images/quest-icons/pile-of-coins.png differ diff --git a/src/main/resources/static/assets/images/student/codecooler.png b/src/main/resources/static/assets/images/student/codecooler.png new file mode 100644 index 0000000..3e1db7e Binary files /dev/null and b/src/main/resources/static/assets/images/student/codecooler.png differ diff --git a/src/main/resources/static/assets/images/student/coins-bag.png b/src/main/resources/static/assets/images/student/coins-bag.png new file mode 100644 index 0000000..8861a76 Binary files /dev/null and b/src/main/resources/static/assets/images/student/coins-bag.png differ diff --git a/src/main/resources/static/assets/images/user-icons/codecooler.png b/src/main/resources/static/assets/images/user-icons/codecooler.png new file mode 100644 index 0000000..3e1db7e Binary files /dev/null and b/src/main/resources/static/assets/images/user-icons/codecooler.png differ diff --git a/src/main/resources/static/assets/images/user-icons/creepy-guy.png b/src/main/resources/static/assets/images/user-icons/creepy-guy.png new file mode 100644 index 0000000..b57190b Binary files /dev/null and b/src/main/resources/static/assets/images/user-icons/creepy-guy.png differ diff --git a/src/main/resources/static/assets/images/user-icons/mentor.png b/src/main/resources/static/assets/images/user-icons/mentor.png new file mode 100644 index 0000000..2bc7cdc Binary files /dev/null and b/src/main/resources/static/assets/images/user-icons/mentor.png differ diff --git a/src/main/resources/static/assets/stylesheets/configuration-menu.css b/src/main/resources/static/assets/stylesheets/configuration-menu.css new file mode 100644 index 0000000..f7b9140 --- /dev/null +++ b/src/main/resources/static/assets/stylesheets/configuration-menu.css @@ -0,0 +1,149 @@ +/* + ======================================== + Configuration Menus + ======================================== +*/ + +/* centering */ + +.primary-main-page-container { + display: flex; + align-items: center; + justify-content: space-evenly; + flex-flow: wrap; + height: 100%; +} + +/* main container */ + +.take-action-container { + margin: 5% 1% 18% 1%; + width: 300px; + height: 250px; + border-radius: 2%; + background-color: #ffffff; + color: #57033b; + cursor: pointer; +} + +.take-action-container h2, +.take-action-container span, +.take-action-container p { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; + padding: 2%; +} + +.take-action-container img { + display: block; + margin: auto; + padding: 2%; + filter: grayscale(100%); +} + +.take-action-container h2 { + font-weight: bolder; + font-size: 20px; +} + +span.action-separator { + color: #f8c218; +} + +/* hover effect */ + +.take-action-container:hover, +.take-action-container:hover .action-separator, +.take-action-container:hover .action-image { + background-color: #f8c218; + color: #ffffff; + filter: grayscale(0%); +} + +/* text */ + +p.action-description { + line-height: 1.2; +} + +/* action form container */ + +.action-form-container { + margin-top: 18%; + display: none; +} + +.action-form-container label { + display: none; +} + +.action-form-container input { + display: block; + margin: 2% auto; + text-align: center; + width: 100%; + color: #f8c218; + border-radius: 5%; + outline-color: #f8c218; + padding: 3% 0; +} + +.action-form-container input::placeholder { + color: #57033b; +} + +.action-form-container [type="submit"] { + background-color: #f8c218; + color: #f3f3f3; + box-shadow: + 0 2px 5px rgba(0, 0, 0, 0.5), + 0 1px 0 rgba(255, 255, 255, 0.25) inset, + 0 0 0 rgba(0, 0, 0, 0.25) inset, + 0 20px 0 rgba(255, 255, 255, 0.03) inset, + 0 -20px 20px rgba(0, 0, 0, 0.15) inset, + 0 20px 20px rgba(255, 255, 255, 0.05) inset; + transition: all 0.4s linear 0s; +} + +.action-form-container input[type="submit"]:hover { + cursor: pointer; + color: #57033b; + font-weight: bolder; + background-color: #f3f3f3; +} + +/* review options */ + +.review-data { + color: #f3f3f3; + background-color: #57033b; + border-radius: 7%; +} + +/* notification with status update */ + +#creepy-guy-notification-message, +#mentor-notification-message { + margin: 0.5% auto; + width:50%; + height: 8%; + position: sticky; + background-color: rgba(200, 198, 198, 0.63); + box-shadow: + 0 4px 8px 0 rgba(0, 0, 0, 0.2), + 0 6px 20px 0 rgba(0, 0, 0, 0.19); + display: flex; + justify-content: center; + align-items: center; + visibility: hidden; +} + +#creepy-guy-notification-message p, +#mentor-notification-message p { + color: #57033b; + font-weight: bolder; + font-size: 20px; +} \ No newline at end of file diff --git a/src/main/resources/static/assets/stylesheets/item-card.css b/src/main/resources/static/assets/stylesheets/item-card.css new file mode 100644 index 0000000..9483542 --- /dev/null +++ b/src/main/resources/static/assets/stylesheets/item-card.css @@ -0,0 +1,279 @@ +/* + ======================================== + Item Card Styles + ======================================== +*/ + +/* centering */ + +#primary-artifacts-container, +#primary-quests-container { + display: flex; + align-items: center; + justify-content: space-evenly; + flex-flow: wrap; + height: 100%; +} + +/* main container */ + +.artifact-container, +.quest-container { + margin: 110px 10px; + width: 300px; + height: 380px; + border-top-left-radius: 10px; + border-top-right-radius: 10px; + box-shadow: + 0 4px 8px 0 rgba(0, 0, 0, 0.2), + 0 6px 20px 0 rgba(0, 0, 0, 0.19); +} + +.quest-container { + margin-right: 30px; +} + +.basic-artifact:hover, +.basic-quest:hover { + box-shadow: + 0 4px 8px 0 rgba(64, 156, 255, 0.74), + 0 6px 20px 0 rgba(64, 156, 255, 0.19); +} + +.magic-artifact:hover, +.extra-quest:hover { + box-shadow: + 0 4px 8px 0 rgba(174, 0, 15, 0.88), + 0 6px 20px 0 rgba(174, 0, 15, 0.19); +} + +/* image container */ + +div.artifact-image-container img, +div.quest-image-container img { + display: block; + margin-left: auto; + margin-right: auto; +} + +div.artifact-image-container img { + padding-top: 4px; + height: 280px; + position: relative; + bottom: 90px; + box-shadow: + 0 4px 8px 0 rgba(0, 0, 0, 0.2), + 0 6px 20px 0 rgba(0, 0, 0, 0.19); +} + +div.quest-image-container img { + width: 200px; +} + +.bag-of-coins img { + position: relative; + bottom: 70px; +} + +.pile-of-coins img { + position: relative; + bottom: 150px; + left: 85px; +} + +/* price container */ + +.artifact-price-container { + position: relative; + padding-left: 0; + bottom: 115px; +} + +.quest-reward-container { + position: relative; + padding-left: 25px; + bottom: 215px; +} + +.artifact-price-container span, +.quest-reward-container p { + font-size: 30px; + font-weight: bolder; + color: #F5C21B; +} + +div.artifact-price-container img { + width: 100px; + position: absolute; + right: 0; +} + +div.artifact-price-container span { + position: relative; + bottom: -40px; + left: 30px; +} + +/* title container */ + +div.artifact-title-container { + position: relative; + bottom: 70px; +} + +div.quest-title-container { + position: relative; + bottom: 150px; +} + +div.artifact-title-container, +div.quest-title-container { + margin: auto; + height: 20px; + width: 180px; + padding: 5px; + border-radius: 10px; + border: 2px solid rgba(64, 156, 255, 0.74); + border-bottom: none; + background-color: #f3f3f3; +} + +.magic-artifact .artifact-title-container, +.extra-quest .quest-title-container { + border: 2px solid rgba(174, 0, 15, 0.88); + border-bottom: none; +} + +div.artifact-title-container p, +div.quest-title-container p { + font-size: 18px; + font-weight: bolder; + text-align: center; + text-transform: uppercase; + color: #57033b; +} + +/* description container */ + +div.artifact-description-container { + position: relative; + bottom: 58px; +} + +div.quest-description-container { + position: relative; + bottom: 120px; +} + +div.artifact-description-container, +div.quest-description-container { + margin: auto; + height: 70px; + width: 250px; + background-color: #f3f3f3; + border-radius: 10px; + border-top: 2px solid rgba(64, 156, 255, 0.74); +} + +.magic-artifact .artifact-description-container, +.extra-quest .quest-description-container { + border-top: 2px solid rgba(174, 0, 15, 0.88); +} + +div.artifact-description-container p, +div.quest-description-container p { + text-align: center; + padding-top: 18px; + font-size: 20px; + color: #57033b; +} + +/* buttons */ + +div.artifact-purchase-button-container { + position: relative; + bottom: 35px; +} + +div.quest-claim-button-container { + position: relative; + bottom: 70px; +} + +div.artifact-purchase-button-container button, +div.quest-claim-button-container button, +.save-button { + height: 50px; + width: 100%; + font-size: 18px; + font-weight: bolder; + color: #ffffff; + background-color: #fb9d06; + box-shadow: + 0 2px 5px rgba(0, 0, 0, 0.5), + 0 1px 0 rgba(255, 255, 255, 0.25) inset, + 0 0 0 rgba(0, 0, 0, 0.25) inset, + 0 20px 0 rgba(255, 255, 255, 0.03) inset, + 0 -20px 20px rgba(0, 0, 0, 0.15) inset, + 0 20px 20px rgba(255, 255, 255, 0.05) inset; + transition: all 0.5s linear 0s; +} + +div.artifact-purchase-button-container button:hover, +div.quest-claim-button-container button:hover, +.save-button:hover { + cursor: pointer; + color: #57033b; + background-color: #f3f3f3; +} + +span.old-price { + text-decoration: line-through; + color: black; +} + +span.new-price { + font-weight: bold; + color: red; +} + +span.no-discount-price, +.quest-reward-container p { + background: -webkit-gradient(linear, left top, left bottom, from(rgba(34, 30, 2, 0.3)), to(#020100)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; +} + +/* discount section */ + +.discount-section { + background-color: #810f42; + text-align: center; + padding: 1%; + color: #ffffff; + font-size: 20px; +} + +#current-discount { + font-weight: bold; + font-size: 25px; + color: #F5C21B; +} + +input#newDiscount { + color: #ffffff; + width: 3%; + outline-color: #fb9d06; + border-radius: 5%; + padding: 0.1%; + background-color: rgba(193, 193, 193, 0.36); +} + +.save-button { + background-color: rgba(251, 157, 6, 0.25); + font-size: 25px; + width: 3%; + height: 0.1%; + padding: 0.2%; + border-radius: 5%; +} \ No newline at end of file diff --git a/src/main/resources/static/assets/stylesheets/login.css b/src/main/resources/static/assets/stylesheets/login.css new file mode 100644 index 0000000..21893d2 --- /dev/null +++ b/src/main/resources/static/assets/stylesheets/login.css @@ -0,0 +1,106 @@ +/* + ======================================== + Login Page Styles + ======================================== +*/ + +/* background */ + +.content { + background-image: + linear-gradient(to right, + #c8c6c6, #d2d0d0, #dcdada, #e7e4e4, + #f1eeee, #f1eeee, #f1eeef, #f1eeef, + #e6e4e6, #dcdbdc, #d2d1d2, #c8c8c8); +} + +/* centering */ + +#primary-login-container { + display: flex; + align-items: center; + justify-content: space-evenly; + flex-flow: wrap; + height: 100%; +} + +/* user login images */ + +.login-user-container { + margin: 50px 0; + width: 300px; + height: 380px; + border-top: 3px solid #fb9d06; + border-bottom: 3px solid #fb9d06; + background: #ffffff; + box-shadow: + 0 4px 8px 0 rgba(0, 0, 0, 0.2), + 0 6px 20px 0 rgba(0, 0, 0, 0.19); +} + +div.login-to-domain-image-container img { + display: block; + margin-left: auto; + margin-right: auto; + padding-top: 8px; + border-radius: 10px; + width: 200px; + height: 200px; + position: relative; + bottom: 70px; + box-shadow: + 0 4px 8px 0 rgba(0, 0, 0, 0.2), + 0 6px 20px 0 rgba(0, 0, 0, 0.19); +} + +/* user forms */ + +.login-form { + text-align: center; +} + +.login-form legend { + font-weight: bolder; + text-transform: uppercase; + color: #57033b; + font-size: 35px; +} + +.login-form label { + visibility: hidden; +} + +.login-form input { + padding-top: 15px; + height: 20px; + width: 200px; + font-size: 14px; + text-align: center; + color: #fb9d06; + outline: none; + border-bottom: 1px solid #57033b; +} + +.login-form input[type="submit"] { + padding: 0; + position: relative; + top: 25px; + height: 35px; + border: none; + background-color: #57033b; + box-shadow: + 0 2px 5px rgba(0, 0, 0, 0.5), + 0 1px 0 rgba(255, 255, 255, 0.25) inset, + 0 0 0 rgba(0, 0, 0, 0.25) inset, + 0 20px 0 rgba(255, 255, 255, 0.03) inset, + 0 -20px 20px rgba(0, 0, 0, 0.15) inset, + 0 20px 20px rgba(255, 255, 255, 0.05) inset; + transition: all 0.4s linear 0s; +} + +.login-form input[type="submit"]:hover { + cursor: pointer; + color: #57033b; + font-weight: bolder; + background-color: #f3f3f3; +} \ No newline at end of file diff --git a/src/main/resources/static/assets/stylesheets/main.css b/src/main/resources/static/assets/stylesheets/main.css new file mode 100644 index 0000000..f7175a5 --- /dev/null +++ b/src/main/resources/static/assets/stylesheets/main.css @@ -0,0 +1,225 @@ +* { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} +body { + line-height: 1; +} +ol, ul { + list-style: none; +} +blockquote, q { + quotes: none; +} +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} + +/* +======================================== +Main Layout Style +======================================== +*/ +html, body { + height: 100%; +} + +body { + display: flex; + flex-direction: column; + margin-right: 50px; + margin-left: 50px; + +} + +.content { + flex: 1 0 auto; + background-color: #f3f3f3; +} + +.footer { + flex-shrink: 0; +} +/* + ======================================== + Links + ======================================== +*/ +a { + text-decoration:none; +} + +/* + ======================================== + Dropdown MENU + ======================================== +*/ +.dropdown { + float: left; + overflow: hidden; +} + +.dropdown .dropbtn { + font-size: 18px; + border: none; + outline: none; + color: #57033b; + letter-spacing: .5px; + text-transform: uppercase; + background-color: rgba(10, 10, 10, 0.17); +} + +.navbar a:hover, .dropdown:hover .dropbtn { + color: #fb9d06; +} + +.dropdown-content { + display: none; + position: absolute; + background-color: #fb9d0671; + z-index: 1; +} + +.dropdown-content a { + float: none; + color: #57033b; + padding: 0 12px 0 12px; + text-decoration: none; + display: block; + text-align: left; +} + +.dropdown-content a:hover { + background-color: #ddd; +} + +.dropdown:hover .dropdown-content { + display: block; +} + +.dropdown { + z-index: 1; +} + +/* + ======================================== + Primary header + ======================================== +*/ +.logo { + float: left; + max-width:100%; +} +.primary-nav { + font-size: 18px; + font-weight: 400; + letter-spacing: .5px; + text-transform: uppercase; +} +.primary-header a { + color: #57033b; +} +.primary-header a:hover { + color: #fb9d06; +} +.primary-header { + overflow: hidden; + background-color: #0a0a0a24; +} +.flex-container-header { + list-style: none; + display: flex; + justify-content: space-between; + flex-direction: row; + flex-wrap: wrap; +} + +.nav { + display: flex; + justify-content: flex-end; + flex-direction: row; + padding-right: 15px; +} + +#main-logo{ + padding: 15px; + padding-bottom: 0; + +} + +.flex-item-header { + padding-left: 30px; + margin-top: 10px; + line-height: 105px; + font-weight: bold; +} + +/* + ======================================== + Searching + ======================================== +*/ +.search-field { + width: 150px; + box-sizing: border-box; + padding: 5px 20px; + border-radius: 10px; + font-size: 16px; + border: 1px solid #57033b; + float: right; + margin-right: 10px; + margin-bottom: 10px; +} + +input[type="text"].search-field { + color: #57033b; + outline: none; +} + +/* + ======================================== + Primary footer + ======================================== +*/ +.icons img { + width: 50px; + padding:10px; +} + +.flex-container-footer { + height: 70px; + list-style: none; + display: flex; + justify-content: space-between; + flex-direction: row; + background-image: linear-gradient(to right, #57033b, #810f42, #a92642, #cb443b, #e6672e, #e6672e, #e6672e, #e6672e, #cb443b, #a92642, #810f42, #57033b); +} + +#copyright { + padding-top: 30px; + padding-left: 15px; + color: #ffffff +} +#icon-github { + margin:auto; +} + +.icons img:hover { + cursor: pointer; + -webkit-filter: brightness(70%);filter: brightness(70%); +} \ No newline at end of file diff --git a/src/main/resources/static/assets/stylesheets/mentors.css b/src/main/resources/static/assets/stylesheets/mentors.css new file mode 100644 index 0000000..f716ba1 --- /dev/null +++ b/src/main/resources/static/assets/stylesheets/mentors.css @@ -0,0 +1,15 @@ +.flex-mentors-container{ + list-style: none; + display: flex; + justify-content: space-around; + flex-direction: row; + flex-wrap: wrap; +} + +.margins-mentors { + margin: 90px 20px 20px 20px; +} + +.info-position { + padding-top: 140px; +} \ No newline at end of file diff --git a/src/main/resources/static/assets/stylesheets/quests.css b/src/main/resources/static/assets/stylesheets/quests.css new file mode 100644 index 0000000..2894f9a --- /dev/null +++ b/src/main/resources/static/assets/stylesheets/quests.css @@ -0,0 +1,6 @@ +#primary-artifacts-container, +#primary-quests-container { + align-items: center; + justify-content: space-evenly; + flex-flow: wrap; +} \ No newline at end of file diff --git a/src/main/resources/static/assets/stylesheets/students.css b/src/main/resources/static/assets/stylesheets/students.css new file mode 100644 index 0000000..acdd2ae --- /dev/null +++ b/src/main/resources/static/assets/stylesheets/students.css @@ -0,0 +1,11 @@ +.flex-students-container{ + list-style: none; + display: flex; + justify-content: space-around; + flex-direction: row; + flex-wrap: wrap; +} + +.margins-student { + margin: 90px 20px 20px 20px; +} diff --git a/src/main/resources/static/assets/stylesheets/user-team.css b/src/main/resources/static/assets/stylesheets/user-team.css new file mode 100644 index 0000000..836f9f8 --- /dev/null +++ b/src/main/resources/static/assets/stylesheets/user-team.css @@ -0,0 +1,267 @@ +/* + ======================================== + Dropdown MENU + ======================================== +*/ +.dropdown { + float: left; + overflow: hidden; +} + +.dropdown .dropbtn { + font-size: 18px; + border: none; + outline: none; + color: #57033b; + letter-spacing: .5px; + text-transform: uppercase; + background-color: rgba(10, 10, 10, 0.17); +} + +.navbar a:hover, .dropdown:hover .dropbtn { + color: #fb9d06; +} + +.dropdown-content { + display: none; + position: absolute; + background-color: #fb9d0671; + z-index: 1; +} + +.dropdown-content a { + float: none; + color: #57033b; + padding: 0 12px 0 12px; + text-decoration: none; + display: block; + text-align: left; +} + +.dropdown-content a:hover { + background-color: #ddd; +} + +.dropdown:hover .dropdown-content { + display: block; +} + +.dropdown { + z-index: 1; +} + +/* + ======================================== + Student Content + ======================================== +*/ +.user-content { + float: left; + padding: 20px; + margin-right: 5px; +} +.artifacts-quests, +.artifacts-quests-team { + float: left; + padding: 35px; + margin: 0 150px; +} +.artifacts-quests p, +.artifacts-quests-team p { + margin: auto; + font-size: 30px; + font-weight: bold; + color: #57033b; +} + +/* Clear floats after the columns */ +section:after { + content: ""; + display: table; + clear: both; +} + +@media (max-width: 600px) { + nav, article { + width: 100%; + height: auto; + } +} + +.flex-container-content, +.flex-team-container { + list-style: none; + display: flex; + justify-content: space-between; + flex-direction: row; +} + +div.user-photo-container img { + display: block; + margin-left: 10px; + padding-top: 4px; + border-radius: 10px; + width: 120px; + height: 120px; + position: relative; + bottom: 70px; + box-shadow: + 0 4px 8px 0 rgba(0, 0, 0, 0.2), + 0 6px 20px 0 rgba(0, 0, 0, 0.19); +} + +.information-user-container { + margin: 80px 30px 10px 30px; + width: 350px; + height: 180px; + border-top: 3px solid #fb9d06; + border-bottom: 3px solid #fb9d06; + background: #ffffff; + box-shadow: + 0 4px 8px 0 rgba(0, 0, 0, 0.2), + 0 6px 20px 0 rgba(0, 0, 0, 0.19); +} + +.info-container { + position: relative; + padding-left: 180px; + bottom: 243px; + font-size: 16px; + font-weight: bold; + color:#57033b; +} + +.info-container p { + padding-bottom: 2px; +} + +.student-coins-container { + position:relative; + bottom: 50px; + left: -20px; +} + +.student-coins-container img{ + width: 100px; +} + +.coins p{ + font-size: 30px; + font-weight: bold; + color:#57033b; +} + +.coins { + position:relative; + bottom: 110px; + left: 90px; +} + +/* + ======================================== + Button on student page + ======================================== +*/ + +.button-student{ + width: 350px; + margin: 10px 0 10px 30px; + background:#0a0a0a24; + color:#57033b; + border:none; + position:relative; + height:60px; + font-size:25px; + font-weight: bold; + padding:0 2em; + cursor:pointer; + transition:800ms ease all; + outline:none; + box-shadow: + 0 2px 5px rgba(0, 0, 0, 0.5), + 0 1px 0 rgba(255, 255, 255, 0.25) inset, + 0 0 0 rgba(0, 0, 0, 0.25) inset, + 0 20px 0 rgba(255, 255, 255, 0.03) inset, + 0 -20px 20px rgba(0, 0, 0, 0.15) inset, + 0 20px 20px rgba(255, 255, 255, 0.05) inset; +} + +.button-student:hover{ + background:#fb9d06; + color:#f3f3f3; + +} + +.button-student:before,.button-student:after{ + content:''; + position:absolute; + top:0; + right:0; + height:2px; + width:0; + background: #f3f3f3; + transition:400ms ease all; +} + +.button-student:after{ + right:inherit; + top:inherit; + left:0; + bottom:0; +} + +.button-student:hover:before,.button-student:hover:after{ + width:100%; + transition:800ms ease all; +} + +/* + ======================================== + Team Content + ======================================== +*/ +.student { + padding-top: 20px; +} + +.first-student-background img { + -webkit-filter: hue-rotate(90deg); + filter: hue-rotate(270deg); +} + +.second-student-background img { + -webkit-filter: hue-rotate(90deg); + filter: hue-rotate(90deg); +} + +.artifacts-quests-team { + margin-right: 5px; + float: left; + padding: 55px; + width: 70%; +} + +/* + ======================================== + Artifacts and Quests of Student! + ======================================== +*/ +.small-card-artifact { + transform: scale(0.6, 0.6); + -webkit-transform: scale(0.6, 0.6); +} + +.small-card-artifact { + border: 0px; + padding:0; + margin:0; + border-collapse: collapse; +} + +.artifacts-quests { + float: left; + padding: 35px; + width: 70%; + margin: 0 150px; +} + diff --git a/src/main/resources/static/creepy-guy.html b/src/main/resources/static/creepy-guy.html new file mode 100644 index 0000000..19d9676 --- /dev/null +++ b/src/main/resources/static/creepy-guy.html @@ -0,0 +1,150 @@ + + + + + + + Creepy Guy's Lair + + + + + + + + + +
+
+
+ +
+ +
+ +
+
+
+ +
+
+ +
+ +
+ +
+ +
+ Create Mentor +

Recruit Mentor

+ ______ +

Recruit a new soul, for there are not enough mentors to take care of the + Quest Store.

+
+ +
+
+ + + + + + + + + + +
+
+ +
+ +
+ +
+ Create Room +

Create Room

+ ______ +

You have a chance to design a new cozy Room for the future fellow + programmers!

+
+ +
+
+ + + + +
+
+ +
+ +
+ +
+ Edit Levels +

Edit Levels

+ ______ +

Want make levels harder or lower the plank? You are looking at the right + button.

+
+ +
+
+

Some Levels

+ Some level interaction goes here + + +
+
+ +
+ +
+ +
+ View Mentors +

View Mentors

+ ______ +

We know you want to peek on mentors... go on... we won't tell anyone.

+
+ +
+ +
+ +
+ +
+ +
+ + + + \ No newline at end of file diff --git a/src/main/resources/static/login.html b/src/main/resources/static/login.html new file mode 100644 index 0000000..2a8adb2 --- /dev/null +++ b/src/main/resources/static/login.html @@ -0,0 +1,124 @@ + + + + + + + Login to Quest Store + + + + + + + + + + + +
+ +
+ + + + \ No newline at end of file diff --git a/src/main/resources/static/main.html b/src/main/resources/static/main.html new file mode 100644 index 0000000..168ea23 --- /dev/null +++ b/src/main/resources/static/main.html @@ -0,0 +1,68 @@ + + + + + + + + + + Quest store + + + + + + + +
+
+
+ +
+ +
+ +
+
+
+ +
+
+ +
+ +
+ + + + +
+ + + +
+ + + + \ No newline at end of file diff --git a/src/main/resources/static/mentor.html b/src/main/resources/static/mentor.html new file mode 100644 index 0000000..f43ca3a --- /dev/null +++ b/src/main/resources/static/mentor.html @@ -0,0 +1,288 @@ + + + + + + + Mentor's Watch Tower + + + + + + + + + +
+
+
+ +
+ +
+ +
+
+
+ +
+
+ +
+ +
+ +
+ +
+ Create Student +

Create Student

+ ______ +

It's time to recruit a courageous warrior... or a DPSer... you know the + drill.

+
+ +
+
+ + + + + + + + + + +
+
+ +
+ +
+ +
+ Create Quest +

Create Quest

+ ______ +

It's ADVENTURE TIME!

+
+ +
+
+ + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ +
+ Create Artifact +

Create Artifact

+ ______ +

Make sure to close the door before leaving.

+
+ +
+
+ + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ +
+ Create Team +

Create Team

+ ______ +

So it begins.

+
+ +
+ +
+ + + + + + +
+
+ +
+ +
+ + I am notification of pending quests +
+ Review Quests +

Review Quests

+ ______ +

Feeling like an NPC in MMO yet?

+
+ +
+
+ Codecooler's Name + Quest's Title + + +
+
+ +
+ +
+ + I am notification of purchased artifacts +
+ Review Artifacts +

Review Artifacts

+ ______ +

Disable used artifacts.

+
+ +
+
+ Codecooler's Name / Team's Name + Artifact's Title + +
+
+ +
+ +
+ +
+ View Codecoolers +

View Codecoolers

+ ______ +

We know you want to peek on Codecoolers... go on... we won't tell + anyone.

+
+ +
+ +
+ +
+ View Quests +

View Quests

+ ______ +

Wonder what kind of challenges Codecoolers face?

+
+ +
+ +
+ +
+ View Artifacts +

View Artifacts

+ ______ +

Available for Indiana Jones ancestors only.

+
+ +
+ +
+ +
+ View Teams +

View Teams

+ ______ +

Assess the gathered power that has a potential to make you do something + unintelligent.

+
+ +
+ +
+ +
+ +
+ +
+ + + + \ No newline at end of file diff --git a/src/main/resources/static/mentors.html b/src/main/resources/static/mentors.html new file mode 100644 index 0000000..1d2f2b1 --- /dev/null +++ b/src/main/resources/static/mentors.html @@ -0,0 +1,140 @@ + + + + + + + + + + Mentors + + + + + + + + + +
+
+ +
+ +
+ + + +
+ +
+ +
+
+ +
+ +
+ + + +
+ +
+ Student photo +
+ +
+

Name:

+

Surname:

+

E-mail:

+

Phone number:

+
+ +
+ + + +
+ +
+ Student photo +
+ +
+

Name:

+

Surname:

+

E-mail:

+

Phone number:

+
+ +
+ + + +
+ +
+ Student photo +
+ +
+

Name:

+

Surname:

+

E-mail:

+

Phone number:

+
+ +
+ +
+ +
+ + + + +
+ + + +
+ + + + \ No newline at end of file diff --git a/src/main/resources/static/quests.html b/src/main/resources/static/quests.html new file mode 100644 index 0000000..5fdeee2 --- /dev/null +++ b/src/main/resources/static/quests.html @@ -0,0 +1,135 @@ + + + + + + + Quest Card + + + + + + + + +
+
+
+ +
+ +
+ +
+
+
+ +
+
+ +
+ +
+ + + +
+ +
+
+ Quest Image +
+ +
+ Pile of Coins +
+
+ +
+

9999

+
+ +
+

Title

+
+ +
+

Description

+
+ +
+ +
+ +
+ + + +
+ +
+
+ Quest Image +
+ +
+ Pile of Coins +
+
+ +
+

9999

+
+ +
+

Title

+
+ +
+

Description

+
+ +
+ +
+ +
+ +
+ +
+ +
+ + + +
+ + + + \ No newline at end of file diff --git a/src/main/resources/static/scripts/configuration-menu.js b/src/main/resources/static/scripts/configuration-menu.js new file mode 100644 index 0000000..a244380 --- /dev/null +++ b/src/main/resources/static/scripts/configuration-menu.js @@ -0,0 +1,25 @@ +"use strict"; + +function closeActionForm(actionForm) { + actionForm.style.display = "none"; +} + +function openActionForm(actionForm) { + actionForm.style.display = "block"; +} + +function toggleHideShowActionForm(actionForm) { + if (actionForm.style.display === "block") { + closeActionForm(actionForm); + } else { + openActionForm(actionForm); + } +} + +export function addEventListenerForTakeActionContainer(createButton, createForm) { + let createObjectButton = document.getElementById(createButton); + let createObjectForm = document.getElementById(createForm); + createObjectButton.addEventListener("click", function () { + toggleHideShowActionForm(createObjectForm); + }); +} \ No newline at end of file diff --git a/src/main/resources/static/scripts/creepy-guy.js b/src/main/resources/static/scripts/creepy-guy.js new file mode 100644 index 0000000..26601ec --- /dev/null +++ b/src/main/resources/static/scripts/creepy-guy.js @@ -0,0 +1,40 @@ +"use strict"; + +import { addEventListenerForTakeActionContainer } from './configuration-menu.js'; + +window.onload = function () { + addEventListenerForViewMentorsButton(); + enableEventListenersForTakeActionContainer(); + addEventListenerForNotificationOfMentor(); +}; + +function showMentorNotification() { + let notificationContainer = document.getElementById("creepy-guy-notification-message"); + notificationContainer.style.visibility = "visible"; + notificationContainer.innerText = "Mentor has been recruited."; +} + +function redirectToMentorsPage() { + window.location.href = "/mentors"; +} + +function addEventListenerForViewMentorsButton() { + let viewMentorsButton = document.getElementById("view-mentors-button"); + viewMentorsButton.addEventListener("click", redirectToMentorsPage); +} + +function addEventListenerForNotificationOfMentor() { + let submitButton = document.getElementById("create-mentor-form"); + submitButton.addEventListener("submit", handleMentorNotification); +} + +function handleMentorNotification() { + showMentorNotification(); +} + +function enableEventListenersForTakeActionContainer() { + addEventListenerForTakeActionContainer("create-mentor-button", "create-mentor-form"); + addEventListenerForTakeActionContainer("create-room-button", "create-room-form"); + addEventListenerForTakeActionContainer("edit-levels-button", "edit-levels-form"); +} + diff --git a/src/main/resources/static/scripts/mentor.js b/src/main/resources/static/scripts/mentor.js new file mode 100644 index 0000000..7bd22e3 --- /dev/null +++ b/src/main/resources/static/scripts/mentor.js @@ -0,0 +1,59 @@ +"use strict"; + +import { addEventListenerForTakeActionContainer } from './configuration-menu.js'; + +window.onload = function () { + handleViewButtonsRedirection(); + enableEventListenersForTakeActionContainer(); +}; + +function redirectToCodecoolersPage() { + window.location.href="/codecoolers"; +} + +function redirectToQuestsPage() { + window.location.href="/quests"; +} + +function redirectToArtifactsPage() { + window.location.href="/artifacts"; +} + +function redirectToTeamsPage() { + window.location.href="/teams"; +} + +function addEventListenerForViewCodecoolersButton() { + let viewCodecoolersButton = document.getElementById("view-codecoolers-button"); + viewCodecoolersButton.addEventListener("click", redirectToCodecoolersPage); +} + +function addEventListenerForViewQuestsButton() { + let viewQuestsButton = document.getElementById("view-quests-button"); + viewQuestsButton.addEventListener("click", redirectToQuestsPage); +} + +function addEventListenerForViewArtifactsButton() { + let viewArtifactsButton = document.getElementById("view-artifacts-button"); + viewArtifactsButton.addEventListener("click", redirectToArtifactsPage); +} + +function addEventListenerForViewTeamsButton() { + let viewArtifactsButton = document.getElementById("view-teams-button"); + viewArtifactsButton.addEventListener("click", redirectToTeamsPage); +} + +function handleViewButtonsRedirection() { + addEventListenerForViewCodecoolersButton(); + addEventListenerForViewQuestsButton(); + addEventListenerForViewArtifactsButton(); +} + +function enableEventListenersForTakeActionContainer() { + addEventListenerForTakeActionContainer("create-student-button", "create-student-form"); + addEventListenerForTakeActionContainer("create-quest-button", "create-quest-form"); + addEventListenerForTakeActionContainer("create-artifact-button", "create-artifact-form"); + addEventListenerForTakeActionContainer("create-team-button", "create-team-form"); + addEventListenerForTakeActionContainer("review-quests-button", "review-quests-form"); + addEventListenerForTakeActionContainer("review-artifacts-button", "review-artifacts-form"); +} diff --git a/src/main/resources/static/student.html b/src/main/resources/static/student.html new file mode 100644 index 0000000..c2014b1 --- /dev/null +++ b/src/main/resources/static/student.html @@ -0,0 +1,321 @@ + + + + + + + + + + Student + + + + + + + + + +
+ +
+ +
+ +
+ + + +
+ +
+ +
+ +
+ + + +
+ +
+ + + +
+ +
+ +
+ Student photo +
+ +
+ Number of Coins +
+ +
+

9999

+
+ + +
+

Name:

+

Surname:

+

E-mail:

+

Phone number:

+
+ +
+ + + +
+
+ + + +
+ + + +
+ +

My Artifacts

+ +
+ +
+ + + +
+ +
+ Artifact Image +
+ +
+ 9999 + Pile of coins +
+ +
+

Title

+
+ +
+

Description of artifact

+
+ +
+ +
+ +
+ + + + +
+ +
+ Artifact Image +
+ +
+ 9999 + Pile of coins +
+ +
+

Title

+
+ +
+

Description of artifact

+
+ +
+ +
+ +
+ +
+ +
+ + + +
+ +

My Quest

+ +
+ + + +
+ +
+
+ Quest Image +
+ +
+ Pile of Coins +
+
+ +
+

9999

+
+ +
+

Title

+
+ +
+

Description

+
+ +
+ +
+ +
+ + + +
+ +
+
+ Quest Image +
+ +
+ Pile of Coins +
+
+ +
+

9999

+
+ +
+

Title

+
+ +
+

Description

+
+ +
+ +
+ +
+ +
+
+ + + +
+ +

Pending Quests

+ + + +
+ +
+
+ Quest Image +
+ +
+ Pile of Coins +
+
+ +
+

9999

+
+ +
+

Title

+
+ +
+

Description

+
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ + + +
+ + + +
+ + + + \ No newline at end of file diff --git a/src/main/resources/static/students.html b/src/main/resources/static/students.html new file mode 100644 index 0000000..8a45781 --- /dev/null +++ b/src/main/resources/static/students.html @@ -0,0 +1,167 @@ + + + + + + + + + + Students + + + + + + + + + +
+
+ +
+ +
+ + + +
+ +
+ +
+
+ +
+ +
+ + + +
+ +
+ Student photo +
+ +
+ Number of Coins +
+ +
+

9999

+
+ + +
+

Name:

+

Surname:

+

E-mail:

+

Phone number:

+
+ +
+ + + +
+ +
+ Student photo +
+ +
+ Number of Coins +
+ +
+

9999

+
+ + +
+

Name:

+

Surname:

+

E-mail:

+

Phone number:

+
+ +
+ + + +
+ +
+ Student photo +
+ +
+ Number of Coins +
+ +
+

9999

+
+ + +
+

Name:

+

Surname:

+

E-mail:

+

Phone number:

+
+ +
+ +
+ +
+ + + + +
+ + + +
+ + + + \ No newline at end of file diff --git a/src/main/resources/static/team.html b/src/main/resources/static/team.html new file mode 100644 index 0000000..ac3fd02 --- /dev/null +++ b/src/main/resources/static/team.html @@ -0,0 +1,290 @@ + + + + + + + + + + Team of Quest store + + + + + + + + +
+ +
+ +
+ +
+ + + +
+ +
+ +
+ +
+ + + +
+ +
+ +
+ + + +
+ +
+ Student photo +
+ +
+ Number of Coins +
+ +
+

9999

+
+ + +
+

Name:

+

Surname:

+

E-mail:

+

Phone number:

+
+ +
+ + + +
+ +
+ Student photo +
+ +
+ Number of Coins +
+ +
+

9999

+
+ + +
+

Name:

+

Surname:

+

E-mail:

+

Phone number:

+
+ +
+ + + +
+ +
+ Student photo +
+ +
+ Number of Coins +
+ +
+

9999

+
+ + +
+

Name:

+

Surname:

+

E-mail:

+

Phone number:

+
+ +
+ +
+ + + +
+ + + +
+ +

My Artifacts

+ +
+ +
+ + + +
+ +
+ Artifact Image +
+ +
+ 9999 + Pile of coins +
+ +
+

Title

+
+ +
+

Description of artifact

+
+ +
+ +
+ +
+ + + + + +
+ +
+ Artifact Image +
+ +
+ 9999 + Pile of coins +
+ +
+

Title

+
+ +
+

Description of artifact

+
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +

Pending Artifacts

+ +
+ +
+ Artifact Image +
+ +
+ 9999 + Pile of coins +
+ +
+

Title

+
+ +
+

Description of artifact

+
+ +
+ +
+ +
+ +
+ + + +
+ +
+ +
+ + + + + +
+ + + +
+ + + + \ No newline at end of file diff --git a/src/main/resources/templates/artifacts.twig b/src/main/resources/templates/artifacts.twig new file mode 100644 index 0000000..5bceba7 --- /dev/null +++ b/src/main/resources/templates/artifacts.twig @@ -0,0 +1,128 @@ + + + + + + + Artifacts + + + + + + + + +{% set userType = user.getTypeId %} +
+ {% if 1 in userType %} + {% include "classpath:/templates/student-header.twig" ignore missing %} + {% endif %} + {% if 2 in userType %} + {% include "classpath:/templates/mentor-header.twig" ignore missing %} + {% endif %} +
+{% if 2 in userType %} +
+

Current discount: {{ discount }}%

+
+ + + +
+
+{% endif %} +
+ +
+ + + + {% for artifact in normal_artifacts %} + {% set newPrice = artifact.getDiscountedPrice(discount) %} +
+ +
+ Artifact Image +
+ +
+ {% if discount == 0 %} + {{ artifact.getPrice }} + {% else %} + {{ artifact.getPrice }} + {{ newPrice }} + {% endif %} + Pile of coins +
+ +
+

{{ artifact.getTitle }}

+
+ +
+

{{ artifact.getDescription }}

+
+ {% if 1 in userType %} +
+
+ +
+
+ {% endif %} +
+ + {% endfor %} + + + {% for artifact in magic_artifacts %} + {% set newPrice = artifact.getDiscountedPrice(discount) %} + +
+ +
+ Artifact Image +
+ +
+ {% if discount == 0 %} + {{ artifact.getPrice }} + {% else %} + {{ artifact.getPrice }} + {{ newPrice }} + {% endif %} + Pile of coins +
+ +
+

{{ artifact.getTitle }}

+
+ +
+

{{ artifact.getDescription }}

+
+ {% if 1 in userType %} +
+
+ +
+
+ {% endif %} +
+ + {% endfor %} + +
+ +
+
+ {% if 1 in userType %} + {% include "classpath:/templates/student-footer.twig" ignore missing %} + {% endif %} + {% if 2 in userType %} + {% include "classpath:/templates/mentor-footer.twig" ignore missing %} + {% endif %} +
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/creepy-guy-footer.twig b/src/main/resources/templates/creepy-guy-footer.twig new file mode 100644 index 0000000..19ac2a7 --- /dev/null +++ b/src/main/resources/templates/creepy-guy-footer.twig @@ -0,0 +1,22 @@ + \ No newline at end of file diff --git a/src/main/resources/templates/creepy-guy-header.twig b/src/main/resources/templates/creepy-guy-header.twig new file mode 100644 index 0000000..1888344 --- /dev/null +++ b/src/main/resources/templates/creepy-guy-header.twig @@ -0,0 +1,30 @@ +
+ +
+ +
+ + + +
+ +
+ +
\ No newline at end of file diff --git a/src/main/resources/templates/creepy-guy.twig b/src/main/resources/templates/creepy-guy.twig new file mode 100644 index 0000000..e6e7da6 --- /dev/null +++ b/src/main/resources/templates/creepy-guy.twig @@ -0,0 +1,132 @@ + + + + + + + Creepy Guy's Lair + + + + + + + + + + + + + +
+ + {% include "classpath:/templates/creepy-guy-header.twig" ignore missing %} + +
+ +
+ +
+
+ +
+ +
+ +
+ Create Mentor +

Recruit Mentor

+ ______ +

Recruit a new soul, for there are not enough mentors to take care of the + Quest Store.

+
+ +
+
+ + + + + + + + + + +
+
+ +
+ +
+ +
+ Create Room +

Create Room

+ ______ +

You have a chance to design a new cozy Room for the future fellow + programmers!

+
+ +
+
+ + + + +
+
+ +
+ +
+ +
+ Edit Levels +

Edit Levels

+ ______ +

Want make levels harder or lower the plank? You are looking at the right + button.

+
+ +
+
+

Some Levels

+ Some level interaction goes here + + +
+
+ +
+ +
+ +
+ View Mentors +

View Mentors

+ ______ +

We know you want to peek on mentors... go on... we won't tell anyone.

+
+ +
+ +
+ +
+ +
+ + {% include "classpath:/templates/creepy-guy-footer.twig" ignore missing %} + +
+ + + + \ No newline at end of file diff --git a/src/main/resources/templates/login.twig b/src/main/resources/templates/login.twig new file mode 100644 index 0000000..5f0d840 --- /dev/null +++ b/src/main/resources/templates/login.twig @@ -0,0 +1,124 @@ + + + + + + + Login to Quest Store + + + + + + + + + + + +
+ +
+ + + + \ No newline at end of file diff --git a/src/main/resources/templates/mentor-footer.twig b/src/main/resources/templates/mentor-footer.twig new file mode 100644 index 0000000..5adbc1b --- /dev/null +++ b/src/main/resources/templates/mentor-footer.twig @@ -0,0 +1,22 @@ + \ No newline at end of file diff --git a/src/main/resources/templates/mentor-header.twig b/src/main/resources/templates/mentor-header.twig new file mode 100644 index 0000000..2ac9fa1 --- /dev/null +++ b/src/main/resources/templates/mentor-header.twig @@ -0,0 +1,33 @@ +
+ +
+ +
+ + + +
+ +
+ +
\ No newline at end of file diff --git a/src/main/resources/templates/mentor.twig b/src/main/resources/templates/mentor.twig new file mode 100644 index 0000000..504f158 --- /dev/null +++ b/src/main/resources/templates/mentor.twig @@ -0,0 +1,265 @@ + + + + + + + Mentor's Watch Tower + + + + + + + + + + + + + +
+ + {% include "classpath:/templates/mentor-header.twig" ignore missing %} + +
+ +
+ +
+
+ +
+ +
+ +
+ Create Student +

Create Student

+ ______ +

It's time to recruit a courageous warrior... or a DPSer... you know the + drill.

+
+ +
+
+ + + + + + + + + + +
+
+ +
+ +
+ +
+ Create Quest +

Create Quest

+ ______ +

It's ADVENTURE TIME!

+
+ +
+
+ + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ +
+ Create Artifact +

Create Artifact

+ ______ +

Make sure to close the door before leaving.

+
+ +
+
+ + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ +
+ Create Team +

Create Team

+ ______ +

So it begins.

+
+ +
+ +
+ + + + + + +
+
+ +
+ +
+ + I am notification of pending quests +
+ Review Quests +

Review Quests

+ ______ +

Feeling like an NPC in MMO yet?

+
+ +
+
+ Codecooler's Name + Quest's Title + + +
+
+ +
+ +
+ + I am notification of purchased artifacts +
+ Review Artifacts +

Review Artifacts

+ ______ +

Disable used artifacts.

+
+ +
+
+ Codecooler's Name / Team's Name + Artifact's Title + +
+
+ +
+ +
+ +
+ View Codecoolers +

View Codecoolers

+ ______ +

We know you want to peek on Codecoolers... go on... we won't tell + anyone.

+
+ +
+ +
+ +
+ View Quests +

View Quests

+ ______ +

Wonder what kind of challenges Codecoolers face?

+
+ +
+ +
+ +
+ View Artifacts +

View Artifacts

+ ______ +

Available for Indiana Jones ancestors only.

+
+ +
+ +
+ +
+ View Teams +

View Teams

+ ______ +

Assess the gathered power that has a potential to make you do something + unintelligent.

+
+ +
+ +
+ +
+ +
+ + {% include "classpath:/templates/mentor-footer.twig" ignore missing %} + +
+ + + + \ No newline at end of file diff --git a/src/main/resources/templates/mentors.twig b/src/main/resources/templates/mentors.twig new file mode 100644 index 0000000..71d9e9f --- /dev/null +++ b/src/main/resources/templates/mentors.twig @@ -0,0 +1,59 @@ + + + + + + + Mentors + + + + + + + + + + + + +
+ + {% include "classpath:/templates/creepy-guy-header.twig" ignore missing %} + +
+ +
+ +
+ + {% for mentor in mentors %} +
+ +
+ Mentor's Photo +
+ +
+

Name:
{{ mentor.getName }}

+

Surname:
{{ mentor.getSurname }}

+

E-mail:
{{ mentor.getEmail }}

+

Phone number:
{{ mentor.getPhoneNumber }}

+
+ +
+ {% endfor %} + +
+ +
+ +
+ + {% include "classpath:/templates/creepy-guy-footer.twig" ignore missing %} + +
+ + + + \ No newline at end of file diff --git a/src/main/resources/templates/quests.twig b/src/main/resources/templates/quests.twig new file mode 100644 index 0000000..81886e1 --- /dev/null +++ b/src/main/resources/templates/quests.twig @@ -0,0 +1,120 @@ + + + + + + + Quests + + + + + + + +{% set userType = user.getTypeId %} +
+ {% if 1 in userType %} + {% include "classpath:/templates/student-header.twig" ignore missing %} + {% endif %} + {% if 2 in userType %} + {% include "classpath:/templates/mentor-header.twig" ignore missing %} + {% endif %} +
+ +
+ +
+ + + + {% for quest in basic_quests %} + +
+ +
+
+ Quest Image +
+ +
+ Pile of Coins +
+
+ +
+

{{ quest.getPrice }}

+
+ +
+

{{ quest.getTitle }}

+
+ +
+

{{ quest.getDescription }}

+
+ {% if 1 in userType %} +
+
+ +
+
+ {% endif %} +
+ + {% endfor %} + + {% for quest in extra_quests %} + + + +
+ +
+
+ Quest Image +
+ +
+ Pile of Coins +
+
+ +
+

{{ quest.getPrice }}

+
+ +
+

{{ quest.getTitle }}

+
+ +
+

{{ quest.getDescription }}

+
+ {% if 1 in userType %} +
+
+ +
+
+ {% endif %} +
+ + {% endfor %} + +
+ +
+ +
+ {% if 1 in userType %} + {% include "classpath:/templates/student-footer.twig" ignore missing %} + {% endif %} + {% if 2 in userType %} + {% include "classpath:/templates/mentor-footer.twig" ignore missing %} + {% endif %} +
+ + + + \ No newline at end of file diff --git a/src/main/resources/templates/student-footer.twig b/src/main/resources/templates/student-footer.twig new file mode 100644 index 0000000..b1a07fd --- /dev/null +++ b/src/main/resources/templates/student-footer.twig @@ -0,0 +1,19 @@ + \ No newline at end of file diff --git a/src/main/resources/templates/student-header.twig b/src/main/resources/templates/student-header.twig new file mode 100644 index 0000000..45a69b0 --- /dev/null +++ b/src/main/resources/templates/student-header.twig @@ -0,0 +1,26 @@ +
+ +
+ +
+ + +
\ No newline at end of file diff --git a/src/main/resources/templates/student.twig b/src/main/resources/templates/student.twig new file mode 100644 index 0000000..34e7033 --- /dev/null +++ b/src/main/resources/templates/student.twig @@ -0,0 +1,255 @@ + + + + + + + Student + + + + + + + + + +
+ +
+ +
+ +
+ + + +
+ + {#
+ +
#} + +
+ + + +
+ +
+ + + +
+ +
+ +
+ Student photo +
+ +
+ Number of Coins +
+ +
+

{{ wallet }}

+
+ + +
+

Name:
{{ name }}

+

Surname:
{{ surname }}

+

E-mail:
{{ email }}

+

Phone number:
{{ phone }}

+
+ +
+ + + + +
+
+ + + +
+ + + +
+ +

My Artifacts

+ +
+ + + + {% for artifact in artifacts %} + +
+ +
+ Artifact Image +
+ +
+ {{ artifact.getPrice }} + Pile of coins +
+ +
+

{{ artifact.getTitle }}

+
+ +
+

{{ artifact.getDescription }}

+
+ + +
+ {% endfor %} + +
+
+ + + +
+ +

My Quest

+ +
+ + + + {% for quest in basic_quests %} + +
+ +
+
+ Quest Image +
+ +
+ Pile of Coins +
+
+ +
+

{{ quest.getPrice }}

+
+ +
+

{{ quest.getTitle }}

+
+ +
+

{{ quest.getDescription }}

+
+ +
+ {% endfor %} + + + + {% for quest in extra_quests %} + +
+ +
+
+ Quest Image +
+ +
+ Pile of Coins +
+
+ +
+

{{ quest.getPrice }}

+
+ +
+

{{ quest.getTitle }}

+
+ +
+

{{ quest.getDescription }}

+
+ +
+ {% endfor %} + +
+ +
+ + + +
+ +

Pending Quests

+ +
+ +
+ + + +
+ + + +
+ + + +
+ + + + \ No newline at end of file diff --git a/src/main/resources/templates/students.twig b/src/main/resources/templates/students.twig new file mode 100644 index 0000000..65aa001 --- /dev/null +++ b/src/main/resources/templates/students.twig @@ -0,0 +1,70 @@ + + + + + + + Codecoolers + + + + + + + + + + + + +
+ + {% include "classpath:/templates/mentor-header.twig" ignore missing %} + +
+ + +
+ +
+ + {% for codecooler in codecoolers %} + +
+ +
+ Student photo +
+ +
+ Number of Coins +
+ +
+

{{ balance.getBalance(codecooler) }}

+
+ +
+

Name:
{{ codecooler.getName }}

+

Surname:
{{ codecooler.getSurname }}

+

E-mail:
{{ codecooler.getEmail }}

+

Phone number:
{{ codecooler.getPhoneNumber }}

+
+ +
+ + {% endfor %} + +
+ +
+ + + + + + \ No newline at end of file