commit c7d5764c435331db96f3ff26b80e2e2e0ee8509d Author: Maciej Życzyński Date: Fri Jun 21 11:33:20 2024 +0200 todoapp diff --git a/todoapp/.vscode/settings.json b/todoapp/.vscode/settings.json new file mode 100644 index 0000000..9462fd1 --- /dev/null +++ b/todoapp/.vscode/settings.json @@ -0,0 +1,13 @@ +{ + "java.jdt.ls.java.home": "C:\\Program Files\\Java\\jdk-22", + "java.configuration.runtimes": [ + { + "name": "JavaSE-22", + "path": "C:\\Program Files\\Java\\jdk-22", + "default": true + } + ], + "java.configuration.updateBuildConfiguration": "automatic", + "java.dependency.packagePresentation": "flat" + } + \ No newline at end of file diff --git a/todoapp/lib/commons-io-2.16.1.jar b/todoapp/lib/commons-io-2.16.1.jar new file mode 100644 index 0000000..eb3c2b0 Binary files /dev/null and b/todoapp/lib/commons-io-2.16.1.jar differ diff --git a/todoapp/lib/javax.servlet-api-4.0.1.jar b/todoapp/lib/javax.servlet-api-4.0.1.jar new file mode 100644 index 0000000..844ec7f Binary files /dev/null and b/todoapp/lib/javax.servlet-api-4.0.1.jar differ diff --git a/todoapp/pom.xml b/todoapp/pom.xml new file mode 100644 index 0000000..ee66060 --- /dev/null +++ b/todoapp/pom.xml @@ -0,0 +1,131 @@ + + + + 4.0.0 + + todoapp + demo + 1 + war + + demo + http://www.example.com + + + UTF-8 + 22 + 22 + + + + + + com.fasterxml.jackson.core + jackson-core + 2.13.0 + + + + + com.fasterxml.jackson.core + jackson-databind + 2.13.0 + + + + + org.slf4j + slf4j-api + 1.7.32 + + + + + ch.qos.logback + logback-classic + 1.2.6 + + + + + org.eclipse.jetty + jetty-server + 10.0.6 + + + + + org.eclipse.jetty + jetty-servlet + 10.0.6 + + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + + mysql + mysql-connector-java + 8.0.33 + + + + + junit + junit + 4.11 + test + + + + + + + + maven-clean-plugin + 3.1.0 + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-jar-plugin + 3.0.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + maven-site-plugin + 3.7.1 + + + maven-project-info-reports-plugin + 3.0.0 + + + + + diff --git a/todoapp/src/main/java/todoapp/JettyServer.java b/todoapp/src/main/java/todoapp/JettyServer.java new file mode 100644 index 0000000..c4aa8f0 --- /dev/null +++ b/todoapp/src/main/java/todoapp/JettyServer.java @@ -0,0 +1,44 @@ +package todoapp; + +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.eclipse.jetty.servlet.DefaultServlet; + +public class JettyServer { + + public static void main(String[] args) throws Exception { + int port = 8080; + + // create Jetty server with 8 threads + QueuedThreadPool threadPool = new QueuedThreadPool(8); + Server server = new Server(threadPool); + + // establishing connector + ServerConnector connector = new ServerConnector(server); + connector.setPort(port); + server.addConnector(connector); + + // Create a servlet context handler + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/todoapp"); + + // adding TaskServlet to the servlet context + context.addServlet(new ServletHolder(new TaskServlet()), "/api/tasks/*"); + + // adding static files from /webapp + String webappDir = "src/main/webapp"; + ServletHolder defaultServletHolder = new ServletHolder("default", DefaultServlet.class); + defaultServletHolder.setInitParameter("resourceBase", webappDir); + defaultServletHolder.setInitParameter("dirAllowed", "true"); + context.addServlet(defaultServletHolder, "/"); + server.setHandler(context); + + // starting the server + server.start(); + System.out.println("Server started on port " + port); + server.join(); + } +} diff --git a/todoapp/src/main/java/todoapp/Task.java b/todoapp/src/main/java/todoapp/Task.java new file mode 100644 index 0000000..bcd2ac3 --- /dev/null +++ b/todoapp/src/main/java/todoapp/Task.java @@ -0,0 +1,37 @@ +package todoapp; + +public class Task { + private int Number; + private String Text; + private boolean isDone; + + public Task(int Number, String Text, boolean isDone) { + this.Number = Number; + this.Text = Text; + this.isDone = isDone; + } + + public int getNumber() { + return Number; + } + + public void setNumber(int Number) { + this.Number = Number; + } + + public String getText() { + return Text; + } + + public void setText(String Text) { + this.Text = Text; + } + + public boolean isStatus() { + return isDone; + } + + public void setStatus(boolean isDone) { + this.isDone = isDone; + } +} diff --git a/todoapp/src/main/java/todoapp/TaskServlet.java b/todoapp/src/main/java/todoapp/TaskServlet.java new file mode 100644 index 0000000..d5c918f --- /dev/null +++ b/todoapp/src/main/java/todoapp/TaskServlet.java @@ -0,0 +1,126 @@ +package todoapp; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class TaskServlet extends HttpServlet { + + //GET, gets info about either all tasks or a specific one depending on path received + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + String pathInfo = request.getPathInfo(); + if (pathInfo == null || pathInfo.equals("/")) { + // return all tasks + List tasks = TodoAppDAO.getAllTasks(); + ObjectMapper mapper = new ObjectMapper(); + response.setContentType("application/json"); + mapper.writeValue(response.getWriter(), tasks); + } else { + // return specific task + try { + int taskNumber = Integer.parseInt(pathInfo.substring(1)); + Task task = TodoAppDAO.getTaskByNumber(taskNumber); + if (task != null) { + ObjectMapper mapper = new ObjectMapper(); + response.setContentType("application/json"); + mapper.writeValue(response.getWriter(), task); + } else { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + response.getWriter().write("{\"error\": \"Task not found\"}"); + } + } catch (NumberFormatException e) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + response.getWriter().write("{\"error\": \"Invalid task number\"}"); + } + } + } + + // POST (receives string and adds a new task with set string as text) + @Override + protected void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + BufferedReader reader = request.getReader(); + String taskText = reader.lines().collect(Collectors.joining(System.lineSeparator())); + boolean success = TodoAppDAO.addTask(taskText); + + if (success) { + response.setStatus(HttpServletResponse.SC_CREATED); + response.getWriter().write("{\"success\": true}"); + } else { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + response.getWriter().write("{\"success\": false}"); + } + } + + // PUT, edit task's status + @Override + protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + String pathInfo = request.getPathInfo(); + if (pathInfo != null) { + try { + int taskNumber = Integer.parseInt(pathInfo.substring(1)); + + // get set task's isDone status + Task currentTask = TodoAppDAO.getTaskByNumber(taskNumber); + if (currentTask == null) { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + response.getWriter().write("{\"error\": \"Task not found\"}"); + return; + } + + // new status is set to !isDone + boolean newStatus = !currentTask.isStatus(); + boolean success = TodoAppDAO.updateTaskStatus(taskNumber, newStatus); + + if (success) { + response.setStatus(HttpServletResponse.SC_OK); + response.getWriter().write("{\"success\": true}"); + } else { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + response.getWriter().write("{\"success\": false}"); + } + } catch (NumberFormatException e) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + response.getWriter().write("{\"error\": \"Invalid task number\"}"); + } + } else { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + response.getWriter().write("{\"error\": \"Invalid request\"}"); + } + } + + + //DELETE, deletes a task + @Override + protected void doDelete(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + String pathInfo = request.getPathInfo(); + if (pathInfo != null) { + try { + int taskNumber = Integer.parseInt(pathInfo.substring(1)); + boolean success = TodoAppDAO.deleteTask(taskNumber); + if (success) { + response.setStatus(HttpServletResponse.SC_OK); + response.getWriter().write("{\"success\": true}"); + } else { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + response.getWriter().write("{\"success\": false}"); + } + } catch (NumberFormatException e) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + response.getWriter().write("{\"error\": \"Invalid task number\"}"); + } + } else { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + response.getWriter().write("{\"error\": \"Invalid request\"}"); + } + } +} diff --git a/todoapp/src/main/java/todoapp/TodoAppDAO.java b/todoapp/src/main/java/todoapp/TodoAppDAO.java new file mode 100644 index 0000000..0da6956 --- /dev/null +++ b/todoapp/src/main/java/todoapp/TodoAppDAO.java @@ -0,0 +1,136 @@ +package todoapp; + +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + +public class TodoAppDAO { + + private static final String JDBC_URL = "jdbc:mysql://mysql.wmi.amu.edu.pl/s492459_db1"; + private static final String USERNAME = "s492459"; + private static final String PASSWORD = "TYmmLNTTH2"; + + @FunctionalInterface + private interface DatabaseOperation { + T execute(Connection conn) throws SQLException; + } + + // Function returning amount of current tasks + private static int howManyCurrentTasks() { + String getTasksSql = "SELECT Number FROM todoapp_entries ORDER BY Number"; + return executeOperation(conn -> { + try (Statement statement = conn.createStatement(); + ResultSet resultSet = statement.executeQuery(getTasksSql)) { + int taskAmount = 0; + while (resultSet.next()) { + taskAmount += 1; + } + return taskAmount; + } + }); + } + + // Connect to MySQL database + private static T executeOperation(DatabaseOperation operation) { + try (Connection conn = DriverManager.getConnection(JDBC_URL, USERNAME, PASSWORD)) { + return operation.execute(conn); + } catch (SQLException e) { + e.printStackTrace(); + return null; + } + } + + // Method to get a task by its number + public static Task getTaskByNumber(int number) { + String getTaskSql = "SELECT Number, Text, isDone FROM todoapp_entries WHERE Number = ?"; + return executeOperation(conn -> { + try (PreparedStatement preparedStatement = conn.prepareStatement(getTaskSql)) { + preparedStatement.setInt(1, number); + try (ResultSet resultSet = preparedStatement.executeQuery()) { + if (resultSet.next()) { + String text = resultSet.getString("Text"); + boolean isDone = resultSet.getBoolean("isDone"); + return new Task(number, text, isDone); + } + } + } + return null; + }); + } + + // Add task + public static boolean addTask(String text) { + String addTaskSql = "INSERT INTO todoapp_entries (Number, Text, isDone) VALUES (?, ?, 0)"; + return executeOperation(conn -> { + try (PreparedStatement preparedStatement = conn.prepareStatement(addTaskSql)) { + int newTaskNumber = howManyCurrentTasks() + 1; + preparedStatement.setInt(1, newTaskNumber); + preparedStatement.setString(2, text); + int rowsAffected = preparedStatement.executeUpdate(); + return rowsAffected > 0; + } + }); + } + + // Change status + public static boolean updateTaskStatus(int number, boolean isDone) { + String updateStatusSql = "UPDATE todoapp_entries SET isDone = ? WHERE Number = ?"; + return executeOperation(conn -> { + try (PreparedStatement preparedStatement = conn.prepareStatement(updateStatusSql)) { + preparedStatement.setBoolean(1, isDone); + preparedStatement.setInt(2, number); + int rowsAffected = preparedStatement.executeUpdate(); + return rowsAffected > 0; + } + }); + } + + + // Delete task and update numeration accordingly + public static boolean deleteTask(int number) { + String deleteTaskSql = "DELETE FROM todoapp_entries WHERE Number = ?"; + boolean isSuccessful = executeOperation(conn -> { + try (PreparedStatement preparedStatement = conn.prepareStatement(deleteTaskSql)) { + preparedStatement.setInt(1, number); + int rowsAffected = preparedStatement.executeUpdate(); + return rowsAffected > 0; + } + }); + if (isSuccessful) { + int taskAmount = howManyCurrentTasks() + 2; + for (int i = number + 1; i < taskAmount; i++) { + int oldNumber = i; + int newNumber = i - 1; + String updateTaskNumberSql = "UPDATE todoapp_entries SET Number = ? WHERE Number = ?"; + executeOperation(conn -> { + try (PreparedStatement preparedStatement = conn.prepareStatement(updateTaskNumberSql)) { + preparedStatement.setInt(1, newNumber); + preparedStatement.setInt(2, oldNumber); + preparedStatement.executeUpdate(); + } + return null; + }); + } + } + + return isSuccessful; + } + + // Get tasks + public static List getAllTasks() { + String getAllTasksSql = "SELECT Number, Text, isDone FROM todoapp_entries"; + return executeOperation(conn -> { + List tasks = new ArrayList<>(); + try (Statement statement = conn.createStatement(); + ResultSet resultSet = statement.executeQuery(getAllTasksSql)) { + while (resultSet.next()) { + int number = resultSet.getInt("Number"); + String text = resultSet.getString("Text"); + boolean isDone = resultSet.getInt("isDone") == 1; + tasks.add(new Task(number, text, isDone)); + } + } + return tasks; + }); + } +} diff --git a/todoapp/src/main/webapp/css/styles.css b/todoapp/src/main/webapp/css/styles.css new file mode 100644 index 0000000..dab717f --- /dev/null +++ b/todoapp/src/main/webapp/css/styles.css @@ -0,0 +1,114 @@ +body { + font-family: Arial, sans-serif; + background-color: #f5f5f5; + margin: 20px; + padding: 20px; + max-width: 800px; + margin: auto; +} + +h1 { + text-align: center; + color: #333; + margin-bottom: 20px; + text-shadow: 2px 2px 2px rgba(0, 0, 0, 0.1); +} + +#addTaskForm { + display: flex; + justify-content: center; + margin-bottom: 20px; +} + +#taskText { + flex: 1; + padding: 10px; + border: 1px solid #ccc; + border-radius: 5px 0 0 5px; + font-size: 16px; +} + +#addTaskForm button { + padding: 10px 20px; + border: 1px solid #ccc; + border-left: none; + border-radius: 0 5px 5px 0; + background-color: #4CAF50; + color: white; + font-size: 16px; + cursor: pointer; + transition: background-color 0.3s ease; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} + +#addTaskForm button:hover { + background-color: #45a049; +} + +.task-list { + list-style-type: none; + padding: 0; +} + +.task-item { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 10px; + padding: 10px; + background-color: white; + border: 1px solid #ccc; + border-radius: 5px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + transition: background-color 0.3s ease, transform 0.2s ease; +} + +.task-item.done { + background-color: #e0f7fa; + transform: scale(0.98); +} + +.task-number { + font-weight: bold; + color: #666; + margin-right: 10px; +} + +.task-text { + flex: 1; +} + +.task-actions { + display: flex; + gap: 5px; +} + +.task-actions button { + padding: 5px 10px; + border: 1px solid #ccc; + border-radius: 3px; + background-color: #f0f0f0; + color: #333; + font-size: 14px; + cursor: pointer; + transition: background-color 0.3s ease, transform 0.2s ease; +} + +.task-actions button:hover { + background-color: #e0e0e0; + transform: translateY(-2px); +} + +.task-actions button.done { + background-color: #4CAF50; + color: white; + transform: translateY(-2px); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} + +.task-actions button.delete { + background-color: #f44336; + color: white; + transform: translateY(-2px); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} diff --git a/todoapp/src/main/webapp/index.html b/todoapp/src/main/webapp/index.html new file mode 100644 index 0000000..0134dae --- /dev/null +++ b/todoapp/src/main/webapp/index.html @@ -0,0 +1,27 @@ + + + + + + + Todo App + + + + +

Todo App

+ + +
+ + +
+ + +
    + + + + + + diff --git a/todoapp/src/main/webapp/js/script.js b/todoapp/src/main/webapp/js/script.js new file mode 100644 index 0000000..74ee2e7 --- /dev/null +++ b/todoapp/src/main/webapp/js/script.js @@ -0,0 +1,134 @@ +// fetch tasks from backends (GET) +function fetchTasks() { + fetch('/todoapp/api/tasks') + .then(response => { + if (!response.ok) { + throw new Error('Failed to fetch tasks'); + } + return response.json(); + }) + .then(tasks => { + const taskList = document.getElementById('taskList'); + taskList.innerHTML = ''; // Clear existing list + + tasks.forEach(task => { + const taskItem = createTaskElement(task); + taskList.appendChild(taskItem); + }); + }) + .catch(error => console.error('Error fetching tasks:', error)); +} + +// function adding new task to the list +function createTaskElement(task) { + const taskItem = document.createElement('li'); + taskItem.classList.add('task-item'); + + if (task.status) { + taskItem.classList.add('done'); + } + + // adding number + const taskNumber = document.createElement('span'); + taskNumber.classList.add('task-number'); + taskNumber.textContent = `#${task.number}`; + taskItem.appendChild(taskNumber); + + // adding text + const taskText = document.createElement('span'); + taskText.classList.add('task-text'); + taskText.textContent = task.text; + taskItem.appendChild(taskText); + + // adding buttons + const taskActions = document.createElement('div'); + taskActions.classList.add('task-actions'); + + // button for changing status + const doneButton = document.createElement('button'); + doneButton.textContent = task.isDone ? 'Undo' : 'Done'; + doneButton.addEventListener('click', function() { + updateTaskStatus(task.number, !task.isDone); + }); + taskActions.appendChild(doneButton); + + // button for deleting + const deleteButton = document.createElement('button'); + deleteButton.textContent = 'Delete'; + deleteButton.addEventListener('click', function() { + deleteTask(task.number); + }); + taskActions.appendChild(deleteButton); + + taskItem.appendChild(taskActions); + + return taskItem; +} + +// add new task (POST) +document.getElementById('addTaskForm').addEventListener('submit', function(event) { + event.preventDefault(); + const taskText = document.getElementById('taskText').value.trim(); + if (taskText === '') { + alert('Task description cannot be empty'); + return; + } + + fetch('/todoapp/api/tasks', { + method: 'POST', + headers: { + 'Content-Type': 'text/plain', //request sends a string + }, + body: taskText, + }) + .then(response => { + if (!response.ok) { + throw new Error('Failed to add task'); + } + return response.json(); + }) + .then(result => { + if (result.success) { + document.getElementById('taskText').value = ''; //clear input area + fetchTasks(); // Refresh task list after adding new task + } else { + console.error('Failed to add task'); + } + }) + .catch(error => console.error('Error adding task:', error)); +}); + +// update status (PUT) +function updateTaskStatus(taskNumber, isDone) { + fetch(`/todoapp/api/tasks/${taskNumber}`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', //request sends a json table with task's data + }, + body: JSON.stringify({ isDone: isDone }) + }) + .then(response => { + if (!response.ok) { + throw new Error('Failed to update task status'); + } + fetchTasks(); + }) + .catch(error => console.error('Error updating task status:', error)); +} + +// delete a task (DELETE) +function deleteTask(taskNumber) { + fetch(`/todoapp/api/tasks/${taskNumber}`, { + method: 'DELETE' + }) + .then(response => { + if (!response.ok) { + throw new Error('Failed to delete task'); + } + fetchTasks(); + }) + .catch(error => console.error('Error deleting task:', error)); +} + +// fetch tasks on startup +fetchTasks(); diff --git a/todoapp/target/classes/todoapp/JettyServer.class b/todoapp/target/classes/todoapp/JettyServer.class new file mode 100644 index 0000000..3cc350d Binary files /dev/null and b/todoapp/target/classes/todoapp/JettyServer.class differ diff --git a/todoapp/target/classes/todoapp/Task.class b/todoapp/target/classes/todoapp/Task.class new file mode 100644 index 0000000..5b2e2e8 Binary files /dev/null and b/todoapp/target/classes/todoapp/Task.class differ diff --git a/todoapp/target/classes/todoapp/TaskServlet.class b/todoapp/target/classes/todoapp/TaskServlet.class new file mode 100644 index 0000000..bdcbc39 Binary files /dev/null and b/todoapp/target/classes/todoapp/TaskServlet.class differ diff --git a/todoapp/target/classes/todoapp/TodoAppDAO$DatabaseOperation.class b/todoapp/target/classes/todoapp/TodoAppDAO$DatabaseOperation.class new file mode 100644 index 0000000..2a94abb Binary files /dev/null and b/todoapp/target/classes/todoapp/TodoAppDAO$DatabaseOperation.class differ diff --git a/todoapp/target/classes/todoapp/TodoAppDAO.class b/todoapp/target/classes/todoapp/TodoAppDAO.class new file mode 100644 index 0000000..d9ef72b Binary files /dev/null and b/todoapp/target/classes/todoapp/TodoAppDAO.class differ diff --git a/todoapp/target/demo-1/WEB-INF/classes/todoapp/JettyServer.class b/todoapp/target/demo-1/WEB-INF/classes/todoapp/JettyServer.class new file mode 100644 index 0000000..3cc350d Binary files /dev/null and b/todoapp/target/demo-1/WEB-INF/classes/todoapp/JettyServer.class differ diff --git a/todoapp/target/demo-1/WEB-INF/classes/todoapp/Task.class b/todoapp/target/demo-1/WEB-INF/classes/todoapp/Task.class new file mode 100644 index 0000000..5b2e2e8 Binary files /dev/null and b/todoapp/target/demo-1/WEB-INF/classes/todoapp/Task.class differ diff --git a/todoapp/target/demo-1/WEB-INF/classes/todoapp/TaskServlet.class b/todoapp/target/demo-1/WEB-INF/classes/todoapp/TaskServlet.class new file mode 100644 index 0000000..bdcbc39 Binary files /dev/null and b/todoapp/target/demo-1/WEB-INF/classes/todoapp/TaskServlet.class differ diff --git a/todoapp/target/demo-1/WEB-INF/classes/todoapp/TodoAppDAO$DatabaseOperation.class b/todoapp/target/demo-1/WEB-INF/classes/todoapp/TodoAppDAO$DatabaseOperation.class new file mode 100644 index 0000000..2a94abb Binary files /dev/null and b/todoapp/target/demo-1/WEB-INF/classes/todoapp/TodoAppDAO$DatabaseOperation.class differ diff --git a/todoapp/target/demo-1/WEB-INF/classes/todoapp/TodoAppDAO.class b/todoapp/target/demo-1/WEB-INF/classes/todoapp/TodoAppDAO.class new file mode 100644 index 0000000..d9ef72b Binary files /dev/null and b/todoapp/target/demo-1/WEB-INF/classes/todoapp/TodoAppDAO.class differ diff --git a/todoapp/target/demo-1/WEB-INF/lib/jackson-annotations-2.13.0.jar b/todoapp/target/demo-1/WEB-INF/lib/jackson-annotations-2.13.0.jar new file mode 100644 index 0000000..ad9613d Binary files /dev/null and b/todoapp/target/demo-1/WEB-INF/lib/jackson-annotations-2.13.0.jar differ diff --git a/todoapp/target/demo-1/WEB-INF/lib/jackson-core-2.13.0.jar b/todoapp/target/demo-1/WEB-INF/lib/jackson-core-2.13.0.jar new file mode 100644 index 0000000..fd8c2ed Binary files /dev/null and b/todoapp/target/demo-1/WEB-INF/lib/jackson-core-2.13.0.jar differ diff --git a/todoapp/target/demo-1/WEB-INF/lib/jackson-databind-2.13.0.jar b/todoapp/target/demo-1/WEB-INF/lib/jackson-databind-2.13.0.jar new file mode 100644 index 0000000..d72f47e Binary files /dev/null and b/todoapp/target/demo-1/WEB-INF/lib/jackson-databind-2.13.0.jar differ diff --git a/todoapp/target/demo-1/WEB-INF/lib/jetty-http-10.0.6.jar b/todoapp/target/demo-1/WEB-INF/lib/jetty-http-10.0.6.jar new file mode 100644 index 0000000..529c03a Binary files /dev/null and b/todoapp/target/demo-1/WEB-INF/lib/jetty-http-10.0.6.jar differ diff --git a/todoapp/target/demo-1/WEB-INF/lib/jetty-io-10.0.6.jar b/todoapp/target/demo-1/WEB-INF/lib/jetty-io-10.0.6.jar new file mode 100644 index 0000000..8ec6720 Binary files /dev/null and b/todoapp/target/demo-1/WEB-INF/lib/jetty-io-10.0.6.jar differ diff --git a/todoapp/target/demo-1/WEB-INF/lib/jetty-security-10.0.6.jar b/todoapp/target/demo-1/WEB-INF/lib/jetty-security-10.0.6.jar new file mode 100644 index 0000000..c01b558 Binary files /dev/null and b/todoapp/target/demo-1/WEB-INF/lib/jetty-security-10.0.6.jar differ diff --git a/todoapp/target/demo-1/WEB-INF/lib/jetty-server-10.0.6.jar b/todoapp/target/demo-1/WEB-INF/lib/jetty-server-10.0.6.jar new file mode 100644 index 0000000..40160b2 Binary files /dev/null and b/todoapp/target/demo-1/WEB-INF/lib/jetty-server-10.0.6.jar differ diff --git a/todoapp/target/demo-1/WEB-INF/lib/jetty-servlet-10.0.6.jar b/todoapp/target/demo-1/WEB-INF/lib/jetty-servlet-10.0.6.jar new file mode 100644 index 0000000..bbfa408 Binary files /dev/null and b/todoapp/target/demo-1/WEB-INF/lib/jetty-servlet-10.0.6.jar differ diff --git a/todoapp/target/demo-1/WEB-INF/lib/jetty-servlet-api-4.0.6.jar b/todoapp/target/demo-1/WEB-INF/lib/jetty-servlet-api-4.0.6.jar new file mode 100644 index 0000000..99357ea Binary files /dev/null and b/todoapp/target/demo-1/WEB-INF/lib/jetty-servlet-api-4.0.6.jar differ diff --git a/todoapp/target/demo-1/WEB-INF/lib/jetty-util-10.0.6.jar b/todoapp/target/demo-1/WEB-INF/lib/jetty-util-10.0.6.jar new file mode 100644 index 0000000..32afebb Binary files /dev/null and b/todoapp/target/demo-1/WEB-INF/lib/jetty-util-10.0.6.jar differ diff --git a/todoapp/target/demo-1/WEB-INF/lib/logback-classic-1.2.6.jar b/todoapp/target/demo-1/WEB-INF/lib/logback-classic-1.2.6.jar new file mode 100644 index 0000000..57f30e9 Binary files /dev/null and b/todoapp/target/demo-1/WEB-INF/lib/logback-classic-1.2.6.jar differ diff --git a/todoapp/target/demo-1/WEB-INF/lib/logback-core-1.2.6.jar b/todoapp/target/demo-1/WEB-INF/lib/logback-core-1.2.6.jar new file mode 100644 index 0000000..c1123d2 Binary files /dev/null and b/todoapp/target/demo-1/WEB-INF/lib/logback-core-1.2.6.jar differ diff --git a/todoapp/target/demo-1/WEB-INF/lib/mysql-connector-j-8.0.33.jar b/todoapp/target/demo-1/WEB-INF/lib/mysql-connector-j-8.0.33.jar new file mode 100644 index 0000000..3f741f5 Binary files /dev/null and b/todoapp/target/demo-1/WEB-INF/lib/mysql-connector-j-8.0.33.jar differ diff --git a/todoapp/target/demo-1/WEB-INF/lib/protobuf-java-3.21.9.jar b/todoapp/target/demo-1/WEB-INF/lib/protobuf-java-3.21.9.jar new file mode 100644 index 0000000..c4fd860 Binary files /dev/null and b/todoapp/target/demo-1/WEB-INF/lib/protobuf-java-3.21.9.jar differ diff --git a/todoapp/target/demo-1/WEB-INF/lib/slf4j-api-1.7.32.jar b/todoapp/target/demo-1/WEB-INF/lib/slf4j-api-1.7.32.jar new file mode 100644 index 0000000..b16a078 Binary files /dev/null and b/todoapp/target/demo-1/WEB-INF/lib/slf4j-api-1.7.32.jar differ diff --git a/todoapp/target/demo-1/css/styles.css b/todoapp/target/demo-1/css/styles.css new file mode 100644 index 0000000..dab717f --- /dev/null +++ b/todoapp/target/demo-1/css/styles.css @@ -0,0 +1,114 @@ +body { + font-family: Arial, sans-serif; + background-color: #f5f5f5; + margin: 20px; + padding: 20px; + max-width: 800px; + margin: auto; +} + +h1 { + text-align: center; + color: #333; + margin-bottom: 20px; + text-shadow: 2px 2px 2px rgba(0, 0, 0, 0.1); +} + +#addTaskForm { + display: flex; + justify-content: center; + margin-bottom: 20px; +} + +#taskText { + flex: 1; + padding: 10px; + border: 1px solid #ccc; + border-radius: 5px 0 0 5px; + font-size: 16px; +} + +#addTaskForm button { + padding: 10px 20px; + border: 1px solid #ccc; + border-left: none; + border-radius: 0 5px 5px 0; + background-color: #4CAF50; + color: white; + font-size: 16px; + cursor: pointer; + transition: background-color 0.3s ease; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} + +#addTaskForm button:hover { + background-color: #45a049; +} + +.task-list { + list-style-type: none; + padding: 0; +} + +.task-item { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 10px; + padding: 10px; + background-color: white; + border: 1px solid #ccc; + border-radius: 5px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + transition: background-color 0.3s ease, transform 0.2s ease; +} + +.task-item.done { + background-color: #e0f7fa; + transform: scale(0.98); +} + +.task-number { + font-weight: bold; + color: #666; + margin-right: 10px; +} + +.task-text { + flex: 1; +} + +.task-actions { + display: flex; + gap: 5px; +} + +.task-actions button { + padding: 5px 10px; + border: 1px solid #ccc; + border-radius: 3px; + background-color: #f0f0f0; + color: #333; + font-size: 14px; + cursor: pointer; + transition: background-color 0.3s ease, transform 0.2s ease; +} + +.task-actions button:hover { + background-color: #e0e0e0; + transform: translateY(-2px); +} + +.task-actions button.done { + background-color: #4CAF50; + color: white; + transform: translateY(-2px); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} + +.task-actions button.delete { + background-color: #f44336; + color: white; + transform: translateY(-2px); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} diff --git a/todoapp/target/demo-1/index.html b/todoapp/target/demo-1/index.html new file mode 100644 index 0000000..0134dae --- /dev/null +++ b/todoapp/target/demo-1/index.html @@ -0,0 +1,27 @@ + + + + + + + Todo App + + + + +

    Todo App

    + + +
    + + +
    + + +
      + + + + + + diff --git a/todoapp/target/demo-1/js/script.js b/todoapp/target/demo-1/js/script.js new file mode 100644 index 0000000..74ee2e7 --- /dev/null +++ b/todoapp/target/demo-1/js/script.js @@ -0,0 +1,134 @@ +// fetch tasks from backends (GET) +function fetchTasks() { + fetch('/todoapp/api/tasks') + .then(response => { + if (!response.ok) { + throw new Error('Failed to fetch tasks'); + } + return response.json(); + }) + .then(tasks => { + const taskList = document.getElementById('taskList'); + taskList.innerHTML = ''; // Clear existing list + + tasks.forEach(task => { + const taskItem = createTaskElement(task); + taskList.appendChild(taskItem); + }); + }) + .catch(error => console.error('Error fetching tasks:', error)); +} + +// function adding new task to the list +function createTaskElement(task) { + const taskItem = document.createElement('li'); + taskItem.classList.add('task-item'); + + if (task.status) { + taskItem.classList.add('done'); + } + + // adding number + const taskNumber = document.createElement('span'); + taskNumber.classList.add('task-number'); + taskNumber.textContent = `#${task.number}`; + taskItem.appendChild(taskNumber); + + // adding text + const taskText = document.createElement('span'); + taskText.classList.add('task-text'); + taskText.textContent = task.text; + taskItem.appendChild(taskText); + + // adding buttons + const taskActions = document.createElement('div'); + taskActions.classList.add('task-actions'); + + // button for changing status + const doneButton = document.createElement('button'); + doneButton.textContent = task.isDone ? 'Undo' : 'Done'; + doneButton.addEventListener('click', function() { + updateTaskStatus(task.number, !task.isDone); + }); + taskActions.appendChild(doneButton); + + // button for deleting + const deleteButton = document.createElement('button'); + deleteButton.textContent = 'Delete'; + deleteButton.addEventListener('click', function() { + deleteTask(task.number); + }); + taskActions.appendChild(deleteButton); + + taskItem.appendChild(taskActions); + + return taskItem; +} + +// add new task (POST) +document.getElementById('addTaskForm').addEventListener('submit', function(event) { + event.preventDefault(); + const taskText = document.getElementById('taskText').value.trim(); + if (taskText === '') { + alert('Task description cannot be empty'); + return; + } + + fetch('/todoapp/api/tasks', { + method: 'POST', + headers: { + 'Content-Type': 'text/plain', //request sends a string + }, + body: taskText, + }) + .then(response => { + if (!response.ok) { + throw new Error('Failed to add task'); + } + return response.json(); + }) + .then(result => { + if (result.success) { + document.getElementById('taskText').value = ''; //clear input area + fetchTasks(); // Refresh task list after adding new task + } else { + console.error('Failed to add task'); + } + }) + .catch(error => console.error('Error adding task:', error)); +}); + +// update status (PUT) +function updateTaskStatus(taskNumber, isDone) { + fetch(`/todoapp/api/tasks/${taskNumber}`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', //request sends a json table with task's data + }, + body: JSON.stringify({ isDone: isDone }) + }) + .then(response => { + if (!response.ok) { + throw new Error('Failed to update task status'); + } + fetchTasks(); + }) + .catch(error => console.error('Error updating task status:', error)); +} + +// delete a task (DELETE) +function deleteTask(taskNumber) { + fetch(`/todoapp/api/tasks/${taskNumber}`, { + method: 'DELETE' + }) + .then(response => { + if (!response.ok) { + throw new Error('Failed to delete task'); + } + fetchTasks(); + }) + .catch(error => console.error('Error deleting task:', error)); +} + +// fetch tasks on startup +fetchTasks(); diff --git a/todoapp/target/maven-archiver/pom.properties b/todoapp/target/maven-archiver/pom.properties new file mode 100644 index 0000000..230fdca --- /dev/null +++ b/todoapp/target/maven-archiver/pom.properties @@ -0,0 +1,3 @@ +artifactId=demo +groupId=todoapp +version=1 diff --git a/todoapp/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/todoapp/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 0000000..75ee856 --- /dev/null +++ b/todoapp/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst @@ -0,0 +1,5 @@ +todoapp\JettyServer.class +todoapp\Task.class +todoapp\TodoAppDAO.class +todoapp\TaskServlet.class +todoapp\TodoAppDAO$DatabaseOperation.class diff --git a/todoapp/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/todoapp/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 0000000..ff062f1 --- /dev/null +++ b/todoapp/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1,4 @@ +P:\Studia\paradygmaty_programowania\PROJEKT\todoapp\src\main\java\todoapp\TaskServlet.java +P:\Studia\paradygmaty_programowania\PROJEKT\todoapp\src\main\java\todoapp\TodoAppDAO.java +P:\Studia\paradygmaty_programowania\PROJEKT\todoapp\src\main\java\todoapp\JettyServer.java +P:\Studia\paradygmaty_programowania\PROJEKT\todoapp\src\main\java\todoapp\Task.java diff --git a/todoapp/target/todoapp_MaciejŻyczyński.war b/todoapp/target/todoapp_MaciejŻyczyński.war new file mode 100644 index 0000000..1aaffb4 Binary files /dev/null and b/todoapp/target/todoapp_MaciejŻyczyński.war differ