diff --git a/.prettierrc b/.prettierrc
index c4724f0668f34772c36233b68dd64137116288af..565b1aae1a0b6a67072c56920b3b887f54fc38fe 100644
--- a/.prettierrc
+++ b/.prettierrc
@@ -4,6 +4,6 @@
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
- "printWidth": 100,
+ "printWidth": 80,
"arrowParens": "always"
}
\ No newline at end of file
diff --git a/server/controllers/todos.js b/server/controllers/todos.js
new file mode 100644
index 0000000000000000000000000000000000000000..abffd99e4a6b376ebd01887919b190f4e7f50aaa
--- /dev/null
+++ b/server/controllers/todos.js
@@ -0,0 +1,149 @@
+/* eslint-disable import/extensions */
+import Todo from '../models/Todo.js';
+import User from '../models/User.js';
+import serverResponse from '../services/response.js';
+
+export async function createTodo(req, res) {
+ try {
+ const { task } = req.body;
+ const user = await User.findById(req.userId);
+
+ const newTodo = new Todo({
+ username: user.username,
+ author: req.userId,
+ task,
+ status: 'OPEN',
+ });
+
+ await newTodo.save();
+ await User.findByIdAndUpdate(req.userId, {
+ $push: { todos: newTodo },
+ });
+
+ return res.status(serverResponse.status.httpSuccess).json({
+ newTodo,
+ success: true,
+ message: serverResponse.message.todos.isCreated,
+ });
+ } catch (error) {
+ return res.status(serverResponse.status.httpBadRequest).json({
+ success: false,
+ error: error.message,
+ message: serverResponse.message.todos.fail,
+ });
+ }
+}
+
+export async function getAll(req, res) {
+ try {
+ const todos = await Todo.find().sort('-createdAt');
+
+ if (!todos) {
+ return res.status(serverResponse.status.httpNoContent).json({
+ success: false,
+ message: serverResponse.message.todos.noContent,
+ });
+ }
+
+ return res.status(serverResponse.status.httpSuccess).json({
+ todos,
+ success: true,
+ message: serverResponse.message.todos.returned,
+ });
+ } catch (error) {
+ return res.status(serverResponse.status.httpBadRequest).json({
+ success: false,
+ error: error.message,
+ message: serverResponse.message.todos.getFail,
+ });
+ }
+}
+
+export async function getMyTodos(req, res) {
+ try {
+ const user = await User.findById(req.userId);
+ const page = req.query.page || 1;
+ const limit = req.query.limit || 7;
+ const startIndex = (page - 1) * limit;
+ const endIndex = page * limit;
+
+ const list = await Promise.all(
+ /* eslint-disable no-underscore-dangle */
+ user.todos
+ .slice(startIndex, endIndex)
+ .map((todo) => Todo.findById(todo._id))
+ /* eslint-disable no-underscore-dangle */
+ );
+
+ return res.status(serverResponse.status.httpSuccess).json({
+ list,
+ success: true,
+ message: serverResponse.message.todos.returned,
+ });
+ } catch (error) {
+ return res.status(serverResponse.status.httpBadRequest).json({
+ success: false,
+ error: error.message,
+ message: serverResponse.message.todos.getFail,
+ });
+ }
+}
+
+export async function getAndUpdateStatusByID(req, res) {
+ try {
+ const todo = await Todo.findOneAndUpdate(
+ { _id: req.params.id },
+ {
+ $set: { status: 'DONE' },
+ },
+ { new: true }
+ );
+
+ if (!todo) {
+ return res.status(serverResponse.status.httpNotFound).json({
+ success: false,
+ message: serverResponse.message.todos.getFail,
+ });
+ }
+
+ return res.status(serverResponse.status.httpSuccess).json({
+ todo,
+ success: true,
+ message: serverResponse.message.todos.returned,
+ });
+ } catch (error) {
+ return res.status(serverResponse.status.httpNotFound).json({
+ success: false,
+ error: error.message,
+ message: serverResponse.message.todos.getFail,
+ });
+ }
+}
+
+export async function removeByID(req, res) {
+ try {
+ const todo = await Todo.findByIdAndDelete(req.params.id);
+
+ if (!todo) {
+ return res.status(serverResponse.status.httpNotFound).json({
+ success: false,
+ message: serverResponse.message.todos.getFail,
+ });
+ }
+
+ await User.findByIdAndUpdate(req.userId, {
+ $pull: { todos: req.params.id },
+ });
+
+ return res.status(serverResponse.status.httpSuccess).json({
+ success: true,
+ message: serverResponse.message.todos.deleted,
+ });
+ } catch (error) {
+ return res.status(serverResponse.status.httpBadRequest).json({
+ success: false,
+ error: error.message,
+ message: serverResponse.message.todos.getFail,
+ });
+ }
+}
diff --git a/server/index.js b/server/index.js
index 6d43c64fd45b80f16a943b75d191f04775af8eba..92291eeaa9eb2556c3387a7b1fd713abb939997a 100644
--- a/server/index.js
+++ b/server/index.js
@@ -4,6 +4,7 @@ import mongoose from 'mongoose';
import dotenv from 'dotenv';
import cors from 'cors';
import authRoute from './routes/auth.js';
+import todoRoute from './routes/todos.js';
const app = express();
dotenv.config();
@@ -18,6 +19,7 @@ app.use(express.json());
// * Routes
app.use('/api/auth', authRoute);
+app.use('/api/todos', todoRoute);
async function start() {
try {
@@ -28,8 +30,10 @@ async function start() {
app.listen(PORT, () => {
console.log(`Server started on port: ${PORT}`);
});
+
+ return null;
} catch (error) {
- console.log(error);
+ return error;
}
}
diff --git a/server/models/Todo.js b/server/models/Todo.js
new file mode 100644
index 0000000000000000000000000000000000000000..b96221a44d199905fd7b6ec96d44b779943b762f
--- /dev/null
+++ b/server/models/Todo.js
@@ -0,0 +1,13 @@
+import mongoose from 'mongoose';
+
+const TodoSchema = new mongoose.Schema(
+ {
+ username: { type: String },
+ author: { type: mongoose.Schema.Types.ObjectID, ref: 'User' },
+ task: { type: String, required: true, default: '' },
+ status: { type: String, required: true, default: 'OPEN' },
+ },
+ { timestamps: true }
+);
+
+export default mongoose.model('Todo', TodoSchema);
diff --git a/server/routes/todos.js b/server/routes/todos.js
new file mode 100644
index 0000000000000000000000000000000000000000..8bc1855ea9867fc6cefd9a19f495606b63959a9e
--- /dev/null
+++ b/server/routes/todos.js
@@ -0,0 +1,29 @@
+/* eslint-disable import/extensions */
+import { Router } from 'express';
+import checkAuth from '../utils/checkAuth.js';
+import {
+ createTodo,
+ getAll,
+ getAndUpdateStatusByID,
+ getMyTodos,
+ removeByID,
+} from '../controllers/todos.js';
+
+const router = new Router();
+
+// * CREATE TODO
+router.post('/', checkAuth, createTodo);
+
+// * GET ALL TODOS
+router.get('/', getAll);
+
+// * GET AND UPDATE TODO STATUS BY ID
+router.get('/:id', getAndUpdateStatusByID);
+
+// * GET MY TODOS
+router.get('/user/me', checkAuth, getMyTodos);
+
+// * REMOVE TODO
+router.delete('/:id', removeByID);
+
+export default router;
diff --git a/server/services/response.js b/server/services/response.js
index 22bef32be7ce86b6b5ca6b5ed3124cb3906c63e8..3e7fcbd863df10d30ef4e26008423b050200ed80 100644
--- a/server/services/response.js
+++ b/server/services/response.js
@@ -1,10 +1,12 @@
const responseStatus = {
httpSuccess: 200,
+ httpNoContent: 204,
httpBadRequest: 400,
httpUnauthorized: 401,
httpNoAccess: 403,
httpNotFound: 404,
httpConflict: 409,
+ httpServerError: 500,
};
const responseMessage = {
@@ -35,6 +37,20 @@ const responseMessage = {
notFound: 'Failed to find such user',
isFound: 'User is successfully found',
},
+
+ todos: {
+ isCreated: 'Todo is created',
+ fail: 'Failed to create Todo',
+ noContent: 'Currently there are no Todos in database',
+ returned: 'All Todos are successfully returned',
+ getFail: 'Failed to find appropriate Todos',
+ deleted: 'Todo is successfully removed',
+ },
+
+ server: {
+ internalError:
+ 'Sorry, we encountered an unexpected error. Please try again later.',
+ },
};
const serverResponse = {