@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contember/engine-content-api",
3
- "version": "1.1.0-alpha.3",
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.3",
14
- "@contember/dic": "^1.1.0-alpha.3",
15
- "@contember/engine-common": "^1.1.0-alpha.3",
16
- "@contember/graphql-utils": "^1.1.0-alpha.3",
17
- "@contember/schema": "^1.1.0-alpha.3",
18
- "@contember/schema-utils": "^1.1.0-alpha.3",
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.3",
24
- "@contember/engine-api-tester": "^1.1.0-alpha.3",
25
- "@contember/schema-definition": "^1.1.0-alpha.3",
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",
@@ -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.permissions[entity]?.operations[operation]?.[field]
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 permissions = this.authorizator.getFieldPermissions(Acl.Operation.read, entity.name, column.name)
18
- return column.nullable || permissions === 'maybe' ? basicType : new GraphQLNonNull(basicType)
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
+ }