From dd837616af9e7a6a080af6b176e387bbc17b103f Mon Sep 17 00:00:00 2001
From: Michael Fatemi <myfatemi04@gmail.com>
Date: Sat, 10 Apr 2021 21:41:24 -0400
Subject: [PATCH] backend revamp: users

---
 src/{api.ts => api/index.ts} | 356 ++++++++++++++++-------------------
 src/api/user.ts              |  43 +++++
 src/index.ts                 |   2 +-
 src/requireApiAuth.ts        |  12 ++
 4 files changed, 217 insertions(+), 196 deletions(-)
 rename src/{api.ts => api/index.ts} (75%)
 create mode 100644 src/api/user.ts
 create mode 100644 src/requireApiAuth.ts

diff --git a/src/api.ts b/src/api/index.ts
similarity index 75%
rename from src/api.ts
rename to src/api/index.ts
index d36dc1f..7b0bad1 100644
--- a/src/api.ts
+++ b/src/api/index.ts
@@ -1,195 +1,161 @@
-import { Router } from 'express';
-import { createSessionFromCodeAndProvider } from './auth';
-import {
-	getGroupByID,
-	getPoolByID,
-	getPoolsWithUser,
-	getUserByID,
-} from './data';
-import { GroupModel, PoolModel } from './models';
-
-export const router = Router();
-
-router.get('/user', async (req, res) => {
-	if (typeof req.query.userID != 'string') {
-		return;
-	}
-
-	let userID = req.query.userID;
-	if (userID === '@me') {
-		userID = req.session.accountID;
-	}
-
-	let user = await getUserByID(userID);
-
-	if (user) {
-		res.json({ status: 'success', data: user });
-	} else {
-		res.json({ status: 'error', error: 'not_found' });
-	}
-});
-
-router.patch('/user', (req, res) => {
-	// if (!(req.body.userID in users)) {
-	// 	res.json({ status: 'error', error: 'user not found' });
-	// } else {
-	// 	let user = users[req.body.userID];
-	// 	user.username = req.body.username;
-	// 	user.first_name = req.body.first_name;
-	// 	user.last_name = req.body.last_name;
-	// 	res.json({ status: 'success' });
-	// }
-});
-
-router.delete('/user', (req, res) => {});
-
-router.get('/pool', async (req, res) => {
-	if (typeof req.query.poolID != 'string') {
-		return;
-	}
-
-	let poolID = req.query.poolID;
-	let pool = await getPoolByID(poolID);
-
-	if (pool) {
-		res.json({ status: 'success', data: pool });
-	} else {
-		res.json({ status: 'error', error: 'not_found' });
-	}
-});
-
-router.post('/pool', (req, res) => {
-	if (req.session.accountID == null) {
-		res.status(401);
-		return res.json({ status: 'error', error: 'need_login' });
-	}
-
-	const userID = req.session.accountID;
-	const {
-		capacity,
-		description,
-		direction,
-		end_time,
-		group_id,
-		start_time,
-		title,
-		type,
-	} = req.body;
-
-	const pool = new PoolModel();
-	Object.assign(pool, {
-		author_id: userID,
-		capacity,
-		description,
-		direction,
-		status: 'pending',
-		title,
-		type,
-		participant_ids: [],
-		comments: [],
-		create_time: new Date().toISOString(),
-		update_time: new Date().toISOString(),
-		group_id,
-	});
-
-	pool
-		.save()
-		.then((pool) => {
-			res.json({ status: 'success', id: pool._id });
-		})
-		.catch((err) => {
-			console.error('Error when creating a pool:', err);
-			res.json({ status: 'error' });
-		});
-});
-
-router.get('/group', async (req, res) => {
-	if (typeof req.query.groupID != 'string') {
-		return res.json({ status: 'error' });
-	}
-
-	let groupID = req.query.groupID;
-	let group = await getGroupByID(groupID);
-
-	if (group) {
-		res.json({ status: 'success', data: group });
-	} else {
-		res.json({ status: 'error', error: 'not_found' });
-	}
-});
-
-router.get('/group_pools', async (req, res) => {
-	if (typeof req.query.groupID != 'string') {
-		res.json({ status: 'error', error: 'need_group_id' });
-		return;
-	}
-
-	let groupID = req.query.groupID;
-	let pools = await PoolModel.find({ group_id: groupID }).exec();
-
-	res.json({ status: 'success', data: pools });
-});
-
-router.post('/join_pool', async (req, res) => {
-	if (!req.session.accountID) {
-		return res.json({ status: 'error', error: 'need_login' });
-	} else {
-		let poolID = req.body.id;
-		let userID = req.session.accountID;
-
-		await PoolModel.findByIdAndUpdate(poolID, {
-			$addToSet: { participant_ids: userID },
-		}).exec();
-
-		res.json({ status: 'success' });
-	}
-});
-
-router.post('/group', (req, res) => {
-	if (req.session.accountID == null) {
-		res.status(401);
-		return res.json({ status: 'error', error: 'need_login' });
-	}
-
-	const userID = req.session.accountID;
-	const name = req.body.name;
-
-	const group = new GroupModel();
-	group.set('name', name);
-	group.set('creator_id', userID);
-	group
-		.save()
-		.then((group) => {
-			res.json({ status: 'success', id: group._id });
-		})
-		.catch((err) => {
-			console.error('Error when creating a group:', err);
-			res.json({ status: 'error' });
-		});
-});
-
-router.get('/my_pools', async (req, res) => {
-	if (req.session.accountID == null) {
-		res.status(401);
-		return res.json({ status: 'error', error: 'need_login' });
-	}
-	let pools = await getPoolsWithUser(req.session.accountID);
-	if (pools) {
-		res.json({ status: 'success', data: pools });
-	} else {
-		res.json({ status: 'error', error: 'not_found' });
-	}
-});
-
-router.post('/create_session', (req, res) => {
-	const { code, provider } = req.body;
-	console.log('Creating session: code =', code, 'provider =', provider);
-	createSessionFromCodeAndProvider(code, provider)
-		.then((token) => {
-			res.json({ status: 'success', token });
-		})
-		.catch((error) => {
-			console.error('Error when creating session:', error);
-			res.json({ status: 'error' });
-		});
-});
+import { Router } from 'express';
+import { createSessionFromCodeAndProvider } from '../auth';
+import { getGroupByID, getPoolByID, getPoolsWithUser } from '../data';
+import { GroupModel, PoolModel } from '../models';
+
+import * as user from './user';
+
+export const router = Router();
+
+router.use('/user', user.router);
+
+router.get('/pool', async (req, res) => {
+	if (typeof req.query.poolID != 'string') {
+		return;
+	}
+
+	let poolID = req.query.poolID;
+	let pool = await getPoolByID(poolID);
+
+	if (pool) {
+		res.json({ status: 'success', data: pool });
+	} else {
+		res.json({ status: 'error', error: 'not_found' });
+	}
+});
+
+router.post('/pool', (req, res) => {
+	if (req.session.accountID == null) {
+		res.status(401);
+		return res.json({ status: 'error', error: 'need_login' });
+	}
+
+	const userID = req.session.accountID;
+	const {
+		capacity,
+		description,
+		direction,
+		end_time,
+		group_id,
+		start_time,
+		title,
+		type,
+	} = req.body;
+
+	const pool = new PoolModel();
+	Object.assign(pool, {
+		author_id: userID,
+		capacity,
+		description,
+		direction,
+		status: 'pending',
+		title,
+		type,
+		participant_ids: [],
+		comments: [],
+		create_time: new Date().toISOString(),
+		update_time: new Date().toISOString(),
+		group_id,
+	});
+
+	pool
+		.save()
+		.then((pool) => {
+			res.json({ status: 'success', id: pool._id });
+		})
+		.catch((err) => {
+			console.error('Error when creating a pool:', err);
+			res.json({ status: 'error' });
+		});
+});
+
+router.get('/group', async (req, res) => {
+	if (typeof req.query.groupID != 'string') {
+		return res.json({ status: 'error' });
+	}
+
+	let groupID = req.query.groupID;
+	let group = await getGroupByID(groupID);
+
+	if (group) {
+		res.json({ status: 'success', data: group });
+	} else {
+		res.json({ status: 'error', error: 'not_found' });
+	}
+});
+
+router.get('/group_pools', async (req, res) => {
+	if (typeof req.query.groupID != 'string') {
+		res.json({ status: 'error', error: 'need_group_id' });
+		return;
+	}
+
+	let groupID = req.query.groupID;
+	let pools = await PoolModel.find({ group_id: groupID }).exec();
+
+	res.json({ status: 'success', data: pools });
+});
+
+router.post('/join_pool', async (req, res) => {
+	if (!req.session.accountID) {
+		return res.json({ status: 'error', error: 'need_login' });
+	} else {
+		let poolID = req.body.id;
+		let userID = req.session.accountID;
+
+		await PoolModel.findByIdAndUpdate(poolID, {
+			$addToSet: { participant_ids: userID },
+		}).exec();
+
+		res.json({ status: 'success' });
+	}
+});
+
+router.post('/group', (req, res) => {
+	if (req.session.accountID == null) {
+		res.status(401);
+		return res.json({ status: 'error', error: 'need_login' });
+	}
+
+	const userID = req.session.accountID;
+	const name = req.body.name;
+
+	const group = new GroupModel();
+	group.set('name', name);
+	group.set('creator_id', userID);
+	group
+		.save()
+		.then((group) => {
+			res.json({ status: 'success', id: group._id });
+		})
+		.catch((err) => {
+			console.error('Error when creating a group:', err);
+			res.json({ status: 'error' });
+		});
+});
+
+router.get('/my_pools', async (req, res) => {
+	if (req.session.accountID == null) {
+		res.status(401);
+		return res.json({ status: 'error', error: 'need_login' });
+	}
+	let pools = await getPoolsWithUser(req.session.accountID);
+	if (pools) {
+		res.json({ status: 'success', data: pools });
+	} else {
+		res.json({ status: 'error', error: 'not_found' });
+	}
+});
+
+router.post('/create_session', (req, res) => {
+	const { code, provider } = req.body;
+	console.log('Creating session: code =', code, 'provider =', provider);
+	createSessionFromCodeAndProvider(code, provider)
+		.then((token) => {
+			res.json({ status: 'success', token });
+		})
+		.catch((error) => {
+			console.error('Error when creating session:', error);
+			res.json({ status: 'error' });
+		});
+});
diff --git a/src/api/user.ts b/src/api/user.ts
new file mode 100644
index 0000000..1289572
--- /dev/null
+++ b/src/api/user.ts
@@ -0,0 +1,43 @@
+import { Router } from 'express';
+import { GroupModel, PoolModel, UserModel } from '../models';
+import requireApiAuth from '../requireApiAuth';
+import { ObjectID } from 'mongodb';
+
+export const router = Router();
+
+router.use(requireApiAuth);
+
+router.get('/@me/groups', async (req, res) => {
+	let userID = req.session.accountID;
+	let groups = await GroupModel.find({
+		member_ids: { $all: [userID] },
+	});
+
+	res.json({ status: 'success', data: groups });
+});
+
+router.get('/@me/pools', async (req, res) => {
+	let userID = req.session.accountID;
+	let pools = await PoolModel.find({
+		participant_ids: { $all: [userID] },
+	}).exec();
+
+	res.json({ status: 'success', data: pools });
+});
+
+router.get('/@me', async (req, res) => {
+	let user = await UserModel.findById(
+		new ObjectID(req.session.accountID)
+	).exec();
+
+	res.json({ status: 'success', data: user });
+});
+
+router.get('/:userID', async (req, res) => {
+	let userID = req.params.userID;
+	let user = await UserModel.findById(new ObjectID(userID)).exec();
+	let data = user.toJSON();
+	delete data['email'];
+
+	res.json({ status: 'success', data });
+});
diff --git a/src/index.ts b/src/index.ts
index 9a680ed..7c9c57b 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -16,7 +16,7 @@ else console.log('DB connected successfully');
 import bodyParser from 'body-parser';
 import cors from 'cors';
 import express from 'express';
-import * as api from './api';
+import * as api from './api/index';
 import { sessionMiddleware } from './sessionMiddleware';
 
 const app = express();
diff --git a/src/requireApiAuth.ts b/src/requireApiAuth.ts
new file mode 100644
index 0000000..d621cfa
--- /dev/null
+++ b/src/requireApiAuth.ts
@@ -0,0 +1,12 @@
+import { RequestHandler } from 'express';
+
+const requireApiAuth: RequestHandler = (req, res, next) => {
+	if (req.session?.accountID == null) {
+		res.status(401);
+		res.json({ error: 'unauthorized' });
+	} else {
+		next();
+	}
+};
+
+export default requireApiAuth;