[FEATURE] New Project Display (#1)
All checks were successful
S3 Repo Backup / s3-repo-backup (push) Successful in 45s
Deploy Edge / deploy-edge (push) Successful in 3m55s

Reviewed-on: https://forgejo.dunemask.dev///elysium/cairo/pulls/1
Co-authored-by: Dunemask <dunemask@gmail.com>
Co-committed-by: Dunemask <dunemask@gmail.com>
This commit is contained in:
Dunemask 2024-09-03 02:35:38 +00:00 committed by dunemask
parent c50c4ef647
commit a293eadbde
18 changed files with 247 additions and 45 deletions

View file

@ -31,4 +31,8 @@ export default class ProjectTableService extends TableService {
throw ProjectErrors.ConflictNonUnique;
});
}
async listChildren(parentProjectId: string) {
return this.pg.project.findMany({ where: { parentProject: parentProjectId } });
}
}

View file

@ -18,6 +18,8 @@ type CreateCRC = ContractRouteContext<{
RequestParamsContract: typeof ProjectContract.ProjectParams;
}>;
type ListCRC = ContractRouteContext<{ RequestParamsContract: typeof ProjectContract.ProjectParams }>;
export default class ProjectController extends VixpressController {
declare pg: PostgresService;
constructor(app: Express) {
@ -45,4 +47,13 @@ export default class ProjectController extends VixpressController {
const publicKey = await decrypt(kp.encryptedPublicKey, config.SigningOptions.Keys.KeyPair);
return { user: usr, project: proj, publicKey };
}
async list(crc: any): Promise<CProjectContract["ListProjects"]> {
const { project: parentProject } = crc.req as UserRequest;
const projectPromise = this.pg.project.byId(parentProject.id);
const childProjectsPromise = this.pg.project.listChildren(parentProject.id);
const [project, childProjects] = await Promise.all([projectPromise, childProjectsPromise]);
if (!project) throw ProjectErrors.NotFoundProject;
return { project, childProjects };
}
}

View file

@ -14,9 +14,11 @@ export class ProjectRoute extends VixpressRoute {
// Configuration
const projCreate = { ...cBase, reqBody: ProjectContract.Create };
const projList = { reqParams: ProjectContract.ProjectParams, resBody: ProjectContract.ListProjects };
// Middleware
// Routes
router.post("/create", RouteGuard.MangeProjectsCreate, contract(projController.create, projCreate));
router.get("/list", RouteGuard.ManageProjectsRead, contract(projController.list, projList));
}
}

View file

@ -3,14 +3,30 @@ import * as y from "yup";
import { DatabaseContract } from "./database.contracts";
// ====================================== Reused Contracts ======================================
const Project = y.object({
id: y.string().required(),
slug: y.string().required(),
parentProject: y.string().required(),
name: y.string().nullable(),
});
// ====================================== Response Contracts ======================================
export const ProjectContractRes = defineContractExport("CProjectContractRes", {
CreateResponse: y.object({
project: DatabaseContract.Project,
user: DatabaseContract.User,
publicKey: y.string().required(),
}),
CreateResponse: y
.object({
project: DatabaseContract.Project,
user: DatabaseContract.User,
publicKey: y.string().required(),
})
.required(),
Project: Project.required(),
ListProjects: y
.object({
project: Project.required(),
childProjects: y.array(Project).required(),
})
.required(),
});
// ====================================== Request Contracts ======================================

View file

@ -18,6 +18,7 @@ export class ProjectErrors {
static readonly BadRequestProjectIncomplete = new ClientError(400, "Project incomplete!");
static readonly UnexpectedRootUserError = new ClientError(500, "Error creating root user!");
static readonly ConflictNonUnique = new ClientError(409, "Slug already taken!");
static readonly NotFoundProject = new ClientError(404, "Project not found!");
}
export class KeyPairErrors {