@contember/schema-definition 2.0.0-beta.2 → 2.0.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/development/src/acl/builder/PermissionOverrider.cjs +7 -1
- package/dist/development/src/acl/builder/PermissionOverrider.cjs.map +1 -1
- package/dist/development/src/acl/builder/PermissionOverrider.js +7 -1
- package/dist/development/src/acl/builder/PermissionOverrider.js.map +1 -1
- package/dist/development/src/acl/definition/internal/AclFactory.cjs +22 -0
- package/dist/development/src/acl/definition/internal/AclFactory.cjs.map +1 -1
- package/dist/development/src/acl/definition/internal/AclFactory.js +22 -0
- package/dist/development/src/acl/definition/internal/AclFactory.js.map +1 -1
- package/dist/development/src/acl/definition/permissions.cjs.map +1 -1
- package/dist/development/src/acl/definition/permissions.js.map +1 -1
- package/dist/development/src/model/definition/internal/SchemaBuilder.cjs +20 -19
- package/dist/development/src/model/definition/internal/SchemaBuilder.cjs.map +1 -1
- package/dist/development/src/model/definition/internal/SchemaBuilder.js +20 -19
- package/dist/development/src/model/definition/internal/SchemaBuilder.js.map +1 -1
- package/dist/production/src/acl/builder/PermissionOverrider.cjs +7 -1
- package/dist/production/src/acl/builder/PermissionOverrider.cjs.map +1 -1
- package/dist/production/src/acl/builder/PermissionOverrider.js +7 -1
- package/dist/production/src/acl/builder/PermissionOverrider.js.map +1 -1
- package/dist/production/src/acl/definition/internal/AclFactory.cjs +22 -0
- package/dist/production/src/acl/definition/internal/AclFactory.cjs.map +1 -1
- package/dist/production/src/acl/definition/internal/AclFactory.js +22 -0
- package/dist/production/src/acl/definition/internal/AclFactory.js.map +1 -1
- package/dist/production/src/acl/definition/permissions.cjs.map +1 -1
- package/dist/production/src/acl/definition/permissions.js.map +1 -1
- package/dist/production/src/model/definition/internal/SchemaBuilder.cjs +20 -19
- package/dist/production/src/model/definition/internal/SchemaBuilder.cjs.map +1 -1
- package/dist/production/src/model/definition/internal/SchemaBuilder.js +20 -19
- package/dist/production/src/model/definition/internal/SchemaBuilder.js.map +1 -1
- package/dist/tests/tsconfig.tsbuildinfo +1 -1
- package/dist/types/acl/builder/PermissionOverrider.d.ts.map +1 -1
- package/dist/types/acl/definition/internal/AclFactory.d.ts +1 -0
- package/dist/types/acl/definition/internal/AclFactory.d.ts.map +1 -1
- package/dist/types/acl/definition/permissions.d.ts +1 -0
- package/dist/types/acl/definition/permissions.d.ts.map +1 -1
- package/dist/types/model/definition/internal/SchemaBuilder.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/acl/builder/PermissionOverrider.ts +6 -0
- package/src/acl/definition/internal/AclFactory.ts +30 -1
- package/src/acl/definition/permissions.ts +1 -0
- package/src/model/definition/internal/SchemaBuilder.ts +24 -21
- package/tests/cases/unit/readAclDefinitions.test.ts +76 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contember/schema-definition",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.4",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"main": "./dist/production/index.js",
|
|
6
6
|
"typings": "./dist/types/index.d.ts",
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
}
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@contember/schema": "2.0.0-beta.
|
|
27
|
-
"@contember/schema-utils": "2.0.0-beta.
|
|
26
|
+
"@contember/schema": "2.0.0-beta.4",
|
|
27
|
+
"@contember/schema-utils": "2.0.0-beta.4",
|
|
28
28
|
"reflect-metadata": "^0.2.2",
|
|
29
29
|
"fast-deep-equal": "^3.1.3"
|
|
30
30
|
},
|
|
@@ -33,6 +33,12 @@ export default class PermissionOverrider {
|
|
|
33
33
|
: {
|
|
34
34
|
customPrimary: overrides.operations.customPrimary ?? original.operations.customPrimary,
|
|
35
35
|
}),
|
|
36
|
+
...(original.operations.noRoot || overrides.operations.noRoot ? {
|
|
37
|
+
noRoot: [
|
|
38
|
+
...(original.operations.noRoot || []),
|
|
39
|
+
...(overrides.operations.noRoot || []),
|
|
40
|
+
],
|
|
41
|
+
} : {}),
|
|
36
42
|
},
|
|
37
43
|
}
|
|
38
44
|
}
|
|
@@ -53,7 +53,12 @@ export class AclFactory {
|
|
|
53
53
|
|
|
54
54
|
const predicatesResolver = EntityPredicatesResolver.create(rolePermissions, this.model, entity)
|
|
55
55
|
|
|
56
|
-
const entityOperations: Writable<Acl.EntityOperations> = {
|
|
56
|
+
const entityOperations: Writable<Acl.EntityOperations> = {
|
|
57
|
+
}
|
|
58
|
+
const noRootOptions = this.getNoRootOptions(entity, rolePermissions.get(entityName))
|
|
59
|
+
if (noRootOptions?.length) {
|
|
60
|
+
entityOperations.noRoot = noRootOptions
|
|
61
|
+
}
|
|
57
62
|
for (const op of ['create', 'update', 'read'] as const) {
|
|
58
63
|
const fieldPermissions: Writable<Acl.FieldPermissions> = {}
|
|
59
64
|
for (const field of Object.keys(entity.fields)) {
|
|
@@ -76,10 +81,34 @@ export class AclFactory {
|
|
|
76
81
|
return [entityName, {
|
|
77
82
|
predicates: predicatesResolver.getUsedPredicates(),
|
|
78
83
|
operations: entityOperations,
|
|
84
|
+
|
|
79
85
|
}]
|
|
80
86
|
}))
|
|
81
87
|
}
|
|
82
88
|
|
|
89
|
+
|
|
90
|
+
getNoRootOptions(entity: Model.Entity, permissions?: EntityPermissions): Acl.EntityOperations['noRoot'] {
|
|
91
|
+
const allowedRoot = new Set<Acl.Operation>()
|
|
92
|
+
const disallowedRoot = new Set<Acl.Operation>()
|
|
93
|
+
for (const def of permissions?.definitions ?? []) {
|
|
94
|
+
const noRoot = def.through === true
|
|
95
|
+
for (const op of ['create', 'read', 'update', 'delete'] as const) {
|
|
96
|
+
if (def[op]) {
|
|
97
|
+
const currentSet = noRoot ? disallowedRoot : allowedRoot
|
|
98
|
+
currentSet.add(op as Acl.Operation)
|
|
99
|
+
|
|
100
|
+
const otherSet = noRoot ? allowedRoot : disallowedRoot
|
|
101
|
+
|
|
102
|
+
if (otherSet.has(op as Acl.Operation)) {
|
|
103
|
+
throw new Error(`Operation ${op} cannot be both allowed and disallowed on root on entity ${entity.name}`)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
}
|
|
109
|
+
return [...disallowedRoot.values()]
|
|
110
|
+
}
|
|
111
|
+
|
|
83
112
|
private createVariables(role: Role, variables: VariableDefinition[]): Acl.Variables {
|
|
84
113
|
const roleVariables = variables.filter(it => it.roles.includes(role))
|
|
85
114
|
return Object.fromEntries(roleVariables.map((variable): [string, Acl.Variable] => {
|
|
@@ -40,32 +40,35 @@ export class SchemaBuilder {
|
|
|
40
40
|
|
|
41
41
|
const primaryName = this.conventions.getPrimaryField()
|
|
42
42
|
|
|
43
|
+
const fields: Model.Entity['fields'] = [
|
|
44
|
+
...definitionInstance[primaryName] ? [] : [tuple(primaryName, this.createPrimaryColumn())],
|
|
45
|
+
...Object.entries(definitionInstance),
|
|
46
|
+
]
|
|
47
|
+
.map(([name, definition]) => {
|
|
48
|
+
return definition.createField({
|
|
49
|
+
name,
|
|
50
|
+
entityName,
|
|
51
|
+
conventions: this.conventions,
|
|
52
|
+
enumRegistry: this.enumRegistry,
|
|
53
|
+
entityRegistry: this.entityRegistry,
|
|
54
|
+
strictDefinitionValidator: this.strictDefinitionValidator,
|
|
55
|
+
})
|
|
56
|
+
})
|
|
57
|
+
.reduce<Model.Entity['fields']>((acc, field) => {
|
|
58
|
+
if (acc[field.name]) {
|
|
59
|
+
throw new Error(`Entity ${entityName}: field ${field.name} is already registered`)
|
|
60
|
+
}
|
|
61
|
+
return { ...acc, [field.name]: field }
|
|
62
|
+
}, {})
|
|
63
|
+
|
|
64
|
+
|
|
43
65
|
const entity: Model.Entity = {
|
|
44
66
|
name: entityName,
|
|
45
67
|
primary: primaryName,
|
|
46
|
-
primaryColumn:
|
|
68
|
+
primaryColumn: (fields[primaryName] as Model.AnyColumn).columnName,
|
|
47
69
|
unique: this.createUnique(entityName, definitionInstance),
|
|
48
70
|
indexes: [],
|
|
49
|
-
fields:
|
|
50
|
-
...definitionInstance[primaryName] ? [] : [tuple(primaryName, this.createPrimaryColumn())],
|
|
51
|
-
...Object.entries(definitionInstance),
|
|
52
|
-
]
|
|
53
|
-
.map(([name, definition]) => {
|
|
54
|
-
return definition.createField({
|
|
55
|
-
name,
|
|
56
|
-
entityName,
|
|
57
|
-
conventions: this.conventions,
|
|
58
|
-
enumRegistry: this.enumRegistry,
|
|
59
|
-
entityRegistry: this.entityRegistry,
|
|
60
|
-
strictDefinitionValidator: this.strictDefinitionValidator,
|
|
61
|
-
})
|
|
62
|
-
})
|
|
63
|
-
.reduce<Model.Entity['fields']>((acc, field) => {
|
|
64
|
-
if (acc[field.name]) {
|
|
65
|
-
throw new Error(`Entity ${entityName}: field ${field.name} is already registered`)
|
|
66
|
-
}
|
|
67
|
-
return { ...acc, [field.name]: field }
|
|
68
|
-
}, {}),
|
|
71
|
+
fields: fields,
|
|
69
72
|
tableName: this.conventions.getTableName(entityName),
|
|
70
73
|
eventLog: {
|
|
71
74
|
enabled: true,
|
|
@@ -566,3 +566,79 @@ test('explicit ID predicate', () => {
|
|
|
566
566
|
'predicates': {},
|
|
567
567
|
})
|
|
568
568
|
})
|
|
569
|
+
|
|
570
|
+
namespace NoRoot {
|
|
571
|
+
export const publicRole = c.createRole('public')
|
|
572
|
+
|
|
573
|
+
@c.Allow(publicRole, {
|
|
574
|
+
read: ['id'],
|
|
575
|
+
})
|
|
576
|
+
@c.Allow(publicRole, {
|
|
577
|
+
when: { foo: { eq: 2 } },
|
|
578
|
+
through: true,
|
|
579
|
+
update: ['id'],
|
|
580
|
+
})
|
|
581
|
+
@c.Allow(publicRole, {
|
|
582
|
+
when: { foo: { eq: 1 } },
|
|
583
|
+
through: true,
|
|
584
|
+
update: ['id'],
|
|
585
|
+
})
|
|
586
|
+
export class Book {
|
|
587
|
+
title = c.stringColumn()
|
|
588
|
+
foo = c.intColumn()
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
test('no root - valid', () => {
|
|
593
|
+
const schema = createSchema(NoRoot)
|
|
594
|
+
expect(schema.acl.roles.public.entities.Book).toStrictEqual({
|
|
595
|
+
operations: {
|
|
596
|
+
noRoot: [Acl.Operation.update],
|
|
597
|
+
read: {
|
|
598
|
+
id: true,
|
|
599
|
+
},
|
|
600
|
+
update: {
|
|
601
|
+
id: 'or_foo_eq_1_foo_eq_2',
|
|
602
|
+
},
|
|
603
|
+
},
|
|
604
|
+
predicates: {
|
|
605
|
+
or_foo_eq_1_foo_eq_2: {
|
|
606
|
+
or: [
|
|
607
|
+
{
|
|
608
|
+
foo: {
|
|
609
|
+
eq: 1,
|
|
610
|
+
},
|
|
611
|
+
},
|
|
612
|
+
{
|
|
613
|
+
foo: {
|
|
614
|
+
eq: 2,
|
|
615
|
+
},
|
|
616
|
+
},
|
|
617
|
+
],
|
|
618
|
+
},
|
|
619
|
+
},
|
|
620
|
+
})
|
|
621
|
+
})
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
namespace NoRootInvalid {
|
|
625
|
+
export const publicRole = c.createRole('public')
|
|
626
|
+
|
|
627
|
+
@c.Allow(publicRole, {
|
|
628
|
+
when: { foo: { eq: 2 } },
|
|
629
|
+
through: true,
|
|
630
|
+
update: ['id'],
|
|
631
|
+
})
|
|
632
|
+
@c.Allow(publicRole, {
|
|
633
|
+
when: { foo: { eq: 1 } },
|
|
634
|
+
update: ['id'],
|
|
635
|
+
})
|
|
636
|
+
export class Book {
|
|
637
|
+
title = c.stringColumn()
|
|
638
|
+
foo = c.intColumn()
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
test('no root - invalid combo', () => {
|
|
643
|
+
expect(() => createSchema(NoRootInvalid)).toThrow('Operation update cannot be both allowed and disallowed on root on entity Book')
|
|
644
|
+
})
|