Canvas: Prettier

Change-Id: I620dde109df0f29f0c85c6fe150e347d2c32a03e
diff --git a/apps/canvas/back/src/index.ts b/apps/canvas/back/src/index.ts
new file mode 100644
index 0000000..65eab15
--- /dev/null
+++ b/apps/canvas/back/src/index.ts
@@ -0,0 +1,394 @@
+import { PrismaClient } from "@prisma/client";
+import express from "express";
+import { env } from "node:process";
+import axios from "axios";
+import { GithubClient } from "./github";
+
+const db = new PrismaClient();
+
+const handleProjectCreate: express.Handler = async (req, resp) => {
+	try {
+		const { id } = await db.project.create({
+			data: {
+				userId: "gio", // req.get("x-forwarded-userid")!,
+				name: req.body.name,
+			},
+		});
+		resp.status(200);
+		resp.header("Content-Type", "application/json");
+		resp.write(
+			JSON.stringify({
+				id,
+			}),
+		);
+	} catch (e) {
+		console.log(e);
+		resp.status(500);
+	} finally {
+		resp.end();
+	}
+};
+
+const handleProjectAll: express.Handler = async (req, resp) => {
+	try {
+		const r = await db.project.findMany({
+			where: {
+				userId: "gio", // req.get("x-forwarded-userid")!,
+			},
+		});
+		resp.status(200);
+		resp.header("Content-Type", "application/json");
+		resp.write(
+			JSON.stringify(
+				r.map((p) => ({
+					id: p.id.toString(),
+					name: p.name,
+				})),
+			),
+		);
+	} catch (e) {
+		console.log(e);
+		resp.status(500);
+	} finally {
+		resp.end();
+	}
+};
+
+const handleSave: express.Handler = async (req, resp) => {
+	try {
+		await db.project.update({
+			where: {
+				id: Number(req.params["projectId"]),
+			},
+			data: {
+				draft: Buffer.from(JSON.stringify(req.body)),
+			},
+		});
+		resp.status(200);
+	} catch (e) {
+		console.log(e);
+		resp.status(500);
+	} finally {
+		resp.end();
+	}
+};
+
+const handleSavedGet: express.Handler = async (req, resp) => {
+	try {
+		const r = await db.project.findUnique({
+			where: {
+				id: Number(req.params["projectId"]),
+			},
+			select: {
+				state: true,
+				draft: true,
+			},
+		});
+		if (r == null) {
+			resp.status(404);
+		} else {
+			resp.status(200);
+			resp.header("content-type", "application/json");
+			if (r.draft == null) {
+				if (r.state == null) {
+					resp.send({
+						nodes: [],
+						edges: [],
+						viewport: { x: 0, y: 0, zoom: 1 },
+					});
+				} else {
+					resp.send(JSON.parse(Buffer.from(r.state).toString("utf8")));
+				}
+			} else {
+				resp.send(JSON.parse(Buffer.from(r.draft).toString("utf8")));
+			}
+		}
+	} catch (e) {
+		console.log(e);
+		resp.status(500);
+	} finally {
+		resp.end();
+	}
+};
+
+const handleDelete: express.Handler = async (req, resp) => {
+	try {
+		const projectId = Number(req.params["projectId"]);
+		const p = await db.project.findUnique({
+			where: {
+				id: projectId,
+			},
+			select: {
+				instanceId: true,
+			},
+		});
+		if (p === null) {
+			resp.status(404);
+			return;
+		}
+		const r = await axios.request({
+			url: `http://appmanager.hgrz-appmanager.svc.cluster.local/api/instance/${p.instanceId}/remove`,
+			method: "post",
+		});
+		if (r.status === 200) {
+			await db.project.delete({
+				where: {
+					id: projectId,
+				},
+			});
+		}
+		resp.status(200);
+	} catch (e) {
+		console.log(e);
+		resp.status(500);
+	} finally {
+		resp.end();
+	}
+};
+
+const handleDeploy: express.Handler = async (req, resp) => {
+	try {
+		const projectId = Number(req.params["projectId"]);
+		const state = Buffer.from(JSON.stringify(req.body.state));
+		const p = await db.project.findUnique({
+			where: {
+				id: projectId,
+			},
+			select: {
+				instanceId: true,
+				githubToken: true,
+				deployKey: true,
+			},
+		});
+		if (p === null) {
+			resp.status(404);
+			return;
+		}
+		await db.project.update({
+			where: {
+				id: projectId,
+			},
+			data: {
+				draft: state,
+			},
+		});
+		let r: { status: number; data: { id: string; deployKey: string } };
+		if (p.instanceId == null) {
+			r = await axios.request({
+				url: "http://appmanager.hgrz-appmanager.svc.cluster.local/api/dodo-app",
+				method: "post",
+				data: {
+					config: req.body.config,
+				},
+			});
+			console.log(r);
+			if (r.status === 200) {
+				await db.project.update({
+					where: {
+						id: projectId,
+					},
+					data: {
+						state,
+						draft: null,
+						instanceId: r.data.id,
+						deployKey: r.data.deployKey,
+					},
+				});
+
+				if (p.githubToken && r.data.deployKey) {
+					const stateObj = JSON.parse(JSON.parse(state.toString()));
+					const githubNodes = stateObj.nodes.filter(
+						(n: any) => n.type === "github" && n.data?.repository?.id,
+					);
+
+					const github = new GithubClient(p.githubToken);
+					for (const node of githubNodes) {
+						try {
+							await github.addDeployKey(node.data.repository.sshURL, r.data.deployKey);
+						} catch (error) {
+							console.error(
+								`Failed to add deploy key to repository ${node.data.repository.sshURL}:`,
+								error,
+							);
+						}
+					}
+				}
+			}
+		} else {
+			r = await axios.request({
+				url: `http://appmanager.hgrz-appmanager.svc.cluster.local/api/dodo-app/${p.instanceId}`,
+				method: "put",
+				data: {
+					config: req.body.config,
+				},
+			});
+			if (r.status === 200) {
+				await db.project.update({
+					where: {
+						id: projectId,
+					},
+					data: {
+						state,
+						draft: null,
+					},
+				});
+			}
+		}
+	} catch (e) {
+		console.log(e);
+		resp.status(500);
+	} finally {
+		resp.end();
+	}
+};
+
+const handleStatus: express.Handler = async (req, resp) => {
+	try {
+		const projectId = Number(req.params["projectId"]);
+		const p = await db.project.findUnique({
+			where: {
+				id: projectId,
+			},
+			select: {
+				instanceId: true,
+			},
+		});
+		console.log(projectId, p);
+		if (p === null) {
+			resp.status(404);
+			return;
+		}
+		if (p.instanceId == null) {
+			resp.status(404);
+			return;
+		}
+		const r = await axios.request({
+			url: `http://appmanager.hgrz-appmanager.svc.cluster.local/api/instance/${p.instanceId}/status`,
+			method: "get",
+		});
+		resp.status(r.status);
+		if (r.status === 200) {
+			resp.write(JSON.stringify(r.data));
+		}
+	} catch (e) {
+		console.log(e);
+		resp.status(500);
+	} finally {
+		resp.end();
+	}
+};
+
+const handleGithubRepos: express.Handler = async (req, resp) => {
+	try {
+		const projectId = Number(req.params["projectId"]);
+		const project = await db.project.findUnique({
+			where: { id: projectId },
+			select: { githubToken: true },
+		});
+
+		if (!project?.githubToken) {
+			resp.status(400);
+			resp.write(JSON.stringify({ error: "GitHub token not configured" }));
+			return;
+		}
+
+		const github = new GithubClient(project.githubToken);
+		const repositories = await github.getRepositories();
+
+		resp.status(200);
+		resp.header("Content-Type", "application/json");
+		resp.write(JSON.stringify(repositories));
+	} catch (e) {
+		console.log(e);
+		resp.status(500);
+		resp.write(JSON.stringify({ error: "Failed to fetch repositories" }));
+	} finally {
+		resp.end();
+	}
+};
+
+const handleUpdateGithubToken: express.Handler = async (req, resp) => {
+	try {
+		const projectId = Number(req.params["projectId"]);
+		const { githubToken } = req.body;
+
+		await db.project.update({
+			where: { id: projectId },
+			data: { githubToken },
+		});
+
+		resp.status(200);
+	} catch (e) {
+		console.log(e);
+		resp.status(500);
+	} finally {
+		resp.end();
+	}
+};
+
+const handleEnv: express.Handler = async (req, resp) => {
+	const projectId = Number(req.params["projectId"]);
+	try {
+		const project = await db.project.findUnique({
+			where: { id: projectId },
+			select: {
+				deployKey: true,
+				githubToken: true,
+			},
+		});
+
+		if (!project) {
+			resp.status(404);
+			resp.write(JSON.stringify({ error: "Project not found" }));
+			return;
+		}
+
+		resp.status(200);
+		resp.write(
+			JSON.stringify({
+				deployKey: project.deployKey,
+				integrations: {
+					github: !!project.githubToken,
+				},
+				networks: [
+					{
+						name: "Public",
+						domain: "v1.dodo.cloud",
+					},
+					{
+						name: "Private",
+						domain: "p.v1.dodo.cloud",
+					},
+				],
+			}),
+		);
+	} catch (error) {
+		console.error("Error checking integrations:", error);
+		resp.status(500);
+		resp.write(JSON.stringify({ error: "Internal server error" }));
+	} finally {
+		resp.end();
+	}
+};
+
+async function start() {
+	await db.$connect();
+	const app = express();
+	app.use(express.json());
+	app.post("/api/project/:projectId/saved", handleSave);
+	app.get("/api/project/:projectId/saved", handleSavedGet);
+	app.post("/api/project/:projectId/deploy", handleDeploy);
+	app.get("/api/project/:projectId/status", handleStatus);
+	app.delete("/api/project/:projectId", handleDelete);
+	app.get("/api/project", handleProjectAll);
+	app.post("/api/project", handleProjectCreate);
+	app.get("/api/project/:projectId/repos/github", handleGithubRepos);
+	app.post("/api/project/:projectId/github-token", handleUpdateGithubToken);
+	app.get("/api/project/:projectId/env", handleEnv);
+	app.use("/", express.static("../front/dist"));
+	app.listen(env.DODO_PORT_WEB, () => {
+		console.log("started");
+	});
+}
+
+start();