Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DNM 75 mongo transactions nesbitt #85

Closed
wants to merge 8 commits into from
Closed
2 changes: 2 additions & 0 deletions src/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { IPFSContent, Token } from "@gatsby-tv/types";
import { ClientSession } from "mongoose";

declare global {
declare namespace NodeJS {
Expand All @@ -12,6 +13,7 @@ declare global {
interface Request {
decodedToken?: Token;
ipfsContent?: IPFSContent;
session?: ClientSession;
}
}
}
6 changes: 6 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ app.use(
return;
}

if (req.session) {
// TODO: Abort transaction is async
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rule of thumb I've been using with westegg now since we have multiple people working on it is to not add any more todos but instead just open a ticket for it. If the line is specific and you want to make sure you remember the context then link it in the issue you make.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR is still in progress. I left that in there so I would remember to discuss it during our work session today

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Next time I'll prefix it with Draft: or something so it doesn't accidentally get merged

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use DNM for (Do no merge) in the PR title. That way it can be for drafts or if something is wrong.

req.session.abortTransaction();
req.session.endSession();
}

// Check if error is specific with response code
if (error instanceof WestEggError) {
return res.status(error.statusCode).json({ error } as ErrorResponse);
Expand Down
16 changes: 16 additions & 0 deletions src/middleware/transaction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { NextFunction, Request, Response } from "express";
import mongoose from "mongoose";

export const useTransaction = async (
req: Request,
res: Response,
next: NextFunction
) => {
const session = await mongoose.startSession();

req.session = session;
session.startTransaction();
next();
await session.commitTransaction();
session.endSession();
};
44 changes: 25 additions & 19 deletions src/routes/auth.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
import { Router } from "express";
import { createHmac } from "crypto";
import jwt from "jsonwebtoken";
import { keys as keysOf } from "ts-transformer-keys";
import {
ErrorMessage,
GetAuthSignInKeyRequest,
Expand All @@ -13,7 +9,6 @@ import {
PostAuthSignInResponse,
StatusCode
} from "@gatsby-tv/types";

import { InvalidToken } from "@src/entities/InvalidToken";
import { PersistSignInKey } from "@src/entities/PersistSignInKey";
import { SignInKey } from "@src/entities/SignInKey";
Expand All @@ -22,7 +17,12 @@ import logger from "@src/logger";
import mail from "@src/mail";
import { isValidBody } from "@src/middleware";
import { isAuthenticated, validateSignin } from "@src/middleware/auth";
import { useTransaction } from "@src/middleware/transaction";
import { randomString } from "@src/utilities";
import { createHmac } from "crypto";
import { Router } from "express";
import jwt from "jsonwebtoken";
import { keys as keysOf } from "ts-transformer-keys";

const router = Router();

Expand All @@ -32,6 +32,7 @@ const router = Router();
router.post(
"/signin",
validateSignin,
useTransaction,
(req, res, next) => {
isValidBody(keysOf<PostAuthSignInRequest>(), req, res, next);
},
Expand Down Expand Up @@ -115,7 +116,7 @@ router.get("/signin/:key", async (req, res, next) => {
/**
* POST /auth/signin/:key/persist
*/
router.post("/signin/:key/persist", async (req, res, next) => {
router.post("/signin/:key/persist", useTransaction, async (req, res, next) => {
try {
const params = req.params as PostAuthPersistSignInKeyRequestParams;

Expand Down Expand Up @@ -158,20 +159,25 @@ router.get("/token/refresh", isAuthenticated, async (req, res, next) => {
/**
* POST /auth/token/invalidate
*/
router.post("/token/invalidate", isAuthenticated, async (req, res, next) => {
try {
const invalid = new InvalidToken({
expire: Date.now()
});
await InvalidToken.findByIdAndUpdate(req.decodedToken!._id, invalid, {
upsert: true,
setDefaultsOnInsert: true
});
router.post(
"/token/invalidate",
isAuthenticated,
useTransaction,
async (req, res, next) => {
try {
const invalid = new InvalidToken({
expire: Date.now()
});
await InvalidToken.findByIdAndUpdate(req.decodedToken!._id, invalid, {
upsert: true,
setDefaultsOnInsert: true
});

res.sendStatus(StatusCode.CREATED);
} catch (error) {
next(error);
res.sendStatus(StatusCode.CREATED);
} catch (error) {
next(error);
}
}
});
);

export default router;
6 changes: 6 additions & 0 deletions src/routes/channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import {
} from "@src/middleware/channel";
import { upload } from "@src/middleware/multipart";
import { isMongoDuplicateKeyError, projection } from "@src/utilities";
import { useTransaction } from "@src/middleware/transaction";

const router = Router();

Expand Down Expand Up @@ -86,6 +87,7 @@ router.get(
router.post(
"/",
isAuthenticated,
useTransaction,
(req, res, next) => {
isValidBody(keysOf<PostChannelRequest>(), req, res, next);
},
Expand Down Expand Up @@ -198,6 +200,7 @@ router.put(
isAuthenticated,
hasPermissionToPutChannelRequest,
validatePutChannelHandleRequest,
useTransaction,
(req, res, next) => {
isValidBody(keysOf<PutChannelHandleRequest>(), req, res, next);
},
Expand Down Expand Up @@ -239,6 +242,7 @@ router.put(
"/:id/avatar",
isAuthenticated,
hasPermissionToPutChannelRequest,
useTransaction,
(req, res, next) => {
upload(req, res, next, 2);
},
Expand Down Expand Up @@ -273,6 +277,7 @@ router.put(
"/:id/banner",
isAuthenticated,
hasPermissionToPutChannelRequest,
useTransaction,
(req, res, next) => {
upload(req, res, next, 2);
},
Expand Down Expand Up @@ -307,6 +312,7 @@ router.put(
"/:id/poster",
isAuthenticated,
hasPermissionToPutChannelRequest,
useTransaction,
(req, res, next) => {
upload(req, res, next, 2);
},
Expand Down
6 changes: 6 additions & 0 deletions src/routes/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
validatePutUserRequest
} from "@src/middleware/user";
import { isMongoDuplicateKeyError, projection } from "@src/utilities";
import { useTransaction } from "@src/middleware/transaction";

const router = Router();

Expand Down Expand Up @@ -85,6 +86,7 @@ router.post(
(req, res, next) => {
isValidBody(keysOf<PostUserCompleteSignupRequest>(), req, res, next);
},
useTransaction,
async (req, res, next) => {
try {
const body = req.body as PostUserCompleteSignupRequest;
Expand Down Expand Up @@ -196,6 +198,7 @@ router.put(
isValidBody(keysOf<PutUserRequest>(), req, res, next);
},
hasPermissionToPutUserRequest,
useTransaction,
async (req, res, next) => {
try {
const body = req.body as PutUserRequest;
Expand Down Expand Up @@ -230,6 +233,7 @@ router.put(
isAuthenticated,
hasPermissionToPutUserRequest,
validatePutUserRequest,
useTransaction,
(req, res, next) => {
upload(req, res, next, 2);
},
Expand Down Expand Up @@ -267,6 +271,7 @@ router.put(
"/:id/banner",
isAuthenticated,
hasPermissionToPutUserRequest,
useTransaction,
(req, res, next) => {
upload(req, res, next, 2);
},
Expand Down Expand Up @@ -305,6 +310,7 @@ router.put(
isValidBody(keysOf<PutUserSubscriptionRequest>(), req, res, next);
},
hasPermissionToPutUserRequest,
useTransaction,
async (req, res, next) => {
try {
const body = req.body as PutUserSubscriptionRequest;
Expand Down
5 changes: 5 additions & 0 deletions src/routes/video.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
validateVideoExists
} from "@src/middleware/video";
import { projection } from "@src/utilities";
import { useTransaction } from "@src/middleware/transaction";

const router = Router();

Expand Down Expand Up @@ -56,6 +57,7 @@ router.post(
"/",
isAuthenticated,
validatePostVideo,
useTransaction,
(req, res, next) => {
isValidBody(keysOf<PostVideoRequest>(), req, res, next);
},
Expand Down Expand Up @@ -103,6 +105,7 @@ router.post(
router.put(
"/:id",
isAuthenticated,
useTransaction,
(req, res, next) => {
isValidBody(keysOf<PutVideoRequest>(), req, res, next);
},
Expand All @@ -128,6 +131,7 @@ router.put(
"/:id/view",
isAuthenticated,
validateVideoExists,
useTransaction,
async (req, res, next) => {
try {
const params = req.params as PutVideoViewRequestParams;
Expand Down Expand Up @@ -155,6 +159,7 @@ router.delete(
"/:id",
isAuthenticated,
validateVideoExists,
useTransaction,
async (req, res, next) => {
try {
const request = req.params as DeleteVideoRequest;
Expand Down