diff --git a/packages/nocodb/src/lib/controllers/projectApis.ts b/packages/nocodb/src/lib/controllers/projectApis.ts index e69de29bb2..18d761efb1 100644 --- a/packages/nocodb/src/lib/controllers/projectApis.ts +++ b/packages/nocodb/src/lib/controllers/projectApis.ts @@ -0,0 +1,169 @@ +import { Request, Response } from 'express'; +import { ProjectType } from 'nocodb-sdk'; +import Project from '../models/Project'; +import { ProjectListType } from 'nocodb-sdk'; +import { packageVersion } from '../utils/packageVersion'; +import { T } from 'nc-help'; +import { PagedResponseImpl } from '../meta/helpers/PagedResponse'; +import NcConnectionMgrv2 from '../utils/common/NcConnectionMgrv2'; +import ncMetaAclMw from '../meta/helpers/ncMetaAclMw'; +import ProjectUser from '../models/ProjectUser'; +import Noco from '../Noco'; +import isDocker from 'is-docker'; +import { metaApiMetrics } from '../meta/helpers/apiMetrics'; +import Filter from '../models/Filter'; + +import { projectService } from '../services'; + +// // Project CRUD + +export async function projectGet( + req: Request, + res: Response +) { + const project = await projectService.getProjectWithInfo({ + projectId: req.params.projectId, + }); + + projectService.sanitizeProject(project); + + res.json(project); +} + +export async function projectUpdate( + req: Request, + res: Response +) { + const project = await projectService.projectUpdate({ + projectId: req.params.projectId, + project: req.body, + }); + + res.json(project); +} + +export async function projectList( + req: Request & { user: { id: string; roles: string } }, + res: Response +) { + const projects = await projectService.projectList({ + user: req.user, + query: req.query, + }); + + res.json( + new PagedResponseImpl(projects as ProjectType[], { + count: projects.length, + limit: projects.length, + }) + ); +} + +export async function projectDelete(req: Request, res: Response) { + const deleted = await projectService.projectSoftDelete({ + projectId: req.params.projectId, + }); + + res.json(deleted); +} + +async function projectCreate(req: Request, res) { + const project = await projectService.projectCreate({ + project: req.body, + user: req['user'], + }); + + res.json(project); +} + +export async function projectInfoGet(_req, res) { + res.json({ + Node: process.version, + Arch: process.arch, + Platform: process.platform, + Docker: isDocker(), + RootDB: Noco.getConfig()?.meta?.db?.client, + PackageVersion: packageVersion, + }); +} + +export async function projectCost(req, res) { + let cost = 0; + const project = await Project.getWithInfo(req.params.projectId); + + for (const base of project.bases) { + const sqlClient = await NcConnectionMgrv2.getSqlClient(base); + const userCount = await ProjectUser.getUsersCount(req.query); + const recordCount = (await sqlClient.totalRecords())?.data.TotalRecords; + + if (recordCount > 100000) { + // 36,000 or $79/user/month + cost = Math.max(36000, 948 * userCount); + } else if (recordCount > 50000) { + // $36,000 or $50/user/month + cost = Math.max(36000, 600 * userCount); + } else if (recordCount > 10000) { + // $240/user/yr + cost = Math.min(240 * userCount, 36000); + } else if (recordCount > 1000) { + // $120/user/yr + cost = Math.min(120 * userCount, 36000); + } + } + + T.event({ + event: 'a:project:cost', + data: { + cost, + }, + }); + + res.json({ cost }); +} + +export async function hasEmptyOrNullFilters(req, res) { + res.json(await Filter.hasEmptyOrNullFilters(req.params.projectId)); +} + +export default (router) => { + router.get( + '/api/v1/db/meta/projects/:projectId/info', + metaApiMetrics, + ncMetaAclMw(projectInfoGet, 'projectInfoGet') + ); + router.get( + '/api/v1/db/meta/projects/:projectId', + metaApiMetrics, + ncMetaAclMw(projectGet, 'projectGet') + ); + router.patch( + '/api/v1/db/meta/projects/:projectId', + metaApiMetrics, + ncMetaAclMw(projectUpdate, 'projectUpdate') + ); + router.get( + '/api/v1/db/meta/projects/:projectId/cost', + metaApiMetrics, + ncMetaAclMw(projectCost, 'projectCost') + ); + router.delete( + '/api/v1/db/meta/projects/:projectId', + metaApiMetrics, + ncMetaAclMw(projectDelete, 'projectDelete') + ); + router.post( + '/api/v1/db/meta/projects', + metaApiMetrics, + ncMetaAclMw(projectCreate, 'projectCreate') + ); + router.get( + '/api/v1/db/meta/projects', + metaApiMetrics, + ncMetaAclMw(projectList, 'projectList') + ); + router.get( + '/api/v1/db/meta/projects/:projectId/has-empty-or-null-filters', + metaApiMetrics, + ncMetaAclMw(hasEmptyOrNullFilters, 'hasEmptyOrNullFilters') + ); +}; diff --git a/packages/nocodb/src/lib/controllers/tableApis.ts b/packages/nocodb/src/lib/controllers/tableApis.ts index e69de29bb2..c59c8d4a13 100644 --- a/packages/nocodb/src/lib/controllers/tableApis.ts +++ b/packages/nocodb/src/lib/controllers/tableApis.ts @@ -0,0 +1,111 @@ +import { Request, Response, Router } from 'express'; +import { TableListType, TableReqType, TableType } from 'nocodb-sdk'; +import { metaApiMetrics } from '../meta/helpers/apiMetrics'; +import ncMetaAclMw from '../meta/helpers/ncMetaAclMw'; +import { PagedResponseImpl } from '../meta/helpers/PagedResponse'; +import { tableService } from '../services'; + +export async function tableList(req: Request, res: Response) { + res.json( + new PagedResponseImpl( + await tableService.getAccessibleTables({ + projectId: req.params.projectId, + baseId: req.params.baseId, + includeM2M: req.query?.includeM2M === 'true', + roles: (req as any).session?.passport?.user?.roles, + }) + ) + ); +} + +export async function tableCreate(req: Request, res) { + const result = await tableService.tableCreate({ + projectId: req.params.projectId, + baseId: req.params.baseId, + table: req.body, + user: (req as any).session?.passport?.user, + }); + + res.json(result); +} + +export async function tableGet(req: Request, res: Response) { + const table = await tableService.getTableWithAccessibleViews({ + tableId: req.params.tableId, + user: (req as any).session?.passport?.user, + }); + + res.json(table); +} + +export async function tableDelete(req: Request, res: Response) { + const result = await tableService.tableDelete({ + tableId: req.params.tableId, + user: (req as any).session?.passport?.user, + req, + }); + + res.json(result); +} + +export async function tableReorder(req: Request, res: Response) { + res.json( + await tableService.reorderTable({ + tableId: req.params.tableId, + order: req.body.order, + }) + ); +} + +// todo: move to table service +export async function tableUpdate(req: Request, res) { + await tableService.tableUpdate({ + tableId: req.params.tableId, + table: req.body, + projectId: (req as any).ncProjectId, + }); + res.json({ msg: 'success' }); +} + +const router = Router({ mergeParams: true }); +router.get( + '/api/v1/db/meta/projects/:projectId/tables', + metaApiMetrics, + ncMetaAclMw(tableList, 'tableList') +); +router.get( + '/api/v1/db/meta/projects/:projectId/:baseId/tables', + metaApiMetrics, + ncMetaAclMw(tableList, 'tableList') +); +router.post( + '/api/v1/db/meta/projects/:projectId/tables', + metaApiMetrics, + ncMetaAclMw(tableCreate, 'tableCreate') +); +router.post( + '/api/v1/db/meta/projects/:projectId/:baseId/tables', + metaApiMetrics, + ncMetaAclMw(tableCreate, 'tableCreate') +); +router.get( + '/api/v1/db/meta/tables/:tableId', + metaApiMetrics, + ncMetaAclMw(tableGet, 'tableGet') +); +router.patch( + '/api/v1/db/meta/tables/:tableId', + metaApiMetrics, + ncMetaAclMw(tableUpdate, 'tableUpdate') +); +router.delete( + '/api/v1/db/meta/tables/:tableId', + metaApiMetrics, + ncMetaAclMw(tableDelete, 'tableDelete') +); +router.post( + '/api/v1/db/meta/tables/:tableId/reorder', + metaApiMetrics, + ncMetaAclMw(tableReorder, 'tableReorder') +); +export default router;