diff --git a/libraries/grpc-sdk/src/classes/Routing/RouteBuilder.ts b/libraries/grpc-sdk/src/classes/Routing/RouteBuilder.ts index 3e2649fa0..8983aba14 100644 --- a/libraries/grpc-sdk/src/classes/Routing/RouteBuilder.ts +++ b/libraries/grpc-sdk/src/classes/Routing/RouteBuilder.ts @@ -36,7 +36,7 @@ export class RouteBuilder { if (!Array.isArray(middleware)) { middleware = [middleware]; } - if (this._options.middlewares?.length !== 0) { + if (this._options.middlewares !== undefined && this._options.middlewares?.length !== 0) { if (allowDuplicates) { this._options.middlewares?.concat(middleware); } else { diff --git a/modules/database/src/admin/admin.ts b/modules/database/src/admin/admin.ts index bd6213e0c..9ec56a121 100644 --- a/modules/database/src/admin/admin.ts +++ b/modules/database/src/admin/admin.ts @@ -155,8 +155,24 @@ export class AdminHandlers { fields: ConduitJson.Required, modelOptions: ConduitJson.Optional, enabled: ConduitBoolean.Optional, // move inside modelOptions (frontend-compat) - authentication: ConduitBoolean.Optional, // move inside modelOptions (frontend-compat) - crudOperations: ConduitBoolean.Optional, // move inside modelOptions (frontend-compat) + crudOperations: { + create: { + enabled: ConduitBoolean.Optional, + authenticated: ConduitBoolean.Required, + }, + read: { + enabled: ConduitBoolean.Optional, + authenticated: ConduitBoolean.Required, + }, + update: { + enabled: ConduitBoolean.Optional, + authenticated: ConduitBoolean.Required, + }, + delete: { + enabled: ConduitBoolean.Optional, + authenticated: ConduitBoolean.Required, + }, + }, permissions: { extendable: ConduitBoolean.Optional, canCreate: ConduitBoolean.Optional, @@ -180,8 +196,24 @@ export class AdminHandlers { fields: ConduitJson.Optional, modelOptions: ConduitJson.Optional, enabled: ConduitBoolean.Optional, // move inside modelOptions (frontend-compat) - authentication: ConduitBoolean.Optional, // move inside modelOptions (frontend-compat) - crudOperations: ConduitBoolean.Optional, // move inside modelOptions (frontend-compat) + crudOperations: { + create: { + enabled: ConduitBoolean.Optional, + authenticated: ConduitBoolean.Optional, + }, + read: { + enabled: ConduitBoolean.Optional, + authenticated: ConduitBoolean.Optional, + }, + update: { + enabled: ConduitBoolean.Optional, + authenticated: ConduitBoolean.Optional, + }, + delete: { + enabled: ConduitBoolean.Optional, + authenticated: ConduitBoolean.Optional, + }, + }, permissions: { extendable: ConduitBoolean.Optional, canCreate: ConduitBoolean.Optional, diff --git a/modules/database/src/admin/documents.admin.ts b/modules/database/src/admin/documents.admin.ts index bbdfacd65..edecfcf47 100644 --- a/modules/database/src/admin/documents.admin.ts +++ b/modules/database/src/admin/documents.admin.ts @@ -44,7 +44,6 @@ export class DocumentsAdmin { if (isNil(schema)) { throw new GrpcError(status.NOT_FOUND, 'Schema does not exist'); } - if (!query || query.length === '') { query = {}; } diff --git a/modules/database/src/admin/schema.admin.ts b/modules/database/src/admin/schema.admin.ts index b45b2d1be..6fe1fe50b 100644 --- a/modules/database/src/admin/schema.admin.ts +++ b/modules/database/src/admin/schema.admin.ts @@ -121,8 +121,7 @@ export class SchemaAdmin { permissions, } = call.request.params; const enabled = call.request.params.enabled ?? true; - const authentication = call.request.params.authentication ?? false; - const crudOperations = call.request.params.crudOperations ?? true; + const crudOperations = call.request.params.crudOperations; if (name.indexOf('-') >= 0 || name.indexOf(' ') >= 0) { throw new GrpcError( @@ -153,8 +152,8 @@ export class SchemaAdmin { }); const schemaOptions = isNil(modelOptions) - ? { conduit: { cms: { enabled, authentication, crudOperations } } } - : { ...modelOptions, conduit: { cms: { enabled, authentication, crudOperations } } }; + ? { conduit: { cms: { enabled, crudOperations } } } + : { ...modelOptions, conduit: { cms: { enabled, crudOperations } } }; schemaOptions.conduit.permissions = permissions; // database sets missing perms to defaults return this.schemaController @@ -168,12 +167,13 @@ export class SchemaAdmin { } async patchSchema(call: ParsedRouterRequest): Promise { - const { + let { id, name, fields, modelOptions, permissions, + crudOperations } = call.request.params; if (!isNil(name) && name !== '') { @@ -201,12 +201,11 @@ export class SchemaAdmin { requestedSchema.fields = fields ? fields : requestedSchema.fields; const enabled = call.request.params.enabled ?? requestedSchema.modelOptions.conduit.cms.enabled; - const authentication = call.request.params.authentication ?? requestedSchema.modelOptions.conduit.cms.authentication; - const crudOperations = call.request.params.crudOperations ?? requestedSchema.modelOptions.conduit.cms.crudOperations; + crudOperations = call.request.params.crudOperations ?? requestedSchema.modelOptions.conduit.cms.crudOperations; requestedSchema.modelOptions = merge( requestedSchema.modelOptions, modelOptions, - { conduit: { cms: { enabled, authentication, crudOperations } } }, + { conduit: { cms: { enabled, crudOperations } } }, ); diff --git a/modules/database/src/controllers/cms/utils.ts b/modules/database/src/controllers/cms/utils.ts index 989c472d8..74d9191d3 100644 --- a/modules/database/src/controllers/cms/utils.ts +++ b/modules/database/src/controllers/cms/utils.ts @@ -64,20 +64,22 @@ function removeRequiredFields(fields: any) { export function getOps(schemaName: string, actualSchema: any, handlers: CmsHandlers) { let routesArray: any = []; + const authenticatedRead = actualSchema.modelOptions.conduit.cms.crudOperations.read.authenticated; + const readIsEnabled = actualSchema.modelOptions.conduit.cms.crudOperations.read.enabled; let route = new RouteBuilder() .path(`/${schemaName}/:id`) .method(ConduitRouteActions.GET) .urlParams({ id: { type: TYPE.String, required: true }, - }).cacheControl(actualSchema.authentication + }).cacheControl(authenticatedRead ? 'private, max-age=10' : 'public, max-age=10') .return(`${schemaName}`, actualSchema.fields) .handler(handlers.getDocumentById.bind(handlers)); - if (actualSchema.authentication) { + if (authenticatedRead) route.middleware('authMiddleware'); - } - routesArray.push(route.build()); + if (readIsEnabled) + routesArray.push(route.build()); route = new RouteBuilder() .path(`/${schemaName}`) @@ -87,7 +89,7 @@ export function getOps(schemaName: string, actualSchema: any, handlers: CmsHandl limit: TYPE.Number, sort: [TYPE.String], }) - .cacheControl(actualSchema.authentication + .cacheControl(authenticatedRead ? 'private, max-age=10' : 'public, max-age=10') .return(`get${schemaName}`, { @@ -95,10 +97,11 @@ export function getOps(schemaName: string, actualSchema: any, handlers: CmsHandl count: TYPE.Number, }) .handler(handlers.getDocuments.bind(handlers)); - if (actualSchema.authentication) { + if (authenticatedRead) { route.middleware('authMiddleware'); } - routesArray.push(route.build()); + if (readIsEnabled) + routesArray.push(route.build()); let assignableFields = Object.assign({}, actualSchema.fields); delete assignableFields._id; @@ -110,10 +113,13 @@ export function getOps(schemaName: string, actualSchema: any, handlers: CmsHandl .bodyParams(assignableFields) .return(`create${schemaName}`, actualSchema.fields) .handler(handlers.createDocument.bind(handlers)); - if (actualSchema.authentication) { + const authenticatedCreate = actualSchema.modelOptions.conduit.cms.crudOperations.create.authenticated; + const createIsEnabled = actualSchema.modelOptions.conduit.cms.crudOperations.create.enabled; + if (authenticatedCreate) { route.middleware('authMiddleware'); } - routesArray.push(route.build()); + if (createIsEnabled) + routesArray.push(route.build()); route = new RouteBuilder() .path(`/${schemaName}/many`) @@ -123,10 +129,11 @@ export function getOps(schemaName: string, actualSchema: any, handlers: CmsHandl docs: [actualSchema.fields], }) .handler(handlers.createManyDocuments.bind(handlers)); - if (actualSchema.authentication) { + if (authenticatedCreate) { route.middleware('authMiddleware'); } - routesArray.push(route.build()); + if (createIsEnabled) + routesArray.push(route.build()); route = new RouteBuilder() .path(`/${schemaName}/many`) @@ -141,10 +148,13 @@ export function getOps(schemaName: string, actualSchema: any, handlers: CmsHandl docs: [actualSchema.fields], }) .handler(handlers.updateManyDocuments.bind(handlers)); - if (actualSchema.authentication) { + const authenticatedUpdate = actualSchema.modelOptions.conduit.cms.crudOperations.update.authenticated; + const updateIsEnabled = actualSchema.modelOptions.conduit.cms.crudOperations.update.enabled; + if (authenticatedUpdate) { route.middleware('authMiddleware'); } - routesArray.push(route.build()); + if (updateIsEnabled) + routesArray.push(route.build()); route = new RouteBuilder() .path(`/${schemaName}/many`) @@ -164,10 +174,11 @@ export function getOps(schemaName: string, actualSchema: any, handlers: CmsHandl docs: [actualSchema.fields], }) .handler(handlers.patchManyDocuments.bind(handlers)); - if (actualSchema.authentication) { + if (authenticatedUpdate) { route.middleware('authMiddleware'); } - routesArray.push(route.build()); + if (updateIsEnabled) + routesArray.push(route.build()); route = new RouteBuilder() .path(`/${schemaName}/:id`) @@ -178,7 +189,7 @@ export function getOps(schemaName: string, actualSchema: any, handlers: CmsHandl .bodyParams(assignableFields) .return(`update${schemaName}`, actualSchema.fields) .handler(handlers.updateDocument.bind(handlers)); - if (actualSchema.authentication) { + if (authenticatedUpdate) { route.middleware('authMiddleware'); } routesArray.push(route.build()); @@ -192,10 +203,11 @@ export function getOps(schemaName: string, actualSchema: any, handlers: CmsHandl .bodyParams(removeRequiredFields(Object.assign({}, assignableFields))) .return(`patch${schemaName}`, actualSchema.fields) .handler(handlers.patchDocument.bind(handlers)); - if (actualSchema.authentication) { + if (authenticatedUpdate) { route.middleware('authMiddleware'); } - routesArray.push(route.build()); + if (updateIsEnabled) + routesArray.push(route.build()); route = new RouteBuilder() .path(`/${schemaName}/:id`) .method(ConduitRouteActions.DELETE) @@ -204,10 +216,13 @@ export function getOps(schemaName: string, actualSchema: any, handlers: CmsHandl }) .return(`delete${schemaName}`, TYPE.String) .handler(handlers.deleteDocument.bind(handlers)); - if (actualSchema.authentication) { + const authenticatedDelete = actualSchema.modelOptions.conduit.cms.crudOperations.delete.authenticated; + const deleteIsEnabled = actualSchema.modelOptions.conduit.cms.crudOperations.delete.enabled; + if (authenticatedDelete) { route.middleware('authMiddleware'); } - routesArray.push(route.build()); + if (deleteIsEnabled) + routesArray.push(route.build()); return routesArray; } diff --git a/modules/database/src/migrations/crudOperations.migration.ts b/modules/database/src/migrations/crudOperations.migration.ts new file mode 100644 index 000000000..8cb9856da --- /dev/null +++ b/modules/database/src/migrations/crudOperations.migration.ts @@ -0,0 +1,40 @@ +import { DatabaseAdapter } from '../adapters/DatabaseAdapter'; +import { MongooseSchema } from '../adapters/mongoose-adapter/MongooseSchema'; +import { SequelizeSchema } from '../adapters/sequelize-adapter/SequelizeSchema'; + +export async function migrateCrudOperations(adapter: DatabaseAdapter) { + const model = adapter.getSchemaModel('_DeclaredSchema').model; + const cmsSchemas = await model + .findMany({ 'modelOptions.conduit.cms.enabled': { $exists: true } }); + + for (const schema of cmsSchemas) { + const { crudOperations, authentication, enabled } = schema.modelOptions.conduit.cms; + const cms = { + enabled: enabled, + crudOperations: { + create: { + enabled: crudOperations, + authenticated: authentication, + }, + read: { + enabled: crudOperations, + authenticated: authentication, + }, + update: { + enabled: crudOperations, + authenticated: authentication, + }, + delete: { + enabled: crudOperations, + authenticated: authentication, + }, + }, + }; + const id = (schema._id).toString() + await model.findByIdAndUpdate(id,{ + modelOptions: { + conduit: { cms } + }, + }); + } +} diff --git a/modules/database/src/migrations/index.ts b/modules/database/src/migrations/index.ts index bae0f064c..8931363ae 100644 --- a/modules/database/src/migrations/index.ts +++ b/modules/database/src/migrations/index.ts @@ -1,7 +1,8 @@ import { DatabaseAdapter } from '../adapters/DatabaseAdapter'; import { MongooseSchema } from '../adapters/mongoose-adapter/MongooseSchema'; import { SequelizeSchema } from '../adapters/sequelize-adapter/SequelizeSchema'; +import { migrateCrudOperations } from './crudOperations.migration'; export async function runMigrations(adapter: DatabaseAdapter){ - // ... + await migrateCrudOperations(adapter); }