mirror of https://github.com/nocodb/nocodb
Pranav C
2 years ago
16 changed files with 757 additions and 355 deletions
@ -0,0 +1,36 @@
|
||||
export { default as ApiToken } from './ApiToken'; |
||||
export { default as Audit } from './Audit'; |
||||
export { default as BarcodeColumn } from './BarcodeColumn'; |
||||
export { default as Base } from './Base'; |
||||
export { default as Column } from './Column'; |
||||
export { default as Filter } from './Filter'; |
||||
export { default as FormulaColumn } from './FormulaColumn'; |
||||
export { default as FormView } from './FormView'; |
||||
export { default as FormViewColumn } from './FormViewColumn'; |
||||
export { default as GalleryView } from './GalleryView'; |
||||
export { default as GalleryViewColumn } from './GalleryViewColumn'; |
||||
export { default as GridView } from './GridView'; |
||||
export { default as GridViewColumn } from './GridViewColumn'; |
||||
export { default as Hook } from './Hook'; |
||||
export { default as HookFilter } from './HookFilter'; |
||||
export { default as HookLog } from './HookLog'; |
||||
export { default as KanbanView } from './KanbanView'; |
||||
export { default as KanbanViewColumn } from './KanbanViewColumn'; |
||||
export { default as LinkToAnotherRecordColumn } from './LinkToAnotherRecordColumn'; |
||||
export { default as LookupColumn } from './LookupColumn'; |
||||
export { default as MapView } from './MapView'; |
||||
export { default as MapViewColumn } from './MapViewColumn'; |
||||
export { default as Model } from './Model'; |
||||
export { default as ModelRoleVisibility } from './ModelRoleVisibility'; |
||||
export { default as Plugin } from './Plugin'; |
||||
export { default as Project } from './Project'; |
||||
export { default as ProjectUser } from './ProjectUser'; |
||||
export { default as QrCodeColumn } from './QrCodeColumn'; |
||||
export { default as RollupColumn } from './RollupColumn'; |
||||
export { default as SelectOption } from './SelectOption'; |
||||
export { default as Sort } from './Sort'; |
||||
export { default as Store } from './Store'; |
||||
export { default as SyncLogs } from './SyncLogs'; |
||||
export { default as SyncSource } from './SyncSource'; |
||||
export { default as User } from './User'; |
||||
export { default as View } from './View'; |
@ -0,0 +1,30 @@
|
||||
import { ApiTokenReqType, OrgUserRoles } from 'nocodb-sdk'; |
||||
import { Tele } from 'nc-help'; |
||||
import { NcError } from '../meta/helpers/catchError'; |
||||
import ApiToken from '../models/ApiToken'; |
||||
import User from '../models/User'; |
||||
|
||||
export async function apiTokenList(param: { userId: string }) { |
||||
return ApiToken.list(param.userId); |
||||
} |
||||
export async function apiTokenCreate(param: { |
||||
userId: string; |
||||
tokenBody: ApiTokenReqType; |
||||
}) { |
||||
Tele.emit('evt', { evt_type: 'apiToken:created' }); |
||||
return ApiToken.insert({ ...param.tokenBody, fk_user_id: param.userId }); |
||||
} |
||||
|
||||
export async function apiTokenDelete(param: { token; user: User }) { |
||||
const apiToken = await ApiToken.getByToken(param.token); |
||||
if ( |
||||
!param.user.roles.includes(OrgUserRoles.SUPER_ADMIN) && |
||||
apiToken.fk_user_id !== param.user.id |
||||
) { |
||||
NcError.notFound('Token not found'); |
||||
} |
||||
Tele.emit('evt', { evt_type: 'apiToken:deleted' }); |
||||
|
||||
// todo: verify token belongs to the user
|
||||
return await ApiToken.delete(param.token); |
||||
} |
@ -0,0 +1,78 @@
|
||||
import Project from '../models/Project'; |
||||
import { BaseReqType } from 'nocodb-sdk'; |
||||
import { syncBaseMigration } from '../meta/helpers/syncMigration'; |
||||
import Base from '../models/Base'; |
||||
import { Tele } from 'nc-help'; |
||||
import { populateMeta } from '../meta/api/helpers'; |
||||
|
||||
export async function baseGetWithConfig(param: { baseId: any }) { |
||||
const base = await Base.get(param.baseId); |
||||
|
||||
base.config = base.getConnectionConfig(); |
||||
|
||||
return base; |
||||
} |
||||
|
||||
export async function baseUpdate(param: { |
||||
baseId: string; |
||||
base: BaseReqType; |
||||
projectId: string; |
||||
}) { |
||||
const baseBody = param.base; |
||||
const project = await Project.getWithInfo(param.projectId); |
||||
const base = await Base.updateBase(param.baseId, { |
||||
...baseBody, |
||||
type: baseBody.config?.client, |
||||
projectId: project.id, |
||||
id: param.baseId, |
||||
}); |
||||
|
||||
delete base.config; |
||||
|
||||
Tele.emit('evt', { |
||||
evt_type: 'base:updated', |
||||
}); |
||||
|
||||
return base; |
||||
} |
||||
|
||||
export async function baseList(param: { projectId: string }) { |
||||
const bases = await Base.list({ projectId: param.projectId }); |
||||
|
||||
return bases; |
||||
} |
||||
|
||||
export async function baseDelete(param: { baseId: string }) { |
||||
const base = await Base.get(param.baseId); |
||||
await base.delete(); |
||||
Tele.emit('evt', { evt_type: 'base:deleted' }); |
||||
return true; |
||||
} |
||||
|
||||
export async function baseCreate(param: { |
||||
projectId: string; |
||||
base: BaseReqType; |
||||
}) { |
||||
// type | base | projectId
|
||||
const baseBody = param.base; |
||||
const project = await Project.getWithInfo(param.projectId); |
||||
const base = await Base.createBase({ |
||||
...baseBody, |
||||
type: baseBody.config?.client, |
||||
projectId: project.id, |
||||
}); |
||||
|
||||
await syncBaseMigration(project, base); |
||||
|
||||
const info = await populateMeta(base, project); |
||||
|
||||
Tele.emit('evt_api_created', info); |
||||
|
||||
delete base.config; |
||||
|
||||
Tele.emit('evt', { |
||||
evt_type: 'base:created', |
||||
}); |
||||
|
||||
return base; |
||||
} |
@ -0,0 +1,123 @@
|
||||
import { Tele } from 'nc-help'; |
||||
import catchError from '../helpers/catchError'; |
||||
import { Request, Response, Router } from 'express'; |
||||
import { Hook, Model } from '../models'; |
||||
import { HookListType, HookReqType, HookTestReqType, HookType, TableReqType } from 'nocodb-sdk' |
||||
import { PagedResponseImpl } from '../helpers/PagedResponse'; |
||||
import { invokeWebhook } from '../helpers/webhookHelpers'; |
||||
import populateSamplePayload from '../helpers/populateSamplePayload'; |
||||
import ncMetaAclMw from '../helpers/ncMetaAclMw'; |
||||
import { metaApiMetrics } from '../helpers/apiMetrics'; |
||||
import { getAjvValidatorMw } from './helpers'; |
||||
|
||||
export async function hookList( |
||||
param: { |
||||
tableId: string; |
||||
} |
||||
) { |
||||
// todo: pagination
|
||||
await Hook.list({ fk_model_id: param.tableId })) |
||||
} |
||||
|
||||
export async function hookCreate( |
||||
param: { |
||||
tableId: string; |
||||
hook: HookReqType |
||||
} |
||||
) { |
||||
Tele.emit('evt', { evt_type: 'webhooks:created' }); |
||||
const hook = await Hook.insert({ |
||||
...param.hook, |
||||
fk_model_id: param.tableId, |
||||
}); |
||||
return hook; |
||||
} |
||||
|
||||
export async function hookDelete( |
||||
param :{ |
||||
hookId: string; |
||||
} |
||||
) { |
||||
Tele.emit('evt', { evt_type: 'webhooks:deleted' }); |
||||
await Hook.delete(param.hookId); |
||||
return true; |
||||
} |
||||
|
||||
export async function hookUpdate( |
||||
param: { |
||||
hookId: string; |
||||
hook: HookReqType; |
||||
} |
||||
) { |
||||
Tele.emit('evt', { evt_type: 'webhooks:updated' }); |
||||
|
||||
return await Hook.update(param.hookId, param.hook) |
||||
} |
||||
|
||||
export async function hookTest(param: { |
||||
tableId: string; |
||||
hookTest: HookTestReqType; |
||||
}) { |
||||
const model = await Model.getByIdOrName({ id: param.tableId }); |
||||
|
||||
const { |
||||
hook, |
||||
payload: { data, user }, |
||||
} = param.hookTest; |
||||
await invokeWebhook( |
||||
new Hook(hook), |
||||
model, |
||||
data, |
||||
user, |
||||
(hook as any)?.filters, |
||||
true |
||||
); |
||||
|
||||
Tele.emit('evt', { evt_type: 'webhooks:tested' }); |
||||
|
||||
return true |
||||
} |
||||
export async function tableSampleData(param:{ |
||||
tableId: string; |
||||
operation: 'insert' | 'update'; |
||||
}) { |
||||
const model = await Model.getByIdOrName({ id: param.tableId }); |
||||
|
||||
return await populateSamplePayload(model, false, param.operation); |
||||
} |
||||
|
||||
const router = Router({ mergeParams: true }); |
||||
router.get( |
||||
'/api/v1/db/meta/tables/:tableId/hooks', |
||||
metaApiMetrics, |
||||
ncMetaAclMw(hookList, 'hookList') |
||||
); |
||||
router.post( |
||||
'/api/v1/db/meta/tables/:tableId/hooks/test', |
||||
metaApiMetrics, |
||||
getAjvValidatorMw('swagger.json#/components/schemas/HookTestReq'), |
||||
ncMetaAclMw(hookTest, 'hookTest') |
||||
); |
||||
router.post( |
||||
'/api/v1/db/meta/tables/:tableId/hooks', |
||||
metaApiMetrics, |
||||
getAjvValidatorMw('swagger.json#/components/schemas/HookReq'), |
||||
ncMetaAclMw(hookCreate, 'hookCreate') |
||||
); |
||||
router.delete( |
||||
'/api/v1/db/meta/hooks/:hookId', |
||||
metaApiMetrics, |
||||
ncMetaAclMw(hookDelete, 'hookDelete') |
||||
); |
||||
router.patch( |
||||
'/api/v1/db/meta/hooks/:hookId', |
||||
metaApiMetrics, |
||||
getAjvValidatorMw('swagger.json#/components/schemas/HookReq'), |
||||
ncMetaAclMw(hookUpdate, 'hookUpdate') |
||||
); |
||||
router.get( |
||||
'/api/v1/db/meta/tables/:tableId/hooks/samplePayload/:operation', |
||||
metaApiMetrics, |
||||
catchError(tableSampleData) |
||||
); |
||||
export default router; |
@ -1,4 +1,8 @@
|
||||
// export * as projectService from './projectService';
|
||||
export * as projectService from './projectService'; |
||||
export * as tableService from './tableService'; |
||||
export * as columnService from './columnService'; |
||||
export * as filterService from './filterService'; |
||||
export * as sortService from './sortService'; |
||||
export * as baseService from './baseService'; |
||||
export * as apiTokenService from './apiTokenService'; |
||||
export * as viewService from './viewService'; |
||||
|
@ -1,42 +1,169 @@
|
||||
// // services/project.service.ts
|
||||
// import { OrgUserRoles, ProjectType } from 'nocodb-sdk'
|
||||
// import Project from '../models/Project'
|
||||
// import ProjectUser from '../models/ProjectUser'
|
||||
// import { customAlphabet } from 'nanoid'
|
||||
// import { NcError } from './helpers/catchError'
|
||||
//
|
||||
// const nanoid = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyz_', 4)
|
||||
//
|
||||
// export async function getProjectWithInfo(projectId: string) {
|
||||
// const project = await Project.getWithInfo(projectId)
|
||||
// return project
|
||||
// }
|
||||
//
|
||||
// export function sanitizeProject(project: any) {
|
||||
// const sanitizedProject = { ...project }
|
||||
// sanitizedProject.bases?.forEach((b: any) => {
|
||||
// ['config'].forEach((k) => delete b[k])
|
||||
// })
|
||||
// return sanitizedProject
|
||||
// }
|
||||
//
|
||||
// export async function updateProject(projectId: string, data: Partial<ProjectType>) {
|
||||
// const project = await Project.getWithInfo(projectId)
|
||||
// if (data?.title && project.title !== data.title && (await Project.getByTitle(data.title))) {
|
||||
// NcError.badRequest('Project title already in use')
|
||||
// }
|
||||
// const result = await Project.update(projectId, data)
|
||||
// return result
|
||||
// }
|
||||
//
|
||||
// export async function listProjects(user: any) {
|
||||
// const projects = user?.roles?.includes(OrgUserRoles.SUPER_ADMIN)
|
||||
// ? await Project.list()
|
||||
// : await ProjectUser.getProjectsList(user.id)
|
||||
// return projects as ProjectType[]
|
||||
// }
|
||||
//
|
||||
// export async function softDeleteProject(projectId: string) {
|
||||
// const result = await Project.softDelete(projectId)
|
||||
// return result
|
||||
// }
|
||||
import DOMPurify from 'isomorphic-dompurify'; |
||||
import { OrgUserRoles, ProjectReqType, } from 'nocodb-sdk'; |
||||
import { promisify } from 'util'; |
||||
import { populateMeta } from '../meta/api/helpers'; |
||||
import { extractPropsAndSanitize } from '../meta/helpers/extractProps'; |
||||
import syncMigration from '../meta/helpers/syncMigration'; |
||||
import Project from '../models/Project'; |
||||
import ProjectUser from '../models/ProjectUser'; |
||||
import { customAlphabet } from 'nanoid'; |
||||
import Noco from '../Noco'; |
||||
import NcConfigFactory from '../utils/NcConfigFactory'; |
||||
import { NcError } from '../meta/helpers/catchError'; |
||||
|
||||
export async function projectCreate(param: { |
||||
project: ProjectReqType; |
||||
user: any; |
||||
}) { |
||||
const projectBody: ProjectReqType & Record<string, any> = param.project; |
||||
if (!projectBody.external) { |
||||
const ranId = nanoid(); |
||||
projectBody.prefix = `nc_${ranId}__`; |
||||
projectBody.is_meta = true; |
||||
if (process.env.NC_MINIMAL_DBS) { |
||||
// if env variable NC_MINIMAL_DBS is set, then create a SQLite file/connection for each project
|
||||
// each file will be named as nc_<random_id>.db
|
||||
const fs = require('fs'); |
||||
const toolDir = NcConfigFactory.getToolDir(); |
||||
const nanoidv2 = customAlphabet( |
||||
'1234567890abcdefghijklmnopqrstuvwxyz', |
||||
14 |
||||
); |
||||
if (!(await promisify(fs.exists)(`${toolDir}/nc_minimal_dbs`))) { |
||||
await promisify(fs.mkdir)(`${toolDir}/nc_minimal_dbs`); |
||||
} |
||||
const dbId = nanoidv2(); |
||||
const projectTitle = DOMPurify.sanitize(projectBody.title); |
||||
projectBody.prefix = ''; |
||||
projectBody.bases = [ |
||||
{ |
||||
type: 'sqlite3', |
||||
config: { |
||||
client: 'sqlite3', |
||||
connection: { |
||||
client: 'sqlite3', |
||||
database: projectTitle, |
||||
connection: { |
||||
filename: `${toolDir}/nc_minimal_dbs/${projectTitle}_${dbId}.db`, |
||||
}, |
||||
}, |
||||
}, |
||||
inflection_column: 'camelize', |
||||
inflection_table: 'camelize', |
||||
}, |
||||
]; |
||||
} else { |
||||
const db = Noco.getConfig().meta?.db; |
||||
projectBody.bases = [ |
||||
{ |
||||
type: db?.client, |
||||
config: null, |
||||
is_meta: true, |
||||
inflection_column: 'camelize', |
||||
inflection_table: 'camelize', |
||||
}, |
||||
]; |
||||
} |
||||
} else { |
||||
if (process.env.NC_CONNECT_TO_EXTERNAL_DB_DISABLED) { |
||||
NcError.badRequest('Connecting to external db is disabled'); |
||||
} |
||||
projectBody.is_meta = false; |
||||
} |
||||
|
||||
if (projectBody?.title.length > 50) { |
||||
NcError.badRequest('Project title exceeds 50 characters'); |
||||
} |
||||
|
||||
if (await Project.getByTitle(projectBody?.title)) { |
||||
NcError.badRequest('Project title already in use'); |
||||
} |
||||
|
||||
projectBody.title = DOMPurify.sanitize(projectBody.title); |
||||
projectBody.slug = projectBody.title; |
||||
|
||||
const project = await Project.createProject(projectBody); |
||||
await ProjectUser.insert({ |
||||
fk_user_id: (param as any).user.id, |
||||
project_id: project.id, |
||||
roles: 'owner', |
||||
}); |
||||
|
||||
await syncMigration(project); |
||||
|
||||
// populate metadata if existing table
|
||||
for (const base of await project.getBases()) { |
||||
const info = await populateMeta(base, project); |
||||
|
||||
Tele.emit('evt_api_created', info); |
||||
delete base.config; |
||||
} |
||||
|
||||
Tele.emit('evt', { |
||||
evt_type: 'project:created', |
||||
xcdb: !projectBody.external, |
||||
}); |
||||
|
||||
Tele.emit('evt', { evt_type: 'project:rest' }); |
||||
|
||||
project; |
||||
} |
||||
|
||||
const nanoid = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyz_', 4); |
||||
|
||||
import { Tele } from 'nc-help'; |
||||
|
||||
export async function getProjectWithInfo(param: { projectId: string }) { |
||||
const project = await Project.getWithInfo(param.projectId); |
||||
return project; |
||||
} |
||||
|
||||
export async function projectSoftDelete(param: { projectId: any }) { |
||||
await Project.softDelete(param.projectId); |
||||
Tele.emit('evt', { evt_type: 'project:deleted' }); |
||||
return true; |
||||
} |
||||
|
||||
export function sanitizeProject(project: any) { |
||||
const sanitizedProject = { ...project }; |
||||
sanitizedProject.bases?.forEach((b: any) => { |
||||
['config'].forEach((k) => delete b[k]); |
||||
}); |
||||
return sanitizedProject; |
||||
} |
||||
|
||||
export async function projectUpdate(param: { |
||||
projectId: string; |
||||
project: ProjectReqType; |
||||
}) { |
||||
const project = await Project.getWithInfo(param.projectId); |
||||
|
||||
const data: Partial<Project> = extractPropsAndSanitize( |
||||
param?.project as Project, |
||||
['title', 'meta', 'color'] |
||||
); |
||||
|
||||
if ( |
||||
data?.title && |
||||
project.title !== data.title && |
||||
(await Project.getByTitle(data.title)) |
||||
) { |
||||
NcError.badRequest('Project title already in use'); |
||||
} |
||||
|
||||
const result = await Project.update(param.projectId, data); |
||||
Tele.emit('evt', { evt_type: 'project:update' }); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
export async function projectList(param: { |
||||
user: { id: string; roles: string }; |
||||
query?: any; |
||||
}) { |
||||
const projects = param.user?.roles?.includes(OrgUserRoles.SUPER_ADMIN) |
||||
? await Project.list(param.query) |
||||
: await ProjectUser.getProjectsList(param.user.id, param.query); |
||||
|
||||
return projects; |
||||
} |
||||
|
@ -0,0 +1,33 @@
|
||||
import { SortReqType } from 'nocodb-sdk'; |
||||
import Sort from '../models/Sort'; |
||||
import { Tele } from 'nc-help'; |
||||
|
||||
export async function sortGet(param: { sortId: string }) { |
||||
return Sort.get(param.sortId); |
||||
} |
||||
|
||||
|
||||
export async function sortDelete(param: { sortId: string }) { |
||||
await Sort.delete(param.sortId); |
||||
Tele.emit('evt', { evt_type: 'sort:deleted' }); |
||||
return true; |
||||
} |
||||
|
||||
export async function sortUpdate(param: { sortId: any; sort: SortReqType }) { |
||||
const sort = await Sort.update(param.sortId, param.sort); |
||||
Tele.emit('evt', { evt_type: 'sort:updated' }); |
||||
return sort; |
||||
} |
||||
|
||||
export async function sortCreate(param: { viewId: any; sort: SortReqType }) { |
||||
const sort = await Sort.insert({ |
||||
...param.sort, |
||||
fk_view_id: param.viewId, |
||||
} as Sort); |
||||
Tele.emit('evt', { evt_type: 'sort:created' }); |
||||
return sort; |
||||
} |
||||
|
||||
export async function sortList(param: { viewId: string }) { |
||||
return Sort.list({ viewId: param.viewId }); |
||||
} |
@ -0,0 +1,85 @@
|
||||
import { Model, View } from '../models'; |
||||
import { Tele } from 'nc-help'; |
||||
import { SharedViewReqType, ViewReqType } from 'nocodb-sdk'; |
||||
import { xcVisibilityMetaGet } from '../meta/api/modelVisibilityApis'; |
||||
|
||||
|
||||
export async function viewList(param: { |
||||
tableId: string; |
||||
user: { |
||||
roles: Record<string, boolean>; |
||||
}; |
||||
}) { |
||||
const model = await Model.get(param.tableId); |
||||
|
||||
const viewList = await xcVisibilityMetaGet( |
||||
// param.projectId,
|
||||
// param.baseId,
|
||||
model.project_id, |
||||
[model] |
||||
); |
||||
|
||||
// todo: user roles
|
||||
//await View.list(param.tableId)
|
||||
const filteredViewList = viewList.filter((view: any) => { |
||||
return Object.keys(param?.user?.roles).some( |
||||
(role) => param?.user?.roles[role] && !view.disabled[role] |
||||
); |
||||
}); |
||||
|
||||
return filteredViewList; |
||||
} |
||||
|
||||
// @ts-ignore
|
||||
export async function shareView(param: { viewId: string }) { |
||||
Tele.emit('evt', { evt_type: 'sharedView:generated-link' }); |
||||
return await View.share(param.viewId); |
||||
} |
||||
|
||||
// @ts-ignore
|
||||
export async function viewUpdate(param: { viewId: string; view: ViewReqType }) { |
||||
const result = await View.update(param.viewId, param.view); |
||||
Tele.emit('evt', { evt_type: 'vtable:updated', show_as: result.type }); |
||||
return result; |
||||
} |
||||
|
||||
// @ts-ignore
|
||||
export async function viewDelete(param: { viewId: string }) { |
||||
await View.delete(param.viewId); |
||||
Tele.emit('evt', { evt_type: 'vtable:deleted' }); |
||||
return true; |
||||
} |
||||
|
||||
export async function shareViewUpdate(param: { |
||||
viewId: string; |
||||
sharedView: SharedViewReqType; |
||||
}) { |
||||
Tele.emit('evt', { evt_type: 'sharedView:updated' }); |
||||
return await View.update(param.viewId, param.sharedView); |
||||
} |
||||
|
||||
export async function shareViewDelete(param: { viewId: string }) { |
||||
Tele.emit('evt', { evt_type: 'sharedView:deleted' }); |
||||
await View.sharedViewDelete(param.viewId); |
||||
return true; |
||||
} |
||||
|
||||
export async function showAllColumns(param: { |
||||
viewId: string; |
||||
ignoreIds?: string[]; |
||||
}) { |
||||
await View.showAllColumns(param.viewId, param.ignoreIds || []); |
||||
return true; |
||||
} |
||||
|
||||
export async function hideAllColumns(param: { |
||||
viewId: string; |
||||
ignoreIds?: string[]; |
||||
}) { |
||||
await View.hideAllColumns(param.viewId, param.ignoreIds || []); |
||||
return true; |
||||
} |
||||
|
||||
export async function shareViewList(param: { tableId: string }) { |
||||
return await View.shareViewList(param.tableId); |
||||
} |
Loading…
Reference in new issue