Skip to content

Commit

Permalink
Added initial user service
Browse files Browse the repository at this point in the history
  • Loading branch information
AydanPirani committed Aug 15, 2023
1 parent 2ca62bd commit 4fbcbff
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 0 deletions.
2 changes: 2 additions & 0 deletions api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import morgan from "morgan";

import Constants from "../src/constants.js";
import authRouter from "../src/services/auth/auth-router.js";
import userRouter from "../src/services/user/user-router.js";
import newsletterRouter from "../src/services/newsletter/newsletter-router.js";

const app: Application = express();
Expand All @@ -22,6 +23,7 @@ if (env == "preview" || env == "production") {

// Add routers for each sub-service
app.use("/auth/", authRouter);
app.use("/user/", userRouter);
app.use("/newsletter/", newsletterRouter);

// Ensure that API is running
Expand Down
21 changes: 21 additions & 0 deletions src/middleware/verify-jwt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Request, Response, NextFunction} from "express";

import Constants from "../constants.js";
import { decodeJwtToken } from "../services/auth/auth-lib.js";

export function verifyJwt(req: Request, res: Response, next: NextFunction): void {
const token: string | undefined = req.headers.authorization;

if (!token) {
res.status(Constants.FORBIDDEN).send({error: "no token passed!"});
next("route");
}

try {
res.locals.payload = decodeJwtToken(token);
next();
} catch (error) {
res.status(Constants.FORBIDDEN).send({error: error as string});
next("route");
}
}
7 changes: 7 additions & 0 deletions src/services/user/user-formats.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export interface UserFormat {
id: string,
username: string,
firstname: string,
lastname: string,
email: string,
}
39 changes: 39 additions & 0 deletions src/services/user/user-lib.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Collection, UpdateFilter } from "mongodb";
import { UserSchema } from "./user-schemas.js";
import DatabaseHelper from "../../database.js";
import { UserFormat } from "./user-formats.js";

export async function getUser(userId: string): Promise<UserSchema> {
const collection: Collection = await DatabaseHelper.getCollection("user", "info");
console.log("|%s|", userId);
try {
const user: UserSchema | null = await collection.findOne({ id: userId }) as UserSchema | null;
if (user) {
return user;
}

return Promise.reject("no such user found!");
} catch (error) {
return Promise.reject(error);
}
}


export async function updateUser(userData: UserFormat): Promise<void> {
const collection: Collection = await DatabaseHelper.getCollection("user", "info");

try {
const updateFilter: UpdateFilter<UserSchema> = {
$set: {
id: userData.id,
email: userData.email,
firstname: userData.firstname,
lastname: userData.lastname,
}};
await collection.updateOne({id: userData.id}, updateFilter, {upsert: true});
} catch (error) {
return Promise.reject(error as string);
}

return Promise.resolve();
}
74 changes: 74 additions & 0 deletions src/services/user/user-router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { Router, Request, Response } from "express";

import Constants from "../../constants.js";
import { JwtPayload } from "../auth/auth-models.js";
import { hasElevatedPerms } from "../auth/auth-lib.js";
import { UserSchema } from "./user-schemas.js";
import { getUser, updateUser } from "./user-lib.js";
import { verifyJwt } from "../../middleware/verify-jwt.js";
import { UserFormat } from "./user-formats.js";


const userRouter: Router = Router();
userRouter.use(verifyJwt);


userRouter.get("/:USERID", async (req: Request, res: Response) => {
const targetUser: string | undefined = req.params.USERID;

// If no target user, exact same as next route
if (!targetUser) {
res.redirect("/");
return;
}

// Get payload, and check if authorized
const payload: JwtPayload = res.locals.payload as JwtPayload;
if (payload.id == targetUser || hasElevatedPerms(payload)) {
// Authorized -> return the user object
await getUser(targetUser).then((user: UserSchema) => {
res.status(Constants.SUCCESS).send(user);
}).catch((error: string) => {
res.status(Constants.INTERNAL_ERROR).send(error);
});

} else {
res.status(Constants.FORBIDDEN).send({error: "no valid auth provided!"});
}
});


userRouter.get("/", async (_: Request, res: Response) => {
// Get payload, return user's values
const payload: JwtPayload = res.locals.payload as JwtPayload;
const user: UserSchema = await getUser(payload.id);
res.status(Constants.SUCCESS).send(user);
});


userRouter.post("/", async (req: Request, res: Response) => {
const token: JwtPayload = res.locals.payload as JwtPayload;

if (!hasElevatedPerms(token)) {
res.status(Constants.FORBIDDEN).send({error: "token not authorized to perform this!"});
}

// Get userData from the request, and print to output
const userData: UserFormat = req.body as UserFormat;

if (!userData.id|| !userData.email || !userData.firstname || !userData.lastname || !userData.username) {
res.status(Constants.BAD_REQUEST).send({error: "bad request!"});
return;
}

await updateUser(userData);

// Return new value of the user
await getUser(userData.id).then((user: UserSchema) => {
res.status(Constants.SUCCESS).send(user);
}).catch((error: string) => {
res.status(Constants.INTERNAL_ERROR).send(error);
});
});

export default userRouter;
10 changes: 10 additions & 0 deletions src/services/user/user-schemas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Document, ObjectId, WithId } from "mongodb";

// User object document schema
export interface UserSchema extends WithId<Document> {
_id: ObjectId,
id: string,
firstName: string,
lastName: string,
email: string
}

0 comments on commit 4fbcbff

Please sign in to comment.