Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@
"deta": "^1.1.0",
"dotenv": "^16.0.3",
"express": "^4.18.1",
"jsonwebtoken": "^9.0.2",
"nodemailer": "^6.9.7",
"outlook-nodemailer-transport": "^1.4.1"
},
"devDependencies": {
"@types/cors": "^2.8.13",
"@types/express": "^4.17.13",
"@types/jsonwebtoken": "^9.0.5",
"@types/node": "14",
"@types/nodemailer": "^6.4.14",
"@typescript-eslint/eslint-plugin": "^5.47.0",
Expand Down
32 changes: 29 additions & 3 deletions server/src/interfaces/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,39 @@ export interface IJWTData {

export interface ITask {
title: string;
definition: string;
description: string;
dueDate: string;
owner: string;
board: string;
}
}

export interface IBoard {
owner: string;
title: string;
tasks: ITask[];
public: boolean;
password?: string;
}

export interface IAddPublicBoard {
title: string;
owner: string;
}

export interface IGetPublicBoards {
username: string;
passwords: IPasswordBoard[];
}
export interface IPasswordBoard {
title: string;
password: string;
}

export interface ITaskUpdate {
title: string;
description: string;
dueDate: Date;
owner: string;
newTitle?: string;
newDescription?: string;
newDueDate?: string;
}
108 changes: 104 additions & 4 deletions server/src/routes/board.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,34 @@ import express from "express";
import * as dotenv from "dotenv";
import path from "path";
import { Deta } from "deta";
import { ITask, IBoard } from "../interfaces/interfaces";
import argon2 from "argon2";
import { ITask, IBoard, IAddPublicBoard, IGetPublicBoards } from "../interfaces/interfaces";
dotenv.config({ path: path.resolve(__dirname, "../.env") });

// deta setup
const projectKey: string = process.env.DETA_PROJECT_KEY;
const deta = Deta(projectKey);
const boardSets = deta.Base("board");
const publicBoards = deta.Base("publicBoards");

const router = express.Router();

router.post("/create", async (req, res) => {
try {
let passwordHash = "";
const boardDataSet: IBoard = req.body as IBoard;
if (typeof boardDataSet.title !== "string" || typeof boardDataSet.owner !== "string") {
throw new Error("Invalid 'title' or 'owner' in the request.");
}

if (boardDataSet.public) {
passwordHash = await argon2.hash(boardDataSet.password);
}

const key = boardDataSet.title.trim() + boardDataSet.owner.trim();

if (await boardSets.get(boardDataSet.title)) {
throw new Error("This board name exists already. Please try to edit this!");
} else if (await boardSets.get(key)) {
throw new Error("This task name exists already. Please try to edit this!");
}

const tasks: ITask[] = [];
Expand All @@ -33,7 +38,9 @@ router.post("/create", async (req, res) => {
key: key,
title: boardDataSet.title,
owner: boardDataSet.owner,
tasks: tasks
tasks: tasks,
public: boardDataSet.public,
password: passwordHash
};

const newtaskDataSet = await boardSets.insert(JSON.parse(JSON.stringify(boardDataSetJSON)));
Expand All @@ -47,4 +54,97 @@ router.post("/create", async (req, res) => {
}
});

router.post("/addPublicBoard", async (req, res) => {
try {
const addPublicBoardData: IAddPublicBoard = req.body as IAddPublicBoard;

if (!(await boardSets.get(addPublicBoardData.title))) {
throw new Error("This board does not exist");
}

if ((await publicBoards.get(addPublicBoardData.owner + addPublicBoardData.title)) !== null) {
throw new Error("You already added this board to your public boards.");
}

const addPublicBoardDataJSON = {
key: addPublicBoardData.owner + addPublicBoardData.title,
owner: addPublicBoardData.owner,
title: addPublicBoardData.title
};

await publicBoards.insert(JSON.parse(JSON.stringify(addPublicBoardDataJSON)));

res.status(201).json({
title: addPublicBoardData.title,
owner: addPublicBoardData.owner,
success: true
});
} catch (err) {
res.status(503).json({ error: err.message });
}
});

router.get("/getAll", async (req, res) => {
try {
const parameters: IGetPublicBoards = req.body as IGetPublicBoards;
const username = parameters.username;
const fetchedBoards = await boardSets.fetch({ owner: username });
const fetchedPublicBoards: any = await publicBoards.fetch({ owner: username });

for (let fetchedPublicBoard of fetchedPublicBoards.items) {
if (parameters.passwords != null) {
for (let password of parameters.passwords) {
const board = await boardSets.get(
fetchedPublicBoard.key.replace(fetchedPublicBoard.owner, "")
);
if (password.title === board.key) {
if (await argon2.verify(board.password as string, password.password)) {
delete board.password;
fetchedBoards.items.push(board);
}
}
}
}
}
for (let i = 0; i < fetchedBoards.count; i++) {
if (fetchedBoards.items[i].public) {
delete fetchedBoards.items[i].password;
}
}
if (fetchedBoards == null || publicBoards == null) {
res.status(409).json({
error: "No boards yet."
});
return false;
} else {
res.status(201).json({ fetchedBoards });
}
} catch (err) {
res.status(503).json({ error: err.message });
}
});

router.get("/get/:board/:password", async (req, res) => {
try {
const board = req.params.board;
const password = req.params.password;
const fetchedBoard = await boardSets.get(board);

if ( fetchedBoard == null) {
throw new Error("This board does not exist.");
}
if (fetchedBoard.public) {
console.log(fetchedBoard.password);
if (await argon2.verify(fetchedBoard.password as string, password)) {
delete fetchedBoard.password;
res.status(201).json({ fetchedBoard });
} else {
throw new Error("Wrong credentials.");
}
}
} catch (err) {
res.status(503).json({ error: err.message });
}
});

export default router;
Loading