Browse Source

refactor: move readonly props from meta to new cols for better stability

pull/8708/head
Pranav C 6 months ago
parent
commit
4561423226
  1. 2
      packages/nc-gui/components/dashboard/TreeView/CreateViewBtn.vue
  2. 18
      packages/nc-gui/components/dashboard/settings/data-sources/CreateBase.vue
  3. 28
      packages/nc-gui/components/dashboard/settings/data-sources/EditBase.vue
  4. 10
      packages/nc-gui/composables/useRoles/index.ts
  5. 2
      packages/nc-gui/lib/acl.ts
  6. 4
      packages/nocodb-sdk/src/lib/enums.ts
  7. 4
      packages/nocodb/src/meta/migrations/XcMigrationSourcev2.ts
  8. 18
      packages/nocodb/src/meta/migrations/v2/nc_051_source_readonly_columns.ts
  9. 8
      packages/nocodb/src/middlewares/extract-ids/extract-ids.middleware.ts
  10. 6
      packages/nocodb/src/models/Source.ts
  11. 8
      packages/nocodb/src/modules/jobs/jobs/export-import/duplicate.controller.ts
  12. 8
      packages/nocodb/src/schema/swagger-v2.json
  13. 8
      packages/nocodb/src/schema/swagger.json
  14. 6
      packages/nocodb/src/services/columns.service.ts
  15. 2
      packages/nocodb/src/services/forms.service.ts
  16. 2
      packages/nocodb/src/services/public-datas.service.ts
  17. 2
      packages/nocodb/src/utils/acl.ts

2
packages/nc-gui/components/dashboard/TreeView/CreateViewBtn.vue

@ -126,7 +126,7 @@ async function onOpenModal({
</div> </div>
</NcMenuItem> </NcMenuItem>
<NcMenuItem v-if="!source.meta?.[SourceRestriction.DATA_READONLY]" @click="onOpenModal({ type: ViewTypes.FORM })"> <NcMenuItem v-if="!source.is_schema_readonly" @click="onOpenModal({ type: ViewTypes.FORM })">
<div class="item" data-testid="sidebar-view-create-form"> <div class="item" data-testid="sidebar-view-create-form">
<div class="item-inner"> <div class="item-inner">
<GeneralViewIcon :meta="{ type: ViewTypes.FORM }" /> <GeneralViewIcon :meta="{ type: ViewTypes.FORM }" />

18
packages/nc-gui/components/dashboard/settings/data-sources/CreateBase.vue

@ -56,9 +56,8 @@ const formState = ref<ProjectCreateForm>({
}, },
sslUse: SSLUsage.No, sslUse: SSLUsage.No,
extraParameters: [], extraParameters: [],
meta: { 'is_schema_readonly': true,
[SourceRestriction.META_READONLY]: true, 'is_data_readonly': false,
[SourceRestriction.DATA_READONLY]: false,
}, },
}) })
@ -249,7 +248,8 @@ const createSource = async () => {
config, config,
inflection_column: formState.value.inflection.inflectionColumn, inflection_column: formState.value.inflection.inflectionColumn,
inflection_table: formState.value.inflection.inflectionTable, inflection_table: formState.value.inflection.inflectionTable,
meta: formState.value.meta, is_schema_readonly: formState.value.is_schema_readonly,
is_data_readonly: formState.value.is_data_readonly,
}) })
$poller.subscribe( $poller.subscribe(
@ -401,18 +401,16 @@ const toggleModal = (val: boolean) => {
} }
const allowMetaWrite = computed({ const allowMetaWrite = computed({
get: () => !formState.value.meta[SourceRestriction.META_READONLY], get: () => !formState.value.is_schema_readonly,
set: (v) => { set: (v) => {
formState.value.meta = formState.value.meta || {} formState.value.is_schema_readonly = !v
formState.value.meta[SourceRestriction.META_READONLY] = !v
}, },
}) })
const allowDataWrite = computed({ const allowDataWrite = computed({
get: () => !formState.value.meta[SourceRestriction.DATA_READONLY], get: () => !formState.value.is_data_readonly,
set: (v) => { set: (v) => {
formState.value.meta = formState.value.meta || {} formState.value.is_data_readonly = !v
formState.value.meta[SourceRestriction.DATA_READONLY] = !v
}, },
}) })
</script> </script>

28
packages/nc-gui/components/dashboard/settings/data-sources/EditBase.vue

@ -61,10 +61,8 @@ const formState = ref<ProjectCreateForm>({
}, },
sslUse: SSLUsage.No, sslUse: SSLUsage.No,
extraParameters: [], extraParameters: [],
meta: { is_schema_readonly: true,
[SourceRestriction.META_READONLY]: true, is_data_readonly: false,
[SourceRestriction.DATA_READONLY]: false,
},
}) })
const customFormState = ref<ProjectCreateForm>({ const customFormState = ref<ProjectCreateForm>({
@ -76,10 +74,8 @@ const customFormState = ref<ProjectCreateForm>({
}, },
sslUse: SSLUsage.No, sslUse: SSLUsage.No,
extraParameters: [], extraParameters: [],
meta: { is_schema_readonly: true,
[SourceRestriction.META_READONLY]: true, is_data_readonly: false,
[SourceRestriction.DATA_READONLY]: false,
},
}) })
const validators = computed(() => { const validators = computed(() => {
@ -237,7 +233,8 @@ const editBase = async () => {
config, config,
inflection_column: formState.value.inflection.inflectionColumn, inflection_column: formState.value.inflection.inflectionColumn,
inflection_table: formState.value.inflection.inflectionTable, inflection_table: formState.value.inflection.inflectionTable,
meta: formState.value.meta || {}, is_schema_readonly: formState.value.is_schema_readonly,
is_data_readonly: formState.value.is_data_readonly,
}) })
$e('a:source:edit:extdb') $e('a:source:edit:extdb')
@ -349,7 +346,8 @@ onMounted(async () => {
}, },
extraParameters: tempParameters, extraParameters: tempParameters,
sslUse: SSLUsage.No, sslUse: SSLUsage.No,
meta: activeBase.meta || {}, is_schema_readonly: activeBase.is_schema_readonly,
is_data_readonly: activeBase.is_data_readonly,
} }
updateSSLUse() updateSSLUse()
} }
@ -369,18 +367,16 @@ watch(
) )
const allowMetaWrite = computed({ const allowMetaWrite = computed({
get: () => !formState.value.meta[SourceRestriction.META_READONLY], get: () => !formState.value.is_schema_readonly,
set: (v) => { set: (v) => {
formState.value.meta = formState.value.meta || {} formState.value.is_schema_readonly = !v
formState.value.meta[SourceRestriction.META_READONLY] = !v
}, },
}) })
const allowDataWrite = computed({ const allowDataWrite = computed({
get: () => !formState.value.meta[SourceRestriction.DATA_READONLY], get: () => !formState.value.is_data_readonly,
set: (v) => { set: (v) => {
formState.value.meta = formState.value.meta || {} formState.value.is_data_readonly = !v
formState.value.meta[SourceRestriction.DATA_READONLY] = !v
}, },
}) })
</script> </script>

10
packages/nc-gui/composables/useRoles/index.ts

@ -150,7 +150,7 @@ export const useRolesShared = createSharedComposable(() => {
if ( if (
!args.skipSourceCheck && !args.skipSourceCheck &&
(sourceRestrictions[SourceRestriction.DATA_READONLY][permission] || (sourceRestrictions[SourceRestriction.DATA_READONLY][permission] ||
sourceRestrictions[SourceRestriction.META_READONLY][permission]) sourceRestrictions[SourceRestriction.SCHEMA_READONLY][permission])
) { ) {
const source = unref(args.source || null) const source = unref(args.source || null)
@ -159,10 +159,10 @@ export const useRolesShared = createSharedComposable(() => {
return false return false
} }
if (source?.meta?.[SourceRestriction.DATA_READONLY] && sourceRestrictions[SourceRestriction.DATA_READONLY][permission]) { if (source?.is_data_readonly && sourceRestrictions[SourceRestriction.DATA_READONLY][permission]) {
return false return false
} }
if (source?.meta?.[SourceRestriction.META_READONLY] && sourceRestrictions[SourceRestriction.META_READONLY][permission]) { if (source?.is_schema_readonly && sourceRestrictions[SourceRestriction.SCHEMA_READONLY][permission]) {
return false return false
} }
} }
@ -186,11 +186,11 @@ export const useRoles = () => {
const useRolesRes = useRolesShared() const useRolesRes = useRolesShared()
const isMetaReadOnly = computed(() => { const isMetaReadOnly = computed(() => {
return currentSource.value?.meta?.[SourceRestriction.META_READONLY] || false return currentSource.value?.is_schema_readonly || false
}) })
const isDataReadOnly = computed(() => { const isDataReadOnly = computed(() => {
return currentSource.value?.meta?.[SourceRestriction.DATA_READONLY] || false return currentSource.value?.is_schema_readonly || false
}) })
return { return {

2
packages/nc-gui/lib/acl.ts

@ -134,7 +134,7 @@ export const sourceRestrictions = {
duplicateModel: true, duplicateModel: true,
tableDuplicate: true, tableDuplicate: true,
}, },
[SourceRestriction.META_READONLY]: { [SourceRestriction.SCHEMA_READONLY]: {
tableCreate: true, tableCreate: true,
tableRename: true, tableRename: true,
tableDelete: true, tableDelete: true,

4
packages/nocodb-sdk/src/lib/enums.ts

@ -329,8 +329,8 @@ export enum APIContext {
export enum SourceRestriction { export enum SourceRestriction {
META_READONLY = 'metaReadOnly', SCHEMA_READONLY = 'is_schema_readonly',
DATA_READONLY = 'dataReadOnly', DATA_READONLY = 'is_data_readonly',
} }

4
packages/nocodb/src/meta/migrations/XcMigrationSourcev2.ts

@ -37,6 +37,7 @@ import * as nc_047_comment_migration from '~/meta/migrations/v2/nc_047_comment_m
import * as nc_048_view_links from '~/meta/migrations/v2/nc_048_view_links'; import * as nc_048_view_links from '~/meta/migrations/v2/nc_048_view_links';
import * as nc_049_clear_notifications from '~/meta/migrations/v2/nc_049_clear_notifications'; import * as nc_049_clear_notifications from '~/meta/migrations/v2/nc_049_clear_notifications';
import * as nc_050_tenant_isolation from '~/meta/migrations/v2/nc_050_tenant_isolation'; import * as nc_050_tenant_isolation from '~/meta/migrations/v2/nc_050_tenant_isolation';
import * as nc_051_source_readonly_columns from '~/meta/migrations/v2/nc_051_source_readonly_columns';
// Create a custom migration source class // Create a custom migration source class
export default class XcMigrationSourcev2 { export default class XcMigrationSourcev2 {
@ -85,6 +86,7 @@ export default class XcMigrationSourcev2 {
'nc_048_view_links', 'nc_048_view_links',
'nc_049_clear_notifications', 'nc_049_clear_notifications',
'nc_050_tenant_isolation', 'nc_050_tenant_isolation',
'nc_051_source_readonly_columns',
]); ]);
} }
@ -172,6 +174,8 @@ export default class XcMigrationSourcev2 {
return nc_049_clear_notifications; return nc_049_clear_notifications;
case 'nc_050_tenant_isolation': case 'nc_050_tenant_isolation':
return nc_050_tenant_isolation; return nc_050_tenant_isolation;
case 'nc_051_source_readonly_columns':
return nc_051_source_readonly_columns;
} }
} }
} }

18
packages/nocodb/src/meta/migrations/v2/nc_051_source_readonly_columns.ts

@ -0,0 +1,18 @@
import type { Knex } from 'knex';
import { MetaTable } from '~/utils/globals';
const up = async (knex: Knex) => {
await knex.schema.alterTable(MetaTable.BASES, (table) => {
table.boolean('is_schema_readonly').defaultTo(false);
table.boolean('is_data_readonly').defaultTo(false);
});
};
const down = async (knex: Knex) => {
await knex.schema.alterTable(MetaTable.BASES, (table) => {
table.dropColumn('is_schema_readonly');
table.dropColumn('is_data_readonly');
});
};
export { up, down };

8
packages/nocodb/src/middlewares/extract-ids/extract-ids.middleware.ts

@ -471,7 +471,7 @@ export class AclMiddleware implements NestInterceptor {
// 1. Check if it's present in the source restriction list // 1. Check if it's present in the source restriction list
// 2. If present, check if write permission is allowed // 2. If present, check if write permission is allowed
if ( if (
sourceRestrictions[SourceRestriction.META_READONLY][permissionName] || sourceRestrictions[SourceRestriction.SCHEMA_READONLY][permissionName] ||
sourceRestrictions[SourceRestriction.DATA_READONLY][permissionName] sourceRestrictions[SourceRestriction.DATA_READONLY][permissionName]
) { ) {
let source: Source; let source: Source;
@ -496,14 +496,14 @@ export class AclMiddleware implements NestInterceptor {
} }
if ( if (
source.meta?.[SourceRestriction.META_READONLY] && source.is_schema_readonly &&
sourceRestrictions[SourceRestriction.META_READONLY][permissionName] sourceRestrictions[SourceRestriction.SCHEMA_READONLY][permissionName]
) { ) {
NcError.sourceMetaReadOnly(source.alias); NcError.sourceMetaReadOnly(source.alias);
} }
if ( if (
source.meta?.[SourceRestriction.DATA_READONLY] && source.is_data_readonly &&
sourceRestrictions[SourceRestriction.DATA_READONLY][permissionName] sourceRestrictions[SourceRestriction.DATA_READONLY][permissionName]
) { ) {
NcError.sourceDataReadOnly(source.alias); NcError.sourceDataReadOnly(source.alias);

6
packages/nocodb/src/models/Source.ts

@ -33,6 +33,8 @@ export default class Source implements SourceType {
alias?: string; alias?: string;
type?: DriverClient; type?: DriverClient;
is_meta?: BoolType; is_meta?: BoolType;
is_schema_readonly?: BoolType;
is_data_readonly?: BoolType;
config?: string; config?: string;
inflection_column?: string; inflection_column?: string;
inflection_table?: string; inflection_table?: string;
@ -70,6 +72,8 @@ export default class Source implements SourceType {
'order', 'order',
'enabled', 'enabled',
'meta', 'meta',
'is_schema_readonly',
'is_data_readonly',
]); ]);
insertObj.config = CryptoJS.AES.encrypt( insertObj.config = CryptoJS.AES.encrypt(
@ -130,6 +134,8 @@ export default class Source implements SourceType {
'meta', 'meta',
'deleted', 'deleted',
'fk_sql_executor_id', 'fk_sql_executor_id',
'is_schema_readonly',
'is_data_readonly',
]); ]);
if (updateObj.config) { if (updateObj.config) {

8
packages/nocodb/src/modules/jobs/jobs/export-import/duplicate.controller.ts

@ -214,10 +214,10 @@ export class DuplicateController {
const source = await Source.get(context, model.source_id); const source = await Source.get(context, model.source_id);
// if data/schema is readonly, then restrict duplication // if data/schema is readonly, then restrict duplication
if (source.meta?.[SourceRestriction.META_READONLY]) { if (source.is_schema_readonly) {
NcError.sourceMetaReadOnly(source.alias); NcError.sourceMetaReadOnly(source.alias);
} }
if (source.meta?.[SourceRestriction.DATA_READONLY]) { if (source.is_data_readonly) {
NcError.sourceDataReadOnly(source.alias); NcError.sourceDataReadOnly(source.alias);
} }
@ -288,10 +288,10 @@ export class DuplicateController {
const source = await Source.get(context, model.source_id); const source = await Source.get(context, model.source_id);
// if data/schema is readonly, then restrict duplication // if data/schema is readonly, then restrict duplication
if (source.meta?.[SourceRestriction.META_READONLY]) { if (source.is_schema_readonly) {
NcError.sourceMetaReadOnly(source.alias); NcError.sourceMetaReadOnly(source.alias);
} }
if (source.meta?.[SourceRestriction.DATA_READONLY]) { if (source.is_data_readonly) {
NcError.sourceDataReadOnly(source.alias); NcError.sourceDataReadOnly(source.alias);
} }

8
packages/nocodb/src/schema/swagger-v2.json

@ -12166,6 +12166,14 @@
"$ref": "#/components/schemas/Bool", "$ref": "#/components/schemas/Bool",
"description": "Is the data source minimal db" "description": "Is the data source minimal db"
}, },
"is_schema_readonly": {
"$ref": "#/components/schemas/Bool",
"description": "Is the data source minimal db"
},
"is_data_readonly": {
"$ref": "#/components/schemas/Bool",
"description": "Is the data source minimal db"
},
"order": { "order": {
"description": "The order of the list of sources", "description": "The order of the list of sources",
"example": 1, "example": 1,

8
packages/nocodb/src/schema/swagger.json

@ -18215,6 +18215,14 @@
"$ref": "#/components/schemas/Bool", "$ref": "#/components/schemas/Bool",
"description": "Is the data source minimal db" "description": "Is the data source minimal db"
}, },
"is_schema_readonly": {
"$ref": "#/components/schemas/Bool",
"description": "Is the data source minimal db"
},
"is_data_readonly": {
"$ref": "#/components/schemas/Bool",
"description": "Is the data source minimal db"
},
"order": { "order": {
"description": "The order of the list of sources", "description": "The order of the list of sources",
"example": 1, "example": 1,

6
packages/nocodb/src/services/columns.service.ts

@ -201,7 +201,7 @@ export class ColumnsService {
// check if source is readonly and column type is not allowed // check if source is readonly and column type is not allowed
if ( if (
source?.meta?.[SourceRestriction.META_READONLY] && source?.is_schema_readonly &&
(!readonlyMetaAllowedTypes.includes(column.uidt) || (!readonlyMetaAllowedTypes.includes(column.uidt) ||
(param.column.uidt && (param.column.uidt &&
!readonlyMetaAllowedTypes.includes(param.column.uidt as UITypes))) !readonlyMetaAllowedTypes.includes(param.column.uidt as UITypes)))
@ -1496,7 +1496,7 @@ export class ColumnsService {
// check if source is readonly and column type is not allowed // check if source is readonly and column type is not allowed
if ( if (
source?.meta?.[SourceRestriction.META_READONLY] && source?.is_schema_readonly &&
!readonlyMetaAllowedTypes.includes(param.column.uidt as UITypes) !readonlyMetaAllowedTypes.includes(param.column.uidt as UITypes)
) { ) {
NcError.sourceMetaReadOnly(source.alias); NcError.sourceMetaReadOnly(source.alias);
@ -2064,7 +2064,7 @@ export class ColumnsService {
// check if source is readonly and column type is not allowed // check if source is readonly and column type is not allowed
if ( if (
source?.meta?.[SourceRestriction.META_READONLY] && source?.is_schema_readonly &&
!readonlyMetaAllowedTypes.includes(column.uidt) !readonlyMetaAllowedTypes.includes(column.uidt)
) { ) {
NcError.sourceMetaReadOnly(source.alias); NcError.sourceMetaReadOnly(source.alias);

2
packages/nocodb/src/services/forms.service.ts

@ -40,7 +40,7 @@ export class FormsService {
const source = await Source.get(context, model.source_id); const source = await Source.get(context, model.source_id);
if (source.meta?.[SourceRestriction.DATA_READONLY]) { if (source.is_data_readonly) {
NcError.sourceDataReadOnly(source.alias); NcError.sourceDataReadOnly(source.alias);
} }

2
packages/nocodb/src/services/public-datas.service.ts

@ -299,7 +299,7 @@ export class PublicDatasService {
const source = await Source.get(context, model.source_id); const source = await Source.get(context, model.source_id);
if (source?.meta?.[SourceRestriction.DATA_READONLY]) { if (source?.is_data_readonly) {
NcError.sourceDataReadOnly(source.alias); NcError.sourceDataReadOnly(source.alias);
} }

2
packages/nocodb/src/utils/acl.ts

@ -462,7 +462,7 @@ export const sourceRestrictions = {
jsonImport: true, jsonImport: true,
excelImport: true, excelImport: true,
}, },
[SourceRestriction.META_READONLY]: { [SourceRestriction.SCHEMA_READONLY]: {
tableCreate: true, tableCreate: true,
tableRename: true, tableRename: true,
tableDelete: true, tableDelete: true,

Loading…
Cancel
Save