Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"js/ts.tsdk.path": "node_modules/typescript/lib"
}
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions prisma/migrations/20260515093156_init/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- CreateEnum
CREATE TYPE "UserRole" AS ENUM ('FARMER', 'INSPECTOR', 'MANAGER', 'ADMIN', 'DEVELOPER');
3 changes: 3 additions & 0 deletions prisma/migrations/migration_lock.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "postgresql"
7 changes: 7 additions & 0 deletions prisma/models/organisation.prisma
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
model Organisation {
id Int @id @default(autoincrement())
name String
createdAt DateTime @default(now())

projectOrganisations ProjectOrganisation[]
}
1 change: 1 addition & 0 deletions prisma/models/project.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ model Project {
adminLocation Location? @relation("ProjectAdminLocation", fields: [adminLocationId], references: [id], onDelete: Restrict)
userProjects UserProject[]
projectTreeTypes ProjectTreeType[]
projectOrganisations ProjectOrganisation[]
scanBatches ScanBatch[] @relation("ProjectScanBatches")
treeScans TreeScan[] @relation("ProjectTreeScans")

Expand Down
10 changes: 10 additions & 0 deletions prisma/models/projectOrganisation.prisma
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
model ProjectOrganisation {
projectId Int
organisationId Int

project Project @relation(fields: [projectId], references: [id])
organisation Organisation @relation(fields: [organisationId], references: [id])

@@id([projectId, organisationId])
@@map("project_organisations")
}
3 changes: 2 additions & 1 deletion prisma/schema.prisma
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
generator client {
provider = "prisma-client-js"
schema = "./models"
}

datasource db {
Expand All @@ -13,4 +14,4 @@ enum UserRole {
MANAGER
ADMIN
DEVELOPER
}
}
11 changes: 10 additions & 1 deletion src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,18 @@ app.use(express.urlencoded({ extended: true }));
// Swagger docs
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerSpec));

// Module Routes
// Routes (central router)
app.use("/", routes);

// Health check (keep this from your version)
app.get("/health", (_req, res) => {
res.json({
success: true,
status: "ok",
timestamp: new Date().toISOString(),
});
});

// 404 & error handler
app.use(notFound);
app.use(errorHandler);
Expand Down
9 changes: 7 additions & 2 deletions src/routes/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Router } from "express";

import authRoutes from "../modules/auth/auth.routes";
import { healthRoutes } from "../modules/health";
import { projectTreeTypesRoutes } from "../modules/project-tree-types";
Expand All @@ -9,11 +10,14 @@ import { localizationRoutes } from "../modules/localization";
import { adoptersRouter } from "../modules/adopters";
import { userProjectAssignmentRoutes } from "../modules/user-project-assignment";
import { partnersRoutes } from "../modules/partners";

import treeScansRoutes from "../modules/tree-scans";

// FEATURE
import projectOrganisationsRoutes from "./projectOrganisation";

const router = Router();

// system routes
router.use("/health", healthRoutes);
router.use("/auth", authRoutes);
router.use("/adopters", adoptersRouter);
Expand All @@ -24,7 +28,8 @@ router.use("/localized-strings", localizationRoutes);
router.use("/user-projects", userProjectAssignmentRoutes);
router.use("/project-tree-types", projectTreeTypesRoutes);
router.use("/partners", partnersRoutes);

router.use("/tree-scans", treeScansRoutes);

router.use("/project-organisations", projectOrganisationsRoutes);

export default router;
95 changes: 95 additions & 0 deletions src/routes/projectOrganisation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { Router, Request, Response, NextFunction } from "express";
import { prisma } from "../lib/prisma";

const router = Router();

router.get("/", (req: Request, res: Response, next: NextFunction): void => {
void (async () => {
try {
const data = await prisma.projectOrganisation.findMany({
include: {
organisation: true,
project: true,
},
});

res.json(data);
} catch (error) {
next(error);
}
})();
});

router.post("/", (req: Request, res: Response, next: NextFunction): void => {
void (async () => {
try {
const { projectId, organisationId } = req.body as {
projectId: number;
organisationId: number;
};

if (!projectId || !organisationId) {
res.status(400).json({
message: "projectId and organisationId are required",
});
return;
}

const existing = await prisma.projectOrganisation.findUnique({
where: {
projectId_organisationId: {
projectId,
organisationId,
},
},
});

if (existing) {
res.status(409).json({
message: "Relation already exists",
});
return;
}

const result = await prisma.projectOrganisation.create({
data: {
projectId,
organisationId,
},
});

res.status(201).json(result);
} catch (error) {
next(error);
}
})();
});

router.delete(
"/:projectId/:organisationId",
(req: Request, res: Response, next: NextFunction): void => {
void (async () => {
try {
const { projectId, organisationId } = req.params as {
projectId: string;
organisationId: string;
};

const result = await prisma.projectOrganisation.delete({
where: {
projectId_organisationId: {
projectId: Number(projectId),
organisationId: Number(organisationId),
},
},
});

res.json(result);
} catch (error) {
next(error);
}
})();
},
);

export default router;
Loading