schedule deletion of notes
This commit is contained in:
parent
d0de4040ef
commit
dcf607c0dc
@ -6,5 +6,6 @@
|
|||||||
|
|
||||||
ENVIRONMENT=dev
|
ENVIRONMENT=dev
|
||||||
PORT=8080
|
PORT=8080
|
||||||
|
CLEANUP_INTERVAL_SECONDS=60
|
||||||
FRONTEND_URL="http://localhost:3000"
|
FRONTEND_URL="http://localhost:3000"
|
||||||
DATABASE_URL="file:./dev.db"
|
DATABASE_URL="file:./dev.db"
|
||||||
|
64
server/package-lock.json
generated
64
server/package-lock.json
generated
@ -9,7 +9,7 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/client": "^3.15.2",
|
"@prisma/client": "^4.0.0",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"dotenv": "^16.0.1",
|
"dotenv": "^16.0.1",
|
||||||
"express": "^4.18.1",
|
"express": "^4.18.1",
|
||||||
@ -21,7 +21,7 @@
|
|||||||
"@types/node": "^18.0.0",
|
"@types/node": "^18.0.0",
|
||||||
"@types/sqlite3": "^3.1.8",
|
"@types/sqlite3": "^3.1.8",
|
||||||
"nodemon": "^2.0.16",
|
"nodemon": "^2.0.16",
|
||||||
"prisma": "^3.15.2",
|
"prisma": "^4.0.0",
|
||||||
"supertest": "^6.2.3",
|
"supertest": "^6.2.3",
|
||||||
"ts-node": "^10.8.1",
|
"ts-node": "^10.8.1",
|
||||||
"typescript": "^4.7.4",
|
"typescript": "^4.7.4",
|
||||||
@ -128,15 +128,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@prisma/client": {
|
"node_modules/@prisma/client": {
|
||||||
"version": "3.15.2",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-3.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.0.0.tgz",
|
||||||
"integrity": "sha512-ErqtwhX12ubPhU4d++30uFY/rPcyvjk+mdifaZO5SeM21zS3t4jQrscy8+6IyB0GIYshl5ldTq6JSBo1d63i8w==",
|
"integrity": "sha512-g1h2OGoRo7anBVQ9Cw3gsbjwPtvf7i0pkGxKeZICtwkvE5CZXW+xZF4FZdmrViYkKaAShbISL0teNpu9ecpf4g==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/engines-version": "3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e"
|
"@prisma/engines-version": "3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12.6"
|
"node": ">=14.17"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"prisma": "*"
|
"prisma": "*"
|
||||||
@ -148,16 +148,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@prisma/engines": {
|
"node_modules/@prisma/engines": {
|
||||||
"version": "3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e",
|
"version": "3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11.tgz",
|
||||||
"integrity": "sha512-NHlojO1DFTsSi3FtEleL9QWXeSF/UjhCW0fgpi7bumnNZ4wj/eQ+BJJ5n2pgoOliTOGv9nX2qXvmHap7rJMNmg==",
|
"integrity": "sha512-u/rG4lDHALolWBLr3yebZ+N2qImp3SDMcu7bHNJuRDaYvYEXy/MqfNRNEgd9GoPsXL3gofYf0VzJf2AmCG3YVw==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"hasInstallScript": true
|
"hasInstallScript": true
|
||||||
},
|
},
|
||||||
"node_modules/@prisma/engines-version": {
|
"node_modules/@prisma/engines-version": {
|
||||||
"version": "3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e",
|
"version": "3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11.tgz",
|
||||||
"integrity": "sha512-e3k2Vd606efd1ZYy2NQKkT4C/pn31nehyLhVug6To/q8JT8FpiMrDy7zmm3KLF0L98NOQQcutaVtAPhzKhzn9w=="
|
"integrity": "sha512-PiZhdD624SrYEjyLboI0X7OugNbxUzDJx9v/6ldTKuqNDVUCmRH/Z00XwDi/dgM4FlqOSO+YiUsSiSKjxxG8cw=="
|
||||||
},
|
},
|
||||||
"node_modules/@sindresorhus/is": {
|
"node_modules/@sindresorhus/is": {
|
||||||
"version": "0.14.0",
|
"version": "0.14.0",
|
||||||
@ -2949,20 +2949,20 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prisma": {
|
"node_modules/prisma": {
|
||||||
"version": "3.15.2",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/prisma/-/prisma-3.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/prisma/-/prisma-4.0.0.tgz",
|
||||||
"integrity": "sha512-nMNSMZvtwrvoEQ/mui8L/aiCLZRCj5t6L3yujKpcDhIPk7garp8tL4nMx2+oYsN0FWBacevJhazfXAbV1kfBzA==",
|
"integrity": "sha512-Dtsar03XpCBkcEb2ooGWO/WcgblDTLzGhPcustbehwlFXuTMliMDRzXsfygsgYwQoZnAUKRd1rhpvBNEUziOVw==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/engines": "3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e"
|
"@prisma/engines": "3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"prisma": "build/index.js",
|
"prisma": "build/index.js",
|
||||||
"prisma2": "build/index.js"
|
"prisma2": "build/index.js"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12.6"
|
"node": ">=14.17"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/promise-inflight": {
|
"node_modules/promise-inflight": {
|
||||||
@ -4157,23 +4157,23 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@prisma/client": {
|
"@prisma/client": {
|
||||||
"version": "3.15.2",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-3.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.0.0.tgz",
|
||||||
"integrity": "sha512-ErqtwhX12ubPhU4d++30uFY/rPcyvjk+mdifaZO5SeM21zS3t4jQrscy8+6IyB0GIYshl5ldTq6JSBo1d63i8w==",
|
"integrity": "sha512-g1h2OGoRo7anBVQ9Cw3gsbjwPtvf7i0pkGxKeZICtwkvE5CZXW+xZF4FZdmrViYkKaAShbISL0teNpu9ecpf4g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@prisma/engines-version": "3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e"
|
"@prisma/engines-version": "3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@prisma/engines": {
|
"@prisma/engines": {
|
||||||
"version": "3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e",
|
"version": "3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11.tgz",
|
||||||
"integrity": "sha512-NHlojO1DFTsSi3FtEleL9QWXeSF/UjhCW0fgpi7bumnNZ4wj/eQ+BJJ5n2pgoOliTOGv9nX2qXvmHap7rJMNmg==",
|
"integrity": "sha512-u/rG4lDHALolWBLr3yebZ+N2qImp3SDMcu7bHNJuRDaYvYEXy/MqfNRNEgd9GoPsXL3gofYf0VzJf2AmCG3YVw==",
|
||||||
"devOptional": true
|
"devOptional": true
|
||||||
},
|
},
|
||||||
"@prisma/engines-version": {
|
"@prisma/engines-version": {
|
||||||
"version": "3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e",
|
"version": "3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11.tgz",
|
||||||
"integrity": "sha512-e3k2Vd606efd1ZYy2NQKkT4C/pn31nehyLhVug6To/q8JT8FpiMrDy7zmm3KLF0L98NOQQcutaVtAPhzKhzn9w=="
|
"integrity": "sha512-PiZhdD624SrYEjyLboI0X7OugNbxUzDJx9v/6ldTKuqNDVUCmRH/Z00XwDi/dgM4FlqOSO+YiUsSiSKjxxG8cw=="
|
||||||
},
|
},
|
||||||
"@sindresorhus/is": {
|
"@sindresorhus/is": {
|
||||||
"version": "0.14.0",
|
"version": "0.14.0",
|
||||||
@ -6209,12 +6209,12 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"prisma": {
|
"prisma": {
|
||||||
"version": "3.15.2",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/prisma/-/prisma-3.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/prisma/-/prisma-4.0.0.tgz",
|
||||||
"integrity": "sha512-nMNSMZvtwrvoEQ/mui8L/aiCLZRCj5t6L3yujKpcDhIPk7garp8tL4nMx2+oYsN0FWBacevJhazfXAbV1kfBzA==",
|
"integrity": "sha512-Dtsar03XpCBkcEb2ooGWO/WcgblDTLzGhPcustbehwlFXuTMliMDRzXsfygsgYwQoZnAUKRd1rhpvBNEUziOVw==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@prisma/engines": "3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e"
|
"@prisma/engines": "3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"promise-inflight": {
|
"promise-inflight": {
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
"author": "Maxime Cannoodt (mcndt)",
|
"author": "Maxime Cannoodt (mcndt)",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/client": "^3.15.2",
|
"@prisma/client": "^4.0.0",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"dotenv": "^16.0.1",
|
"dotenv": "^16.0.1",
|
||||||
"express": "^4.18.1",
|
"express": "^4.18.1",
|
||||||
@ -23,7 +23,7 @@
|
|||||||
"@types/node": "^18.0.0",
|
"@types/node": "^18.0.0",
|
||||||
"@types/sqlite3": "^3.1.8",
|
"@types/sqlite3": "^3.1.8",
|
||||||
"nodemon": "^2.0.16",
|
"nodemon": "^2.0.16",
|
||||||
"prisma": "^3.15.2",
|
"prisma": "^4.0.0",
|
||||||
"supertest": "^6.2.3",
|
"supertest": "^6.2.3",
|
||||||
"ts-node": "^10.8.1",
|
"ts-node": "^10.8.1",
|
||||||
"typescript": "^4.7.4",
|
"typescript": "^4.7.4",
|
||||||
|
Binary file not shown.
@ -13,6 +13,7 @@ datasource db {
|
|||||||
model EncryptedNote {
|
model EncryptedNote {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
insert_time DateTime @default(now())
|
insert_time DateTime @default(now())
|
||||||
|
expire_time DateTime @default(now())
|
||||||
ciphertext String
|
ciphertext String
|
||||||
hmac String
|
hmac String
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,15 @@ import "dotenv/config";
|
|||||||
import express, { Express, Request, Response } from "express";
|
import express, { Express, Request, Response } from "express";
|
||||||
import cors from "cors";
|
import cors from "cors";
|
||||||
import { PrismaClient, EncryptedNote } from "@prisma/client";
|
import { PrismaClient, EncryptedNote } from "@prisma/client";
|
||||||
|
import { addDays } from "./util";
|
||||||
|
|
||||||
|
// Initialize middleware clients
|
||||||
const prisma = new PrismaClient();
|
const prisma = new PrismaClient();
|
||||||
|
|
||||||
const app: Express = express();
|
const app: Express = express();
|
||||||
|
app.use(express.json());
|
||||||
|
|
||||||
|
// Allow CORS in dev mode.
|
||||||
if (process.env.ENVIRONMENT == "dev") {
|
if (process.env.ENVIRONMENT == "dev") {
|
||||||
app.use(
|
app.use(
|
||||||
cors({
|
cors({
|
||||||
@ -15,8 +19,6 @@ if (process.env.ENVIRONMENT == "dev") {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
app.use(express.json());
|
|
||||||
|
|
||||||
// start the Express server
|
// start the Express server
|
||||||
app.listen(process.env.PORT, () => {
|
app.listen(process.env.PORT, () => {
|
||||||
console.log(`server started at http://localhost:${process.env.PORT}`);
|
console.log(`server started at http://localhost:${process.env.PORT}`);
|
||||||
@ -25,7 +27,9 @@ app.listen(process.env.PORT, () => {
|
|||||||
// Post new encrypted note
|
// Post new encrypted note
|
||||||
app.post("/note/", async (req: Request<{}, {}, EncryptedNote>, res) => {
|
app.post("/note/", async (req: Request<{}, {}, EncryptedNote>, res) => {
|
||||||
const note = req.body;
|
const note = req.body;
|
||||||
const savedNote = await prisma.encryptedNote.create({ data: note });
|
const savedNote = await prisma.encryptedNote.create({
|
||||||
|
data: { ...note, expire_time: addDays(new Date(), 14) },
|
||||||
|
});
|
||||||
res.json({ view_url: `${process.env.FRONTEND_URL}/note/${savedNote.id}` });
|
res.json({ view_url: `${process.env.FRONTEND_URL}/note/${savedNote.id}` });
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -44,3 +48,24 @@ app.get("/note/:id", async (req, res) => {
|
|||||||
app.use((req, res, next) => {
|
app.use((req, res, next) => {
|
||||||
res.status(404).send();
|
res.status(404).send();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Clean up expired notes periodically
|
||||||
|
const interval =
|
||||||
|
Math.max(parseInt(<string>process.env.CLEANUP_INTERVAL_SECONDS) || 1, 1) *
|
||||||
|
1000;
|
||||||
|
setInterval(async () => {
|
||||||
|
try {
|
||||||
|
console.log("[Cleanup] Cleaning up expired notes...");
|
||||||
|
const deleted = await prisma.encryptedNote.deleteMany({
|
||||||
|
where: {
|
||||||
|
expire_time: {
|
||||||
|
lte: new Date(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
console.log(`[Cleanup] Deleted ${deleted.count} expired notes.`);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`[Cleanup] Error cleaning expired notes:`);
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}, interval);
|
||||||
|
5
server/util.ts
Normal file
5
server/util.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export function addDays(date: Date, days: number): Date {
|
||||||
|
var result = new Date(date);
|
||||||
|
result.setDate(result.getDate() + days);
|
||||||
|
return result;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user