@contember/engine-content-api 1.1.0-alpha.3 → 1.1.0-alpha.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/src/acl/Authorizator.d.ts +1 -0
- package/dist/src/acl/Authorizator.d.ts.map +1 -1
- package/dist/src/acl/Authorizator.js +5 -2
- package/dist/src/acl/Authorizator.js.map +1 -1
- package/dist/src/schema/entities/FieldTypeVisitor.d.ts.map +1 -1
- package/dist/src/schema/entities/FieldTypeVisitor.js +10 -2
- package/dist/src/schema/entities/FieldTypeVisitor.js.map +1 -1
- package/dist/src/tsconfig.tsbuildinfo +1 -1
- package/dist/tests/cases/integration/graphQlSchema/graphQlSchemaBuilder.test.js +23 -1
- package/dist/tests/cases/integration/graphQlSchema/graphQlSchemaBuilder.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlSchema/schema-acl-predicate2.gql +110 -0
- package/dist/tests/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -10
- package/src/acl/Authorizator.ts +5 -1
- package/src/schema/entities/FieldTypeVisitor.ts +10 -2
- package/tests/cases/integration/graphQlSchema/graphQlSchemaBuilder.test.ts +28 -1
- package/tests/cases/integration/graphQlSchema/schema-acl-predicate2.gql +110 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contember/engine-content-api",
|
|
3
|
-
"version": "1.1.0-alpha.
|
|
3
|
+
"version": "1.1.0-alpha.4",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"typings": "dist/src/index.d.ts",
|
|
@@ -10,19 +10,19 @@
|
|
|
10
10
|
"test": "uvu dist/tests/cases/ \\.js$"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@contember/database": "^1.1.0-alpha.
|
|
14
|
-
"@contember/dic": "^1.1.0-alpha.
|
|
15
|
-
"@contember/engine-common": "^1.1.0-alpha.
|
|
16
|
-
"@contember/graphql-utils": "^1.1.0-alpha.
|
|
17
|
-
"@contember/schema": "^1.1.0-alpha.
|
|
18
|
-
"@contember/schema-utils": "^1.1.0-alpha.
|
|
13
|
+
"@contember/database": "^1.1.0-alpha.4",
|
|
14
|
+
"@contember/dic": "^1.1.0-alpha.4",
|
|
15
|
+
"@contember/engine-common": "^1.1.0-alpha.4",
|
|
16
|
+
"@contember/graphql-utils": "^1.1.0-alpha.4",
|
|
17
|
+
"@contember/schema": "^1.1.0-alpha.4",
|
|
18
|
+
"@contember/schema-utils": "^1.1.0-alpha.4",
|
|
19
19
|
"@graphql-tools/schema": "^7.1.5",
|
|
20
20
|
"graphql-tag": "^2.12.5"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
|
-
"@contember/database-tester": "^1.1.0-alpha.
|
|
24
|
-
"@contember/engine-api-tester": "^1.1.0-alpha.
|
|
25
|
-
"@contember/schema-definition": "^1.1.0-alpha.
|
|
23
|
+
"@contember/database-tester": "^1.1.0-alpha.4",
|
|
24
|
+
"@contember/engine-api-tester": "^1.1.0-alpha.4",
|
|
25
|
+
"@contember/schema-definition": "^1.1.0-alpha.4",
|
|
26
26
|
"@graphql-codegen/cli": "^1.15.2",
|
|
27
27
|
"@graphql-codegen/typescript": "^1.15.2",
|
|
28
28
|
"@graphql-codegen/typescript-operations": "^1.15.2",
|
package/src/acl/Authorizator.ts
CHANGED
|
@@ -23,8 +23,12 @@ export class Authorizator {
|
|
|
23
23
|
return Object.values(fieldPermissions).filter(it => !!it).length > 0 ? 'yes' : 'no'
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
getFieldPredicate(operation: Acl.Operation.create | Acl.Operation.read | Acl.Operation.update, entity: string, field: string): Acl.Predicate {
|
|
27
|
+
return this.permissions[entity]?.operations[operation]?.[field] ?? false
|
|
28
|
+
}
|
|
29
|
+
|
|
26
30
|
getFieldPermissions(operation: Acl.Operation.create | Acl.Operation.read | Acl.Operation.update, entity: string, field: string): AuthorizationResult {
|
|
27
|
-
const fieldPermissions = this.
|
|
31
|
+
const fieldPermissions = this.getFieldPredicate(operation, entity, field)
|
|
28
32
|
if (!fieldPermissions) {
|
|
29
33
|
return 'no'
|
|
30
34
|
}
|
|
@@ -3,6 +3,7 @@ import { Acl, Model } from '@contember/schema'
|
|
|
3
3
|
import { ColumnTypeResolver } from '../ColumnTypeResolver'
|
|
4
4
|
import { EntityTypeProvider } from '../EntityTypeProvider'
|
|
5
5
|
import { Authorizator } from '../../acl'
|
|
6
|
+
import { ImplementationException } from '../../exception'
|
|
6
7
|
|
|
7
8
|
export class FieldTypeVisitor implements Model.ColumnVisitor<GraphQLOutputType>, Model.RelationByGenericTypeVisitor<GraphQLOutputType> {
|
|
8
9
|
constructor(
|
|
@@ -14,8 +15,15 @@ export class FieldTypeVisitor implements Model.ColumnVisitor<GraphQLOutputType>,
|
|
|
14
15
|
|
|
15
16
|
public visitColumn(entity: Model.Entity, column: Model.AnyColumn): GraphQLOutputType {
|
|
16
17
|
const basicType = this.columnTypeResolver.getType(column)
|
|
17
|
-
const
|
|
18
|
-
|
|
18
|
+
const fieldPredicate = this.authorizator.getFieldPredicate(Acl.Operation.read, entity.name, column.name)
|
|
19
|
+
const idPredicate = this.authorizator.getFieldPredicate(Acl.Operation.read, entity.name, entity.primary)
|
|
20
|
+
if (!fieldPredicate || !idPredicate) {
|
|
21
|
+
throw new ImplementationException()
|
|
22
|
+
}
|
|
23
|
+
if (!column.nullable && (fieldPredicate === true || fieldPredicate === idPredicate)) {
|
|
24
|
+
return new GraphQLNonNull(basicType)
|
|
25
|
+
}
|
|
26
|
+
return basicType
|
|
19
27
|
}
|
|
20
28
|
|
|
21
29
|
public visitHasMany(entity: Model.Entity, relation: Model.Relation): GraphQLOutputType {
|
|
@@ -112,7 +112,7 @@ graphqlSchemaBuilderTest('restricted access to fields by permissions', async ()
|
|
|
112
112
|
})
|
|
113
113
|
|
|
114
114
|
|
|
115
|
-
graphqlSchemaBuilderTest('conditionally restricted read', async () => {
|
|
115
|
+
graphqlSchemaBuilderTest('conditionally restricted read of some fields', async () => {
|
|
116
116
|
await testSchema({
|
|
117
117
|
schema: builder =>
|
|
118
118
|
builder.entity('Test', e =>
|
|
@@ -138,6 +138,33 @@ graphqlSchemaBuilderTest('conditionally restricted read', async () => {
|
|
|
138
138
|
})
|
|
139
139
|
})
|
|
140
140
|
|
|
141
|
+
|
|
142
|
+
graphqlSchemaBuilderTest('conditionally restricted read of whole row', async () => {
|
|
143
|
+
await testSchema({
|
|
144
|
+
schema: builder =>
|
|
145
|
+
builder.entity('Test', e =>
|
|
146
|
+
e
|
|
147
|
+
.column('a', c => c.type(Model.ColumnType.String).notNull()),
|
|
148
|
+
),
|
|
149
|
+
permissions: () => ({
|
|
150
|
+
Test: {
|
|
151
|
+
predicates: {
|
|
152
|
+
testPredicate: {
|
|
153
|
+
a: { eq: 'Foo' },
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
operations: {
|
|
157
|
+
read: {
|
|
158
|
+
id: 'testPredicate',
|
|
159
|
+
a: 'testPredicate',
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
}),
|
|
164
|
+
graphQlSchemaFile: 'schema-acl-predicate2.gql',
|
|
165
|
+
})
|
|
166
|
+
})
|
|
167
|
+
|
|
141
168
|
const oneHasManySchema = (builder: SchemaBuilder) =>
|
|
142
169
|
builder.entity('Root', e =>
|
|
143
170
|
e
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
type Query {
|
|
2
|
+
getTest(by: TestUniqueWhere!, filter: TestWhere): Test
|
|
3
|
+
listTest(filter: TestWhere, orderBy: [TestOrderBy!], offset: Int, limit: Int): [Test!]!
|
|
4
|
+
paginateTest(filter: TestWhere, orderBy: [TestOrderBy!], skip: Int, first: Int): TestConnection!
|
|
5
|
+
transaction: QueryTransaction
|
|
6
|
+
_info: Info
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
type Test {
|
|
10
|
+
_meta: TestMeta
|
|
11
|
+
id: UUID!
|
|
12
|
+
a: String!
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type TestMeta {
|
|
16
|
+
id: FieldMeta
|
|
17
|
+
a: FieldMeta
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type FieldMeta {
|
|
21
|
+
readable: Boolean
|
|
22
|
+
updatable: Boolean
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
scalar UUID
|
|
26
|
+
|
|
27
|
+
input TestUniqueWhere {
|
|
28
|
+
id: UUID
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
input TestWhere {
|
|
32
|
+
id: UUIDCondition
|
|
33
|
+
a: StringCondition
|
|
34
|
+
and: [TestWhere]
|
|
35
|
+
or: [TestWhere]
|
|
36
|
+
not: TestWhere
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
input UUIDCondition {
|
|
40
|
+
and: [UUIDCondition!]
|
|
41
|
+
or: [UUIDCondition!]
|
|
42
|
+
not: UUIDCondition
|
|
43
|
+
null: Boolean
|
|
44
|
+
isNull: Boolean
|
|
45
|
+
eq: UUID
|
|
46
|
+
notEq: UUID
|
|
47
|
+
in: [UUID!]
|
|
48
|
+
notIn: [UUID!]
|
|
49
|
+
lt: UUID
|
|
50
|
+
lte: UUID
|
|
51
|
+
gt: UUID
|
|
52
|
+
gte: UUID
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
input StringCondition {
|
|
56
|
+
and: [StringCondition!]
|
|
57
|
+
or: [StringCondition!]
|
|
58
|
+
not: StringCondition
|
|
59
|
+
null: Boolean
|
|
60
|
+
isNull: Boolean
|
|
61
|
+
eq: String
|
|
62
|
+
notEq: String
|
|
63
|
+
in: [String!]
|
|
64
|
+
notIn: [String!]
|
|
65
|
+
lt: String
|
|
66
|
+
lte: String
|
|
67
|
+
gt: String
|
|
68
|
+
gte: String
|
|
69
|
+
contains: String
|
|
70
|
+
startsWith: String
|
|
71
|
+
endsWith: String
|
|
72
|
+
containsCI: String
|
|
73
|
+
startsWithCI: String
|
|
74
|
+
endsWithCI: String
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
input TestOrderBy {
|
|
78
|
+
_random: Boolean
|
|
79
|
+
_randomSeeded: Int
|
|
80
|
+
id: OrderDirection
|
|
81
|
+
a: OrderDirection
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
enum OrderDirection {
|
|
85
|
+
asc
|
|
86
|
+
desc
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
type TestConnection {
|
|
90
|
+
pageInfo: PageInfo!
|
|
91
|
+
edges: [TestEdge!]!
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
type PageInfo {
|
|
95
|
+
totalCount: Int!
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
type TestEdge {
|
|
99
|
+
node: Test!
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
type QueryTransaction {
|
|
103
|
+
getTest(by: TestUniqueWhere!, filter: TestWhere): Test
|
|
104
|
+
listTest(filter: TestWhere, orderBy: [TestOrderBy!], offset: Int, limit: Int): [Test!]!
|
|
105
|
+
paginateTest(filter: TestWhere, orderBy: [TestOrderBy!], skip: Int, first: Int): TestConnection!
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
type Info {
|
|
109
|
+
description: String
|
|
110
|
+
}
|