@@ -2,6 +2,7 @@ import { Algebra } from 'sparqlalgebrajs';
2
2
import type { Operation } from '../../http/Operation' ;
3
3
import type { Representation } from '../../http/representation/Representation' ;
4
4
import type { SparqlUpdatePatch } from '../../http/representation/SparqlUpdatePatch' ;
5
+ import type { ResourceSet } from '../../storage/ResourceSet' ;
5
6
import { NotImplementedHttpError } from '../../util/errors/NotImplementedHttpError' ;
6
7
import { ModesExtractor } from './ModesExtractor' ;
7
8
import { AccessMode } from './Permissions' ;
@@ -12,6 +13,18 @@ import { AccessMode } from './Permissions';
12
13
* while DELETEs require write permissions as well.
13
14
*/
14
15
export class SparqlUpdateModesExtractor extends ModesExtractor {
16
+ private readonly resourceSet : ResourceSet ;
17
+
18
+ /**
19
+ * Certain permissions depend on the existence of the target resource.
20
+ * The provided {@link ResourceSet} will be used for that.
21
+ * @param resourceSet - {@link ResourceSet} that can verify the target resource existence.
22
+ */
23
+ public constructor ( resourceSet : ResourceSet ) {
24
+ super ( ) ;
25
+ this . resourceSet = resourceSet ;
26
+ }
27
+
15
28
public async canHandle ( { body } : Operation ) : Promise < void > {
16
29
if ( ! this . isSparql ( body ) ) {
17
30
throw new NotImplementedHttpError ( 'Cannot determine permissions of non-SPARQL patches.' ) ;
@@ -21,21 +34,31 @@ export class SparqlUpdateModesExtractor extends ModesExtractor {
21
34
}
22
35
}
23
36
24
- public async handle ( { body } : Operation ) : Promise < Set < AccessMode > > {
37
+ public async handle ( { body, target } : Operation ) : Promise < Set < AccessMode > > {
25
38
// Verified in `canHandle` call
26
39
const update = ( body as SparqlUpdatePatch ) . algebra as Algebra . DeleteInsert ;
27
- const result = new Set < AccessMode > ( ) ;
40
+ const modes = new Set < AccessMode > ( ) ;
28
41
29
- // Since `append` is a specific type of write, it is true if `write` is true.
30
- if ( this . needsWrite ( update ) ) {
31
- result . add ( AccessMode . write ) ;
32
- result . add ( AccessMode . append ) ;
33
- result . add ( AccessMode . create ) ;
34
- result . add ( AccessMode . delete ) ;
35
- } else if ( this . needsAppend ( update ) ) {
36
- result . add ( AccessMode . append ) ;
42
+ if ( this . isNop ( update ) ) {
43
+ return modes ;
37
44
}
38
- return result ;
45
+
46
+ // Access modes inspired by the requirements on N3 Patch requests
47
+ if ( this . hasConditions ( update ) ) {
48
+ modes . add ( AccessMode . read ) ;
49
+ }
50
+ if ( this . hasInserts ( update ) ) {
51
+ modes . add ( AccessMode . append ) ;
52
+ if ( ! await this . resourceSet . hasResource ( target ) ) {
53
+ modes . add ( AccessMode . create ) ;
54
+ }
55
+ }
56
+ if ( this . hasDeletes ( update ) ) {
57
+ modes . add ( AccessMode . read ) ;
58
+ modes . add ( AccessMode . write ) ;
59
+ }
60
+
61
+ return modes ;
39
62
}
40
63
41
64
private isSparql ( data : Representation ) : data is SparqlUpdatePatch {
@@ -52,33 +75,32 @@ export class SparqlUpdateModesExtractor extends ModesExtractor {
52
75
return false ;
53
76
}
54
77
55
- private isDeleteInsert ( op : Algebra . Update ) : op is Algebra . DeleteInsert {
78
+ private isDeleteInsert ( op : Algebra . Operation ) : op is Algebra . DeleteInsert {
56
79
return op . type === Algebra . types . DELETE_INSERT ;
57
80
}
58
81
59
- private isNop ( op : Algebra . Update ) : op is Algebra . Nop {
82
+ private isNop ( op : Algebra . Operation ) : op is Algebra . Nop {
60
83
return op . type === Algebra . types . NOP ;
61
84
}
62
85
63
- private needsAppend ( update : Algebra . Update ) : boolean {
64
- if ( this . isNop ( update ) ) {
65
- return false ;
86
+ private hasConditions ( update : Algebra . Update ) : boolean {
87
+ if ( this . isDeleteInsert ( update ) ) {
88
+ return Boolean ( update . where && ! this . isNop ( update . where ) ) ;
66
89
}
90
+ return ( update as Algebra . CompositeUpdate ) . updates . some ( ( op ) : boolean => this . hasConditions ( op ) ) ;
91
+ }
92
+
93
+ private hasInserts ( update : Algebra . Update ) : boolean {
67
94
if ( this . isDeleteInsert ( update ) ) {
68
95
return Boolean ( update . insert && update . insert . length > 0 ) ;
69
96
}
70
-
71
- return ( update as Algebra . CompositeUpdate ) . updates . some ( ( op ) : boolean => this . needsAppend ( op ) ) ;
97
+ return ( update as Algebra . CompositeUpdate ) . updates . some ( ( op ) : boolean => this . hasInserts ( op ) ) ;
72
98
}
73
99
74
- private needsWrite ( update : Algebra . Update ) : boolean {
75
- if ( this . isNop ( update ) ) {
76
- return false ;
77
- }
100
+ private hasDeletes ( update : Algebra . Update ) : boolean {
78
101
if ( this . isDeleteInsert ( update ) ) {
79
102
return Boolean ( update . delete && update . delete . length > 0 ) ;
80
103
}
81
-
82
- return ( update as Algebra . CompositeUpdate ) . updates . some ( ( op ) : boolean => this . needsWrite ( op ) ) ;
104
+ return ( update as Algebra . CompositeUpdate ) . updates . some ( ( op ) : boolean => this . hasDeletes ( op ) ) ;
83
105
}
84
106
}
0 commit comments