add transactions
This commit is contained in:
parent
6de10f07e6
commit
433394a3c2
@ -2,7 +2,8 @@
|
|||||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||||
|
|
||||||
generator client {
|
generator client {
|
||||||
provider = "prisma-client-js"
|
provider = "prisma-client-js"
|
||||||
|
previewFeatures = ["interactiveTransactions"]
|
||||||
}
|
}
|
||||||
|
|
||||||
datasource db {
|
datasource db {
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
// 2. Store embeds
|
||||||
|
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.note_id = savedNote.id;
|
||||||
|
event.size_bytes = savedNote.ciphertext.length + savedNote.hmac.length;
|
||||||
|
event.expire_window_days = EXPIRE_WINDOW_DAYS;
|
||||||
|
await EventLogger.writeEvent(event);
|
||||||
|
|
||||||
|
// return HTTP request
|
||||||
|
res.json({
|
||||||
|
view_url: `${process.env.FRONTEND_URL}/note/${savedNote.id}`,
|
||||||
|
expire_time: savedNote.expire_time,
|
||||||
|
});
|
||||||
|
} catch (err: any) {
|
||||||
|
event.error = err.toString();
|
||||||
|
await EventLogger.writeEvent(event);
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
|
||||||
createNote(note)
|
createNote(note)
|
||||||
.then(async (savedNote) => {
|
.then(async (savedNote) => {
|
||||||
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);
|
||||||
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(async (err) => {
|
.catch(async (err) => {
|
||||||
event.error = err.toString();
|
// event.error = err.toString();
|
||||||
await EventLogger.writeEvent(event);
|
// await EventLogger.writeEvent(event);
|
||||||
next(err);
|
// next(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user