add transactions

This commit is contained in:
Maxime Cannoodt 2022-08-30 09:51:53 +02:00
parent 6de10f07e6
commit 433394a3c2
3 changed files with 66 additions and 23 deletions

View File

@ -3,6 +3,7 @@
generator client { generator client {
provider = "prisma-client-js" provider = "prisma-client-js"
previewFeatures = ["interactiveTransactions"]
} }
datasource db { datasource db {

View File

@ -1,4 +1,4 @@
import { EncryptedNote, prisma } from "@prisma/client"; import { EncryptedNote, PrismaClient } from "@prisma/client";
import { NextFunction, Request, Response } from "express"; import { NextFunction, Request, Response } from "express";
import { crc16 as crc } from "crc"; import { crc16 as crc } from "crc";
import { createNote } from "../../db/note.dao"; import { createNote } from "../../db/note.dao";
@ -16,6 +16,8 @@ import {
IsArray, IsArray,
ValidateNested, ValidateNested,
} from "class-validator"; } from "class-validator";
import prisma from "../../db/client";
import { createEmbed, EncryptedEmbedDTO } from "../../db/embed.dao";
export class EncryptedEmbedBody { export class EncryptedEmbedBody {
@IsBase64() @IsBase64()
@ -28,7 +30,7 @@ export class EncryptedEmbedBody {
@IsString() @IsString()
@IsNotEmpty() @IsNotEmpty()
embedId: string | undefined; embed_id: string | undefined;
} }
/** /**
@ -73,6 +75,7 @@ export async function postNoteController(
// Validate request body // Validate request body
const notePostRequest = new NotePostRequest(); const notePostRequest = new NotePostRequest();
const noteEmbedRequests: EncryptedEmbedBody[] = [];
Object.assign(notePostRequest, req.body); Object.assign(notePostRequest, req.body);
try { try {
await validateOrReject(notePostRequest); await validateOrReject(notePostRequest);
@ -81,6 +84,7 @@ export async function postNoteController(
const embedBody = new EncryptedEmbedBody(); const embedBody = new EncryptedEmbedBody();
Object.assign(embedBody, embed); Object.assign(embedBody, embed);
await validateOrReject(embedBody); await validateOrReject(embedBody);
noteEmbedRequests.push(embedBody);
} }
} }
} catch (_err: any) { } catch (_err: any) {
@ -109,24 +113,62 @@ export async function postNoteController(
crypto_version: notePostRequest.crypto_version, crypto_version: notePostRequest.crypto_version,
} as EncryptedNote; } as EncryptedNote;
// Store note object // Store note object and possible embeds in database transaction
try {
const savedNote = await prisma.$transaction(async () => {
// 1. Save note
const savedNote = await createNote(note);
createNote(note) // 2. Store embeds
.then(async (savedNote) => { const embeds: EncryptedEmbedDTO[] = noteEmbedRequests.map(
(embed) =>
({
...embed,
note_id: savedNote.id,
} as EncryptedEmbedDTO)
);
embeds.forEach(async (embed) => {
await createEmbed(embed);
});
// 3. Finalize transaction
return savedNote;
});
// Log write event
event.success = true; event.success = true;
event.note_id = savedNote.id; event.note_id = savedNote.id;
event.size_bytes = savedNote.ciphertext.length + savedNote.hmac.length; event.size_bytes = savedNote.ciphertext.length + savedNote.hmac.length;
event.expire_window_days = EXPIRE_WINDOW_DAYS; event.expire_window_days = EXPIRE_WINDOW_DAYS;
await EventLogger.writeEvent(event); await EventLogger.writeEvent(event);
// return HTTP request
res.json({ res.json({
view_url: `${process.env.FRONTEND_URL}/note/${savedNote.id}`, view_url: `${process.env.FRONTEND_URL}/note/${savedNote.id}`,
expire_time: savedNote.expire_time, expire_time: savedNote.expire_time,
}); });
}) } catch (err: any) {
.catch(async (err) => {
event.error = err.toString(); event.error = err.toString();
await EventLogger.writeEvent(event); await EventLogger.writeEvent(event);
next(err); next(err);
}
createNote(note)
.then(async (savedNote) => {
// event.success = true;
// event.note_id = savedNote.id;
// event.size_bytes = savedNote.ciphertext.length + savedNote.hmac.length;
// event.expire_window_days = EXPIRE_WINDOW_DAYS;
// await EventLogger.writeEvent(event);
// res.json({
// view_url: `${process.env.FRONTEND_URL}/note/${savedNote.id}`,
// expire_time: savedNote.expire_time,
// });
})
.catch(async (err) => {
// event.error = err.toString();
// await EventLogger.writeEvent(event);
// next(err);
}); });
} }

View File

@ -186,7 +186,7 @@ const TEST_PAYLOADS: TestParams[] = [
user_id: VALID_USER_ID, user_id: VALID_USER_ID,
embeds: [ embeds: [
{ {
embedId: "0", embed_id: "0",
ciphertext: VALID_CIPHERTEXT, ciphertext: VALID_CIPHERTEXT,
hmac: VALID_HMAC, hmac: VALID_HMAC,
}, },
@ -194,9 +194,9 @@ const TEST_PAYLOADS: TestParams[] = [
}, },
expectedStatus: 200, expectedStatus: 200,
}, },
// Request with embed with empty embedId // Request with embed with empty embed_id
{ {
case: "embed with empty embedId", case: "embed with empty embed_id",
payload: { payload: {
ciphertext: VALID_CIPHERTEXT, ciphertext: VALID_CIPHERTEXT,
hmac: VALID_HMAC, hmac: VALID_HMAC,
@ -221,7 +221,7 @@ const TEST_PAYLOADS: TestParams[] = [
{ {
ciphertext: "not_base64", ciphertext: "not_base64",
hmac: VALID_HMAC, hmac: VALID_HMAC,
embedId: "0", embed_id: "0",
}, },
], ],
}, },
@ -238,7 +238,7 @@ const TEST_PAYLOADS: TestParams[] = [
{ {
ciphertext: VALID_CIPHERTEXT, ciphertext: VALID_CIPHERTEXT,
hmac: "not_base64", hmac: "not_base64",
embedId: "0", embed_id: "0",
}, },
], ],
}, },
@ -255,12 +255,12 @@ const TEST_PAYLOADS: TestParams[] = [
{ {
ciphertext: VALID_CIPHERTEXT, ciphertext: VALID_CIPHERTEXT,
hmac: VALID_HMAC, hmac: VALID_HMAC,
embedId: "0", embed_id: "0",
}, },
{ {
ciphertext: VALID_CIPHERTEXT, ciphertext: VALID_CIPHERTEXT,
hmac: VALID_HMAC, hmac: VALID_HMAC,
embedId: "0", embed_id: "0",
}, },
], ],
}, },