Skip to content

Commit 78b9a75

Browse files
authored
Merge pull request #199 from ls1intum/feature/create-webapp-side-API-and-Websocket-managers
feat: create api and websocket managers
2 parents e771189 + fb72510 commit 78b9a75

File tree

11 files changed

+306
-215
lines changed

11 files changed

+306
-215
lines changed

package-lock.json

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

standalone/server/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"dotenv": "16.4.7",
77
"express": "5.1.0",
88
"mongoose": "8.14.0",
9+
"node-cron": "4.1.0",
910
"ws": "8.18.1"
1011
},
1112
"scripts": {
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import cron from "node-cron"
2+
import Diagram from "./models/Diagram"
3+
4+
export const startDiagramCleanupJob = (): void => {
5+
// every day at 00:00 (midnight).
6+
// Schedule a cron job to delete diagrams older than 60 days
7+
cron.schedule("0 0 * * *", async () => {
8+
try {
9+
const cutoffDate = new Date()
10+
cutoffDate.setDate(cutoffDate.getDate() - 60)
11+
12+
const result = await Diagram.deleteMany({
13+
updatedAt: { $lt: cutoffDate },
14+
})
15+
16+
console.log(`Deleted ${result.deletedCount} diagrams older than 30 days.`)
17+
} catch (error) {
18+
console.error("Error during scheduled diagram cleanup:", error)
19+
}
20+
})
21+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import mongoose from "mongoose"
2+
3+
export const connectToMongoDB = async (mongoURI: string): Promise<void> => {
4+
try {
5+
await mongoose.connect(mongoURI)
6+
console.log("Connected to MongoDB")
7+
} catch (error) {
8+
console.error("MongoDB connection error:", error)
9+
process.exit(1)
10+
}
11+
}

standalone/server/src/models/Diagram.ts renamed to standalone/server/src/database/models/Diagram.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
/* eslint-disable @typescript-eslint/no-explicit-any */
21
import mongoose, { Document, Schema } from "mongoose"
32

43
export interface IDiagram extends Document {
54
_id: string // Custom ID from library
65
version: string
76
title: string
87
type: string
9-
nodes: any[] // JSON array for nodes
10-
edges: any[] // JSON array for edges
11-
assessments: Record<string, any> // Optional JSON object for assessments
8+
nodes: Schema.Types.Mixed[] // JSON array for nodes
9+
edges: Schema.Types.Mixed[] // JSON array for edges
10+
assessments: Record<string, Schema.Types.Mixed> // Optional JSON object for assessments
1211
}
1312

1413
const diagramSchema: Schema = new Schema(
@@ -23,6 +22,15 @@ const diagramSchema: Schema = new Schema(
2322
},
2423
{
2524
minimize: false, // Disable minimization of the document
25+
versionKey: false,
26+
timestamps: true, // Automatically manage createdAt and updatedAt fields
27+
toJSON: {
28+
virtuals: true, // expose `id`
29+
transform: (_doc, ret) => {
30+
ret.id = ret._id // copy _id to id
31+
delete ret._id // optional: remove _id
32+
},
33+
},
2634
}
2735
)
2836

standalone/server/src/diagramRouter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* eslint-disable @typescript-eslint/no-explicit-any */
22
import { Router, Request, Response } from "express"
3-
import Diagram from "./models/Diagram"
3+
import Diagram from "./database/models/Diagram"
44

55
const router = Router()
66

standalone/server/src/server.ts

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
// First load environment variables from .env file
22
import "./loadEnvironment"
33
import express from "express"
4-
import mongoose from "mongoose"
54
import { configureMiddlewares } from "./middlewares"
65
import diagramRouter from "./diagramRouter"
76
import { startSocketServer } from "./relaySocketServer"
7+
import { connectToMongoDB } from "./database/connect"
8+
import { startDiagramCleanupJob } from "./database/cleanupJob"
89

910
const PORT = process.env.PORT || 8000
1011
const serverHost = process.env.HOST || "localhost"
@@ -17,20 +18,11 @@ configureMiddlewares(app)
1718
// Mount routes
1819
app.use("/api", diagramRouter)
1920

20-
console.log("Mongo URI:", mongoURI)
21-
mongoose
22-
.connect(mongoURI)
23-
.then(() => {
24-
console.log("Connected to MongoDB")
25-
// Start server
26-
27-
app.listen(PORT, () => {
28-
console.log(`HTTP server running on http://${serverHost}:${PORT}`)
29-
})
30-
// Start WebSocket server
31-
startSocketServer()
32-
})
33-
.catch((error) => {
34-
console.error("MongoDB connection error:", error)
35-
process.exit(1) // Exit if cannot connect to DB
21+
connectToMongoDB(mongoURI).then(() => {
22+
app.listen(PORT, () => {
23+
console.log(`HTTP server running on http://${serverHost}:${PORT}`)
3624
})
25+
26+
startSocketServer()
27+
startDiagramCleanupJob()
28+
})

standalone/webapp/src/components/modals/ShareModal.tsx

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { toast } from "react-toastify"
55
import { useEditorContext, useModalContext } from "@/contexts"
66
import { useNavigate } from "react-router"
77
import { DiagramView } from "@/types"
8-
import { backendURL } from "@/constants"
8+
import { DiagramAPIManager } from "@/services/DiagramAPIManager"
99

1010
export const ShareModal = () => {
1111
const { editor } = useEditorContext()
@@ -17,36 +17,26 @@ export const ShareModal = () => {
1717
toast.error("Editor instance is not available.")
1818
return
1919
}
20-
const model = editor.model
2120

22-
await fetch(`${backendURL}/api/`, {
23-
method: "POST",
24-
headers: { "Content-Type": "application/json" },
25-
body: JSON.stringify(model),
26-
})
27-
.then(async (res) => {
28-
if (res.ok) {
29-
const diagramID = (await res.json())._id
21+
try {
22+
const model = editor.model
23+
const { id: diagramID } = await DiagramAPIManager.createDiagram(model)
3024

31-
const newurl = `${window.location.origin}/${diagramID}?view=${viewType}`
32-
copyToClipboard(newurl)
33-
navigate(`/${diagramID}?view=${viewType}`)
25+
const newurl = `${window.location.origin}/${diagramID}?view=${viewType}`
26+
copyToClipboard(newurl)
27+
navigate(`/${diagramID}?view=${viewType}`)
3428

35-
toast.success(
36-
`The link has been copied to your clipboard and can be shared to collaborate, simply by pasting the link. You can re-access the link by going to share menu.`,
37-
{
38-
autoClose: 10000,
39-
}
40-
)
41-
closeModal()
42-
} else {
43-
throw new Error("Network response was not ok")
29+
toast.success(
30+
`The link has been copied to your clipboard and can be shared to collaborate, simply by pasting the link. You can re-access the link by going to share menu.`,
31+
{
32+
autoClose: 10000,
4433
}
45-
})
46-
.catch((err) => {
47-
console.error("Error in setDiagram endpoint:", err)
48-
toast.error("Error in setDiagram endpoint:", err)
49-
})
34+
)
35+
closeModal()
36+
} catch (err) {
37+
console.error("Error creating diagram:", err)
38+
toast.error("Could not create diagram.")
39+
}
5040
}
5141

5242
const copyToClipboard = (link: string) => {

0 commit comments

Comments
 (0)