oldaplib 0.3.29__py3-none-any.whl → 0.4.0__py3-none-any.whl
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.
- oldaplib/ontologies/admin-testing.trig +62 -11
- oldaplib/ontologies/admin.trig +12 -51
- oldaplib/ontologies/gaga.trigs +23 -0
- oldaplib/ontologies/oldap.trig +138 -62
- oldaplib/src/connection.py +39 -34
- oldaplib/src/enums/adminpermissions.py +1 -1
- oldaplib/src/enums/datapermissions.py +20 -3
- oldaplib/src/enums/{permissionsetattr.py → roleattr.py} +2 -3
- oldaplib/src/enums/userattr.py +3 -2
- oldaplib/src/helpers/observable_dict.py +1 -0
- oldaplib/src/in_project.py +0 -1
- oldaplib/src/objectfactory.py +348 -105
- oldaplib/src/propertyclass.py +1 -1
- oldaplib/src/resourceclass.py +13 -2
- oldaplib/src/{permissionset.py → role.py} +90 -112
- oldaplib/src/user.py +176 -97
- oldaplib/src/userdataclass.py +67 -38
- oldaplib/src/version.py +1 -1
- oldaplib/test/test_datamodel.py +5 -2
- oldaplib/test/test_in_project.py +21 -20
- oldaplib/test/test_objectfactory.py +100 -34
- oldaplib/test/test_resourceclass.py +3 -3
- oldaplib/test/test_role.py +407 -0
- oldaplib/test/test_user.py +158 -98
- oldaplib/testdata/instances_test.trig +48 -26
- {oldaplib-0.3.29.dist-info → oldaplib-0.4.0.dist-info}/METADATA +1 -1
- {oldaplib-0.3.29.dist-info → oldaplib-0.4.0.dist-info}/RECORD +28 -27
- oldaplib/test/test_permissionset.py +0 -443
- {oldaplib-0.3.29.dist-info → oldaplib-0.4.0.dist-info}/WHEEL +0 -0
oldaplib/src/objectfactory.py
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import re
|
|
2
|
+
import textwrap
|
|
3
|
+
|
|
2
4
|
import jwt
|
|
3
5
|
|
|
4
6
|
from datetime import datetime, timedelta
|
|
5
7
|
from enum import Flag, auto
|
|
6
8
|
from functools import partial
|
|
7
|
-
from typing import Type, Any, Self, cast
|
|
9
|
+
from typing import Type, Any, Self, cast, Dict
|
|
8
10
|
|
|
9
11
|
from oldaplib.src.datamodel import DataModel
|
|
10
12
|
from oldaplib.src.enums.action import Action
|
|
@@ -18,6 +20,7 @@ from oldaplib.src.helpers.attributechange import AttributeChange
|
|
|
18
20
|
from oldaplib.src.helpers.context import Context
|
|
19
21
|
from oldaplib.src.helpers.convert2datatype import convert2datatype
|
|
20
22
|
from oldaplib.src.helpers.langstring import LangString
|
|
23
|
+
from oldaplib.src.helpers.observable_dict import ObservableDict
|
|
21
24
|
from oldaplib.src.helpers.observable_set import ObservableSet
|
|
22
25
|
from oldaplib.src.helpers.oldaperror import OldapErrorNotFound, OldapErrorValue, OldapErrorInconsistency, \
|
|
23
26
|
OldapErrorNoPermission, OldapError, OldapErrorUpdateFailed, OldapErrorInUse, OldapErrorAlreadyExists
|
|
@@ -34,7 +37,7 @@ from oldaplib.src.xsd.xsd_ncname import Xsd_NCName
|
|
|
34
37
|
from oldaplib.src.xsd.xsd_qname import Xsd_QName
|
|
35
38
|
from oldaplib.src.xsd.xsd_string import Xsd_string
|
|
36
39
|
|
|
37
|
-
ValueType = LangString | ObservableSet | Xsd
|
|
40
|
+
ValueType = LangString | ObservableSet | Xsd | Dict[Xsd_QName, DataPermission] | ObservableDict
|
|
38
41
|
|
|
39
42
|
class SortBy(Flag):
|
|
40
43
|
PROPVAL = auto()
|
|
@@ -82,12 +85,13 @@ class ResourceInstance:
|
|
|
82
85
|
:type changeset: dict[Iri, AttributeChange]
|
|
83
86
|
"""
|
|
84
87
|
_iri: Iri
|
|
85
|
-
_values: dict[Xsd_QName, LangString | ObservableSet]
|
|
88
|
+
_values: dict[Xsd_QName, LangString | ObservableSet | DataPermission]
|
|
86
89
|
_graph: Xsd_NCName
|
|
87
|
-
_changeset: dict[
|
|
90
|
+
_changeset: dict[Xsd_QName, AttributeChange]
|
|
91
|
+
_attached_roles: ObservableDict
|
|
88
92
|
|
|
89
|
-
__slots__ = ['_iri', '_values', '_graph', '_changeset', '_superclass_objs',
|
|
90
|
-
'
|
|
93
|
+
__slots__ = ['_iri', '_values', '_graph', '_changeset', '_superclass_objs', '_con', '_attached_roles',
|
|
94
|
+
'project', 'name', 'factory', 'properties', 'superclass', 'user_default_roles']
|
|
91
95
|
|
|
92
96
|
|
|
93
97
|
def __init__(self, *,
|
|
@@ -112,10 +116,31 @@ class ResourceInstance:
|
|
|
112
116
|
self._values: dict[Xsd_QName, ValueType] = {}
|
|
113
117
|
self._graph = self.project.projectShortName
|
|
114
118
|
self._superclass_objs = {}
|
|
115
|
-
self._changeset = {}
|
|
119
|
+
self._changeset: dict[Xsd_QName, AttributeChange] = {}
|
|
120
|
+
self._attached_roles = ObservableDict(on_change=self.__attachedToRole_cb)
|
|
116
121
|
|
|
117
122
|
def set_values(propclass: dict[Xsd_QName, HasProperty]):
|
|
118
123
|
for prop_iri, hasprop in propclass.items():
|
|
124
|
+
if str(prop_iri) == 'oldap:attachedToRole':
|
|
125
|
+
if kwargs.get(str(prop_iri)) or kwargs.get(prop_iri.fragment):
|
|
126
|
+
#
|
|
127
|
+
# we have an attachedToRole property given in the constructor...
|
|
128
|
+
#
|
|
129
|
+
value = kwargs[str(prop_iri)] if kwargs.get(str(prop_iri)) else kwargs[prop_iri.fragment]
|
|
130
|
+
if not isinstance(value, dict):
|
|
131
|
+
raise OldapErrorValue(f'{self.name}: Property {prop_iri} with attachedToRole must be a dict')
|
|
132
|
+
self._attached_roles = ObservableDict(value, on_change=self.__attachedToRole_cb)
|
|
133
|
+
self._values[prop_iri] = ObservableSet({Xsd_QName(x, validate=True) for x in value.keys()},
|
|
134
|
+
notifier=self.notifier, notify_data=prop_iri)
|
|
135
|
+
else:
|
|
136
|
+
#
|
|
137
|
+
# we take the user default values...
|
|
138
|
+
#
|
|
139
|
+
self._values[prop_iri] = ObservableSet({Xsd_QName(x) for x in self.user_default_roles.keys()},
|
|
140
|
+
notifier=self.notifier, notify_data=prop_iri)
|
|
141
|
+
self._attached_roles = ObservableDict(self.user_default_roles, on_change=self.__attachedToRole_cb)
|
|
142
|
+
|
|
143
|
+
continue
|
|
119
144
|
if kwargs.get(str(prop_iri)) or kwargs.get(prop_iri.fragment):
|
|
120
145
|
value = kwargs[str(prop_iri)] if kwargs.get(str(prop_iri)) else kwargs[prop_iri.fragment]
|
|
121
146
|
if isinstance(value, (list, tuple, set, LangString)): # we may have multiple values...
|
|
@@ -133,7 +158,7 @@ class ResourceInstance:
|
|
|
133
158
|
|
|
134
159
|
for prop_iri, hasprop in propclass.items():
|
|
135
160
|
#
|
|
136
|
-
# Validate
|
|
161
|
+
# Validate cardinalities
|
|
137
162
|
#
|
|
138
163
|
if hasprop.get(HasPropertyAttr.MIN_COUNT): # testing for MIN_COUNT conformance
|
|
139
164
|
if hasprop[HasPropertyAttr.MIN_COUNT] > 0 and not self._values.get(prop_iri):
|
|
@@ -203,7 +228,7 @@ class ResourceInstance:
|
|
|
203
228
|
|
|
204
229
|
def get(self, key: Xsd_QName) -> ValueType | Xsd | None:
|
|
205
230
|
if self._values.get(key):
|
|
206
|
-
return self.
|
|
231
|
+
return self.__get_value(key)
|
|
207
232
|
else:
|
|
208
233
|
return None
|
|
209
234
|
|
|
@@ -360,6 +385,11 @@ class ResourceInstance:
|
|
|
360
385
|
|
|
361
386
|
self._changeset[prop_iri] = AttributeChange(None, Action.MODIFY)
|
|
362
387
|
|
|
388
|
+
def __attachedToRole_cb(self, old_value: ObservableDict):
|
|
389
|
+
if self._changeset.get(Xsd_QName('oldap:attachedToRole')) is None:
|
|
390
|
+
self._changeset[Xsd_QName('oldap:attachedToRole')] = AttributeChange(old_value, Action.MODIFY)
|
|
391
|
+
|
|
392
|
+
|
|
363
393
|
def check_for_permissions(self, permission: AdminPermission) -> tuple[bool, str]:
|
|
364
394
|
#
|
|
365
395
|
# First we check if the logged-in user ("actor") has the permission to create a user for
|
|
@@ -383,14 +413,36 @@ class ResourceInstance:
|
|
|
383
413
|
#attr = Xsd_QName(prefix, fragment, validate=False)
|
|
384
414
|
if not isinstance(attr, Xsd_QName):
|
|
385
415
|
attr = Xsd_QName(attr)
|
|
416
|
+
if attr == Xsd_QName('oldap:attachedToRole'):
|
|
417
|
+
return self._attached_roles
|
|
386
418
|
tmp = self._values.get(attr, None)
|
|
387
419
|
if tmp is not None and str(attr) in {'oldap:createdBy', 'oldap:creationDate', 'oldap:lastModifiedBy', 'oldap:lastModificationDate'}:
|
|
420
|
+
if len(tmp) != 1:
|
|
421
|
+
raise OldapErrorValue(f'{self.name}: Property {attr} should have exactly one value, got {len(tmp)} values.')
|
|
388
422
|
return next(iter(tmp))
|
|
389
423
|
return tmp
|
|
390
424
|
|
|
391
425
|
def __set_value(self: Self, value: ValueType | Xsd | None, attr: Xsd_QName | str) -> None:
|
|
392
426
|
if not isinstance(attr, Xsd_QName):
|
|
393
427
|
attr = Xsd_QName(attr)
|
|
428
|
+
|
|
429
|
+
if attr == Xsd_QName('oldap:attachedToRole'):
|
|
430
|
+
if value is None:
|
|
431
|
+
self._changeset[attr] = AttributeChange(self._values.get(attr), Action.DELETE)
|
|
432
|
+
del self._values[attr]
|
|
433
|
+
self._attached_roles = ObservableDict(notifier=self.__attachedToRole_cb)
|
|
434
|
+
return
|
|
435
|
+
if not isinstance(value, dict):
|
|
436
|
+
raise OldapErrorValue(f'{self.name}: Property {attr} requires a dict, got {type(value).__name__}.')
|
|
437
|
+
for role_qname in value.keys():
|
|
438
|
+
if not isinstance(role_qname, Xsd_QName):
|
|
439
|
+
raise OldapErrorValue(f'{self.name}: Property {attr} requires keys to be Xsd_QName, got {type(role_qname).__name__}.')
|
|
440
|
+
if not isinstance(value[role_qname], DataPermission):
|
|
441
|
+
raise OldapErrorValue(f'{self.name}: Property {attr} requires values to be DataPermission, got {type(value[role_qname]).__name__}.')
|
|
442
|
+
self._changeset[attr] = AttributeChange(self._values.get(attr), Action.REPLACE)
|
|
443
|
+
self._values[attr] = ObservableSet({value.keys()}, notifier=self.notifier, notify_data=attr)
|
|
444
|
+
self._attached_roles = ObservableDict(value, notifier=self.__attachedToRole_cb)
|
|
445
|
+
return
|
|
394
446
|
hasprop = self.properties.get(attr)
|
|
395
447
|
|
|
396
448
|
#
|
|
@@ -444,6 +496,12 @@ class ResourceInstance:
|
|
|
444
496
|
def __del_value(self: Self, attr: Xsd_QName | str) -> None:
|
|
445
497
|
if not isinstance(attr, Xsd_QName):
|
|
446
498
|
attr = Xsd_QName(attr)
|
|
499
|
+
|
|
500
|
+
if attr == Xsd_QName('oldap:attachedToRole'):
|
|
501
|
+
self._changeset[attr] = AttributeChange(self._values.get(attr), Action.DELETE)
|
|
502
|
+
del self._values[attr]
|
|
503
|
+
self._attached_roles = ObservableDict(notifier=self.__attachedToRole_cb)
|
|
504
|
+
return
|
|
447
505
|
hasprop = self.properties.get(attr)
|
|
448
506
|
|
|
449
507
|
if hasprop.get(HasPropertyAttr.MIN_COUNT): # testing for MIN_COUNT conformance
|
|
@@ -461,6 +519,10 @@ class ResourceInstance:
|
|
|
461
519
|
def changeset(self) -> dict[Xsd_QName, AttributeChange]:
|
|
462
520
|
return self._changeset
|
|
463
521
|
|
|
522
|
+
@property
|
|
523
|
+
def attachedToRoleAnnotation(self) -> ObservableDict:
|
|
524
|
+
return self._attached_roles
|
|
525
|
+
|
|
464
526
|
def clear_changeset(self) -> None:
|
|
465
527
|
for item in self._values:
|
|
466
528
|
if hasattr(self._values[item], 'clear_changeset'):
|
|
@@ -468,21 +530,29 @@ class ResourceInstance:
|
|
|
468
530
|
self._changeset = {}
|
|
469
531
|
|
|
470
532
|
|
|
471
|
-
def get_data_permission(self,
|
|
533
|
+
def get_data_permission(self, permission: DataPermission) -> bool:
|
|
534
|
+
context = Context(name=self._con.context_name)
|
|
472
535
|
permission_query = context.sparql_context
|
|
473
|
-
permission_query += f'''
|
|
536
|
+
permission_query += textwrap.dedent(f'''
|
|
474
537
|
ASK {{
|
|
475
|
-
|
|
476
|
-
{self.
|
|
538
|
+
{{
|
|
539
|
+
GRAPH {self._graph}:data {{
|
|
540
|
+
{self._iri.toRdf} oldap:createdBy {self._con.userIri.toRdf} .
|
|
541
|
+
}}
|
|
477
542
|
}}
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
543
|
+
UNION
|
|
544
|
+
{{
|
|
545
|
+
GRAPH oldap:admin {{
|
|
546
|
+
{self._con.userIri.toRdf} oldap:hasRole ?role .
|
|
547
|
+
?dataperm oldap:permissionValue ?permval .
|
|
548
|
+
FILTER(?permval >= {permission.numeric.toRdf})
|
|
549
|
+
}}
|
|
550
|
+
GRAPH {self._graph}:data {{
|
|
551
|
+
{self._iri.toRdf} oldap:attachedToRole ?role .
|
|
552
|
+
<<{self._iri.toRdf} oldap:attachedToRole ?role>> oldap:hasDataPermission ?dataperm .
|
|
553
|
+
}}
|
|
482
554
|
}}
|
|
483
|
-
|
|
484
|
-
}}'''
|
|
485
|
-
|
|
555
|
+
}}''')
|
|
486
556
|
if self._con.in_transaction():
|
|
487
557
|
result = self._con.transaction_query(permission_query)
|
|
488
558
|
else:
|
|
@@ -539,7 +609,6 @@ class ResourceInstance:
|
|
|
539
609
|
sparql += f'\n{blank:{(indent + 1) * indent_inc}}GRAPH {self._graph}:data {{'
|
|
540
610
|
|
|
541
611
|
sparql += f'\n{blank:{(indent + 2) * indent_inc}}{self._iri.toRdf} a {self.name}'
|
|
542
|
-
|
|
543
612
|
for prop_iri, values in self._values.items():
|
|
544
613
|
if self.properties.get(prop_iri) and self.properties[prop_iri].prop.datatype == XsdDatatypes.QName:
|
|
545
614
|
qnames = {f'"{x}"^^xsd:QName' for x in values}
|
|
@@ -547,9 +616,11 @@ class ResourceInstance:
|
|
|
547
616
|
sparql += f' ;\n{blank:{(indent + 3) * indent_inc}}{prop_iri.toRdf} {qnames_rdf}'
|
|
548
617
|
else:
|
|
549
618
|
sparql += f' ;\n{blank:{(indent + 3) * indent_inc}}{prop_iri.toRdf} {values.toRdf}'
|
|
619
|
+
for role, dperm in self._attached_roles.items():
|
|
620
|
+
sparql += f' .\n{blank:{(indent + 2) * indent_inc}}<<{self._iri.toRdf} oldap:attachedToRole {role.toRdf}>> oldap:hasDataPermission {dperm.toRdf}'
|
|
621
|
+
|
|
550
622
|
sparql += f' .\n{blank:{(indent + 1) * indent_inc}}}}\n'
|
|
551
623
|
sparql += f'{blank:{indent * indent_inc}}}}\n'
|
|
552
|
-
|
|
553
624
|
self._con.transaction_start()
|
|
554
625
|
try:
|
|
555
626
|
result = self._con.transaction_query(sparql0)
|
|
@@ -584,20 +655,30 @@ class ResourceInstance:
|
|
|
584
655
|
graph = cls.project.projectShortName
|
|
585
656
|
context = Context(name=con.context_name)
|
|
586
657
|
sparql = context.sparql_context
|
|
587
|
-
sparql += f'''
|
|
588
|
-
SELECT ?predicate ?value
|
|
658
|
+
sparql += textwrap.dedent(f'''
|
|
659
|
+
SELECT DISTINCT ?predicate ?value
|
|
589
660
|
WHERE {{
|
|
661
|
+
{{
|
|
662
|
+
GRAPH {graph}:data {{
|
|
663
|
+
{iri.toRdf} oldap:createdBy {con.userIri.toRdf} .
|
|
664
|
+
}}
|
|
665
|
+
}}
|
|
666
|
+
UNION
|
|
667
|
+
{{
|
|
668
|
+
GRAPH oldap:admin {{
|
|
669
|
+
{con.userIri.toRdf} oldap:hasRole ?role .
|
|
670
|
+
?dataperm oldap:permissionValue ?permval .
|
|
671
|
+
FILTER(?permval >= {DataPermission.DATA_VIEW.numeric.toRdf})
|
|
672
|
+
}}
|
|
673
|
+
}}
|
|
590
674
|
GRAPH {graph}:data {{
|
|
591
675
|
{iri.toRdf} ?predicate ?value .
|
|
592
|
-
{iri.toRdf} oldap:
|
|
676
|
+
{iri.toRdf} oldap:attachedToRole ?role .
|
|
677
|
+
<<{iri.toRdf} oldap:attachedToRole ?role>> oldap:hasDataPermission ?dataperm .
|
|
593
678
|
}}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
?DataPermission oldap:permissionValue ?permval .
|
|
598
|
-
}}
|
|
599
|
-
FILTER(?permval >= {DataPermission.DATA_VIEW.numeric.toRdf})
|
|
600
|
-
}}'''
|
|
679
|
+
|
|
680
|
+
}}
|
|
681
|
+
''')
|
|
601
682
|
jsonres = con.query(sparql)
|
|
602
683
|
res = QueryProcessor(context, jsonres)
|
|
603
684
|
objtype = None
|
|
@@ -622,8 +703,25 @@ class ResourceInstance:
|
|
|
622
703
|
kwargs[r['predicate'].as_qname.fragment] = r['value']
|
|
623
704
|
else:
|
|
624
705
|
raise OldapErrorInconsistency(f"Expected QName as predicate, got {r['predicate']}")
|
|
706
|
+
|
|
625
707
|
if objtype is None:
|
|
626
708
|
raise OldapErrorNotFound(f'Resource with iri <{iri}> not found.')
|
|
709
|
+
sparql = context.sparql_context
|
|
710
|
+
sparql += textwrap.dedent(f'''
|
|
711
|
+
SELECT DISTINCT ?role ?dataperm
|
|
712
|
+
WHERE {{
|
|
713
|
+
GRAPH {graph}:data {{
|
|
714
|
+
<< {iri.toRdf} oldap:attachedToRole ?role >> oldap:hasDataPermission ?dataperm .
|
|
715
|
+
}}
|
|
716
|
+
}}
|
|
717
|
+
''')
|
|
718
|
+
jsonres = con.query(sparql)
|
|
719
|
+
res = QueryProcessor(context, jsonres)
|
|
720
|
+
roles = {}
|
|
721
|
+
for r in res:
|
|
722
|
+
roles[r['role']] = DataPermission.from_qname(r['dataperm'])
|
|
723
|
+
kwargs['attachedToRole'] = roles
|
|
724
|
+
|
|
627
725
|
if cls.__name__ != objtype:
|
|
628
726
|
raise OldapErrorInconsistency(f'Expected class {cls.__name__}, got {objtype} instead.')
|
|
629
727
|
return cls(iri=iri, **kwargs)
|
|
@@ -658,8 +756,9 @@ class ResourceInstance:
|
|
|
658
756
|
sparql_list = []
|
|
659
757
|
required_permission = DataPermission.DATA_EXTEND
|
|
660
758
|
for field, change in self._changeset.items():
|
|
661
|
-
if field == 'oldap:
|
|
759
|
+
if field == 'oldap:attachedToRole':
|
|
662
760
|
required_permission = DataPermission.DATA_PERMISSIONS
|
|
761
|
+
continue
|
|
663
762
|
if change.action == Action.MODIFY:
|
|
664
763
|
continue # will be processed below!
|
|
665
764
|
if change.action != Action.CREATE:
|
|
@@ -695,6 +794,77 @@ class ResourceInstance:
|
|
|
695
794
|
sparql_list.append(sparql)
|
|
696
795
|
|
|
697
796
|
for field, change in self._changeset.items():
|
|
797
|
+
if field == 'oldap:attachedToRole':
|
|
798
|
+
sparql = f'# Processing field "{field}"\n'
|
|
799
|
+
add_sparql = False
|
|
800
|
+
if (change.action == Action.DELETE or change.action == Action.REPLACE) and len(change.old_value) > 0:
|
|
801
|
+
sparql += f'{blank:{indent * indent_inc}}DELETE DATA {{\n'
|
|
802
|
+
sparql += f'{blank:{(indent + 1) * indent_inc}}GRAPH {self._graph}:data {{\n'
|
|
803
|
+
for role, dperm in change.old_value.items():
|
|
804
|
+
sparql += f'{blank:{(indent + 2) * indent_inc}}{self._iri.toRdf} {field.toRdf} {role.toRdf} .\n'
|
|
805
|
+
sparql += f'{blank:{(indent + 2) * indent_inc}}<<{self._iri.toRdf} {field.toRdf} {role.toRdf}>> oldap:hasDataPermission {dperm.toRdf} .\n'
|
|
806
|
+
sparql += f'{blank:{(indent + 1) * indent_inc}}}}\n'
|
|
807
|
+
sparql += f'{blank:{indent * indent_inc}}}}\n'
|
|
808
|
+
add_sparql = True
|
|
809
|
+
elif (change.action == Action.CREATE or change.action == Action.REPLACE) and len(self._attached_roles) > 0:
|
|
810
|
+
sparql += f'{blank:{indent * indent_inc}}INSERT DATA {{\n'
|
|
811
|
+
sparql += f'{blank:{(indent + 1) * indent_inc}}GRAPH {self._graph}:data {{\n'
|
|
812
|
+
for role, dperm in self._attached_roles.items():
|
|
813
|
+
sparql += f'{blank:{(indent + 2) * indent_inc}}{self._iri.toRdf} {field.toRdf} {role.toRdf} .\n'
|
|
814
|
+
sparql += f'{blank:{(indent + 2) * indent_inc}}<<{self._iri.toRdf} {field.toRdf} {role.toRdf}>> oldap:hasDataPermission {dperm.toRdf} .\n'
|
|
815
|
+
sparql += f'{blank:{(indent + 1) * indent_inc}}}}\n'
|
|
816
|
+
sparql += f'{blank:{indent * indent_inc}}}}\n'
|
|
817
|
+
add_sparql = True
|
|
818
|
+
elif change.action == Action.MODIFY:
|
|
819
|
+
added = {}
|
|
820
|
+
removed = {}
|
|
821
|
+
changed = {}
|
|
822
|
+
if change.old_value:
|
|
823
|
+
added = {key: self._attached_roles[key] for key in self._attached_roles.keys() - change.old_value.keys()}
|
|
824
|
+
else:
|
|
825
|
+
added = self._attached_roles
|
|
826
|
+
if change.old_value:
|
|
827
|
+
removed = {key: change.old_value[key] for key in
|
|
828
|
+
change.old_value.keys() - self._attached_roles.keys()}
|
|
829
|
+
else:
|
|
830
|
+
removed = {}
|
|
831
|
+
if change.old_value:
|
|
832
|
+
changed = {key: {'old': change.old_value.get(key),
|
|
833
|
+
'new': self._attached_roles.get(key)}
|
|
834
|
+
for key in change.old_value.keys() & self._attached_roles.keys()
|
|
835
|
+
if self._attached_roles[key] != change.old_value[key]}
|
|
836
|
+
else:
|
|
837
|
+
changed = {}
|
|
838
|
+
if len(removed) > 0 or len(changed) > 0:
|
|
839
|
+
sparql += f'{blank:{indent * indent_inc}}DELETE DATA {{\n'
|
|
840
|
+
sparql += f'{blank:{(indent + 1) * indent_inc}}GRAPH {self._graph}:data {{\n'
|
|
841
|
+
for role, dperm in removed.items():
|
|
842
|
+
sparql += f'{blank:{(indent + 2) * indent_inc}}{self._iri.toRdf} {field.toRdf} {role.toRdf} .\n'
|
|
843
|
+
sparql += f'{blank:{(indent + 2) * indent_inc}}<<{self._iri.toRdf} {field.toRdf} {role.toRdf}>> oldap:hasDataPermission {dperm.toRdf} .\n'
|
|
844
|
+
for role, data in changed.items():
|
|
845
|
+
sparql += f'{blank:{(indent + 2) * indent_inc}}{self._iri.toRdf} {field.toRdf} {role.toRdf} .\n'
|
|
846
|
+
sparql += f'{blank:{(indent + 2) * indent_inc}}<<{self._iri.toRdf} {field.toRdf} {role.toRdf}>> oldap:hasDataPermission {data['old'].toRdf} .\n'
|
|
847
|
+
sparql += f'{blank:{(indent + 1) * indent_inc}}}}\n'
|
|
848
|
+
sparql += f'{blank:{indent * indent_inc}}}}\n'
|
|
849
|
+
add_sparql = True
|
|
850
|
+
if len(added) > 0 or len(changed) > 0:
|
|
851
|
+
if add_sparql:
|
|
852
|
+
sparql += f'{blank:{indent * indent_inc}}\n;\n'
|
|
853
|
+
sparql += f'{blank:{indent * indent_inc}}INSERT DATA {{\n'
|
|
854
|
+
sparql += f'{blank:{(indent + 1) * indent_inc}}GRAPH {self._graph}:data {{\n'
|
|
855
|
+
for role, dperm in added.items():
|
|
856
|
+
sparql += f'{blank:{(indent + 2) * indent_inc}}{self._iri.toRdf} {field.toRdf} {role.toRdf} .\n'
|
|
857
|
+
sparql += f'{blank:{(indent + 2) * indent_inc}}<<{self._iri.toRdf} {field.toRdf} {role.toRdf}>> oldap:hasDataPermission {dperm.toRdf} .\n'
|
|
858
|
+
for role, data in changed.items():
|
|
859
|
+
sparql += f'{blank:{(indent + 2) * indent_inc}}{self._iri.toRdf} {field.toRdf} {role.toRdf} .\n'
|
|
860
|
+
sparql += f'{blank:{(indent + 2) * indent_inc}}<<{self._iri.toRdf} {field.toRdf} {role.toRdf}>> oldap:hasDataPermission {data['old'].toRdf} .\n'
|
|
861
|
+
sparql += f'{blank:{(indent + 1) * indent_inc}}}}\n'
|
|
862
|
+
sparql += f'{blank:{indent * indent_inc}}}}\n'
|
|
863
|
+
add_sparql = True
|
|
864
|
+
if add_sparql:
|
|
865
|
+
sparql_list.append(sparql)
|
|
866
|
+
continue
|
|
867
|
+
|
|
698
868
|
if change.action != Action.MODIFY:
|
|
699
869
|
continue # has been processed above
|
|
700
870
|
if self.properties[field].prop.datatype == XsdDatatypes.langString:
|
|
@@ -754,7 +924,7 @@ class ResourceInstance:
|
|
|
754
924
|
# Test permission for Action.REPLACE
|
|
755
925
|
#
|
|
756
926
|
if not admin_resources:
|
|
757
|
-
if not self.get_data_permission(
|
|
927
|
+
if not self.get_data_permission(required_permission):
|
|
758
928
|
self._con.transaction_abort()
|
|
759
929
|
raise OldapErrorNoPermission(f'No permission to update resource "{self._iri}"')
|
|
760
930
|
try:
|
|
@@ -810,13 +980,14 @@ class ResourceInstance:
|
|
|
810
980
|
DELETE WHERE {{
|
|
811
981
|
GRAPH {self._graph}:data {{
|
|
812
982
|
{self._iri.toRdf} ?prop ?val .
|
|
983
|
+
<< {self._iri.toRdf} oldap:attachedToRole ?role >> oldap:hasDataPermission ?dataperm .
|
|
813
984
|
}}
|
|
814
985
|
}}
|
|
815
986
|
"""
|
|
816
987
|
|
|
817
988
|
self._con.transaction_start()
|
|
818
989
|
if not admin_resources:
|
|
819
|
-
if not self.get_data_permission(
|
|
990
|
+
if not self.get_data_permission(DataPermission.DATA_DELETE):
|
|
820
991
|
self._con.transaction_abort()
|
|
821
992
|
raise OldapErrorNoPermission(f'No permission to update resource "{self._iri}"')
|
|
822
993
|
try:
|
|
@@ -840,21 +1011,27 @@ class ResourceInstance:
|
|
|
840
1011
|
@staticmethod
|
|
841
1012
|
def read_data(con: IConnection, projectShortName: Xsd_NCName | str, iri: Iri | str) -> dict[Xsd_QName, Any]:
|
|
842
1013
|
"""
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
in the RDF database, verifies user permissions, and returns selected data in a
|
|
846
|
-
dictionary format.
|
|
1014
|
+
Retrieves data from a resource in the specified project with permissions validation.
|
|
1015
|
+
NOTE: It does *NOT* return the attachedToRole data!
|
|
847
1016
|
|
|
848
|
-
|
|
1017
|
+
This function performs a SPARQL query to fetch data associated with the given
|
|
1018
|
+
IRI within a specific project graph, taking into account user permissions for
|
|
1019
|
+
the resource. If no data is found for the given IRI, or if permission requirements
|
|
1020
|
+
are not met, exceptions are raised.
|
|
1021
|
+
|
|
1022
|
+
:param con: A connection object used to interact with the database.
|
|
849
1023
|
:type con: IConnection
|
|
850
|
-
:param projectShortName: The short name of the project
|
|
851
|
-
|
|
852
|
-
:
|
|
853
|
-
:
|
|
854
|
-
|
|
1024
|
+
:param projectShortName: The short name of the project graph. Can be an Xsd_NCName
|
|
1025
|
+
or string.
|
|
1026
|
+
:type projectShortName: Xsd_NCName | str
|
|
1027
|
+
:param iri: The IRI of the resource to retrieve data for. Can be an Iri instance
|
|
1028
|
+
or string.
|
|
1029
|
+
:type iri: Iri | str
|
|
1030
|
+
:return: A dictionary mapping predicates (of type Xsd_QName) to their corresponding
|
|
1031
|
+
values.
|
|
855
1032
|
:rtype: dict[Xsd_QName, Any]
|
|
856
|
-
:raises OldapErrorInconsistency: If a
|
|
857
|
-
:raises OldapErrorNotFound: If the resource with the
|
|
1033
|
+
:raises OldapErrorInconsistency: If a predicate is not a valid QName.
|
|
1034
|
+
:raises OldapErrorNotFound: If the resource with the specified IRI cannot be found.
|
|
858
1035
|
"""
|
|
859
1036
|
if not isinstance(iri, Iri):
|
|
860
1037
|
iri = Iri(iri, validate=True)
|
|
@@ -865,26 +1042,37 @@ class ResourceInstance:
|
|
|
865
1042
|
|
|
866
1043
|
context = Context(name=con.context_name)
|
|
867
1044
|
sparql = context.sparql_context
|
|
868
|
-
sparql += f'''
|
|
869
|
-
SELECT ?predicate ?value
|
|
1045
|
+
sparql += textwrap.dedent(f'''
|
|
1046
|
+
SELECT DISTINCT ?predicate ?value
|
|
870
1047
|
WHERE {{
|
|
1048
|
+
{{
|
|
1049
|
+
GRAPH {graph}:data {{
|
|
1050
|
+
{iri.toRdf} oldap:createdBy {con.userIri.toRdf} .
|
|
1051
|
+
}}
|
|
1052
|
+
}}
|
|
1053
|
+
UNION
|
|
1054
|
+
{{
|
|
1055
|
+
GRAPH oldap:admin {{
|
|
1056
|
+
{con.userIri.toRdf} oldap:hasRole ?role .
|
|
1057
|
+
?dataperm oldap:permissionValue ?permval .
|
|
1058
|
+
FILTER(?permval >= {DataPermission.DATA_VIEW.numeric.toRdf})
|
|
1059
|
+
}}
|
|
1060
|
+
}}
|
|
871
1061
|
GRAPH {graph}:data {{
|
|
872
1062
|
{iri.toRdf} ?predicate ?value .
|
|
873
|
-
{iri.toRdf} oldap:
|
|
874
|
-
|
|
875
|
-
GRAPH oldap:admin {{
|
|
876
|
-
{con.userIri.toRdf} oldap:hasPermissions ?permset .
|
|
877
|
-
?permset oldap:givesPermission ?DataPermission .
|
|
878
|
-
?DataPermission oldap:permissionValue ?permval .
|
|
1063
|
+
{iri.toRdf} oldap:attachedToRole ?role .
|
|
1064
|
+
<<{iri.toRdf} oldap:attachedToRole ?role>> oldap:hasDataPermission ?dataperm .
|
|
879
1065
|
}}
|
|
880
|
-
FILTER(?permval >= {DataPermission.DATA_VIEW.numeric.toRdf})
|
|
881
1066
|
}}
|
|
882
|
-
'''
|
|
1067
|
+
''')
|
|
1068
|
+
|
|
883
1069
|
jsonres = con.query(sparql)
|
|
884
1070
|
res = QueryProcessor(context, jsonres)
|
|
885
1071
|
data = {}
|
|
886
1072
|
for r in res:
|
|
887
1073
|
if r['predicate'].is_qname:
|
|
1074
|
+
if r['predicate'].as_qname == Xsd_QName('oldap:attachedToRole'):
|
|
1075
|
+
continue
|
|
888
1076
|
if not data.get(r['predicate'].as_qname):
|
|
889
1077
|
data[r['predicate'].as_qname] = []
|
|
890
1078
|
data[str(r['predicate'].as_qname)].append(str(r['value']))
|
|
@@ -892,6 +1080,23 @@ class ResourceInstance:
|
|
|
892
1080
|
raise OldapErrorInconsistency(f"Expected QName as predicate, got {r['predicate']}")
|
|
893
1081
|
if not data.get('rdf:type'):
|
|
894
1082
|
raise OldapErrorNotFound(f'Resource with iri <{iri}> not found.')
|
|
1083
|
+
|
|
1084
|
+
sparql = context.sparql_context
|
|
1085
|
+
sparql += textwrap.dedent(f'''
|
|
1086
|
+
SELECT DISTINCT ?role ?dataperm
|
|
1087
|
+
WHERE {{
|
|
1088
|
+
GRAPH {graph}:data {{
|
|
1089
|
+
<< {iri.toRdf} oldap:attachedToRole ?role >> oldap:hasDataPermission ?dataperm .
|
|
1090
|
+
}}
|
|
1091
|
+
}}
|
|
1092
|
+
''')
|
|
1093
|
+
jsonres = con.query(sparql)
|
|
1094
|
+
res = QueryProcessor(context, jsonres)
|
|
1095
|
+
roles = {}
|
|
1096
|
+
for r in res:
|
|
1097
|
+
roles[r['role']] = DataPermission.from_qname(r['dataperm'])
|
|
1098
|
+
data[Xsd_QName('oldap:attachedToRole')] = roles
|
|
1099
|
+
|
|
895
1100
|
return data
|
|
896
1101
|
|
|
897
1102
|
@staticmethod
|
|
@@ -981,6 +1186,11 @@ class ResourceInstance:
|
|
|
981
1186
|
if sortBy == SortBy.LASTMOD:
|
|
982
1187
|
sparql += '?lastModificationDate'
|
|
983
1188
|
sparql += f'\n{blank:{indent * indent_inc}}WHERE {{'
|
|
1189
|
+
sparql += f'\n{blank:{(indent + 1) * indent_inc}}GRAPH oldap:admin {{'
|
|
1190
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}{con.userIri.toRdf} oldap:hasRole ?role .'
|
|
1191
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?DataPermission oldap:permissionValue ?permval .'
|
|
1192
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}FILTER(?permval >= {DataPermission.DATA_VIEW.numeric.toRdf})'
|
|
1193
|
+
sparql += f'\n{blank:{(indent + 1) * indent_inc}}}}'
|
|
984
1194
|
sparql += f'\n{blank:{(indent + 1) * indent_inc}}GRAPH {graph}:data {{'
|
|
985
1195
|
if sortBy:
|
|
986
1196
|
if sortBy == SortBy.CREATED:
|
|
@@ -991,16 +1201,11 @@ class ResourceInstance:
|
|
|
991
1201
|
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s rdf:type ?t .'
|
|
992
1202
|
if resClass:
|
|
993
1203
|
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s rdf:type {resClass} .'
|
|
994
|
-
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s oldap:
|
|
1204
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s oldap:attachedToRole ?role .'
|
|
1205
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}<< ?s oldap:attachedToRole ?role >> oldap:hasDataPermission ?DataPermission .'
|
|
1206
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}FILTER(isLiteral(?o) && (datatype(?o) = xsd:string || datatype(?o) = rdf:langString || lang(?o) != ""))'
|
|
1207
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}FILTER(CONTAINS(LCASE(STR(?o)), "{s}")) # case-insensitive substring match'
|
|
995
1208
|
sparql += f'\n{blank:{(indent + 1) * indent_inc}}}}'
|
|
996
|
-
sparql += f'\n{blank:{(indent + 1) * indent_inc}}FILTER(isLiteral(?o) && (datatype(?o) = xsd:string || datatype(?o) = rdf:langString || lang(?o) != ""))'
|
|
997
|
-
sparql += f'\n{blank:{(indent + 1) * indent_inc}}FILTER(CONTAINS(LCASE(STR(?o)), "{s}")) # case-insensitive substring match'
|
|
998
|
-
sparql += f'\n{blank:{(indent + 1) * indent_inc}}GRAPH oldap:admin {{'
|
|
999
|
-
sparql += f'\n{blank:{(indent + 2) * indent_inc}}{con.userIri.toRdf} oldap:hasPermissions ?permset .'
|
|
1000
|
-
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?permset oldap:givesPermission ?DataPermission .'
|
|
1001
|
-
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?DataPermission oldap:permissionValue ?permval .'
|
|
1002
|
-
sparql += f'\n{blank:{(indent + 1) * indent_inc}}}}'
|
|
1003
|
-
sparql += f'\n{blank:{(indent + 1) * indent_inc}}FILTER(?permval >= {DataPermission.DATA_VIEW.numeric.toRdf})'
|
|
1004
1209
|
sparql += f'\n{blank:{indent * indent_inc}}}}'
|
|
1005
1210
|
|
|
1006
1211
|
if sortBy:
|
|
@@ -1015,7 +1220,6 @@ class ResourceInstance:
|
|
|
1015
1220
|
sparql += f'\n{blank:{indent * indent_inc}}LIMIT {limit} OFFSET {offset}'
|
|
1016
1221
|
sparql += '\n'
|
|
1017
1222
|
|
|
1018
|
-
|
|
1019
1223
|
try:
|
|
1020
1224
|
jsonres = con.query(sparql)
|
|
1021
1225
|
except OldapError:
|
|
@@ -1105,7 +1309,14 @@ class ResourceInstance:
|
|
|
1105
1309
|
if sortBy == SortBy.LASTMOD:
|
|
1106
1310
|
sparql += '?lastModificationDate'
|
|
1107
1311
|
sparql += f'\n{blank:{indent * indent_inc}}WHERE {{'
|
|
1312
|
+
sparql += f'\n{blank:{(indent + 1) * indent_inc}}GRAPH oldap:admin {{'
|
|
1313
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}{con.userIri.toRdf} oldap:hasRole ?role .'
|
|
1314
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?dataperm oldap:permissionValue ?permval .'
|
|
1315
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}FILTER(?permval >= {DataPermission.DATA_VIEW.numeric.toRdf})'
|
|
1316
|
+
sparql += f'\n{blank:{(indent + 1) * indent_inc}}}}'
|
|
1108
1317
|
sparql += f'\n{blank:{(indent + 1) * indent_inc}}GRAPH {graph}:data {{'
|
|
1318
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s oldap:attachedToRole ?role .'
|
|
1319
|
+
sparql += f'\n{blank:{(indent + 2) * indent_inc}}<< ?s oldap:attachedToRole ?role >> oldap:hasDataPermission ?dataperm .'
|
|
1109
1320
|
if sortBy:
|
|
1110
1321
|
if sortBy == SortBy.CREATED:
|
|
1111
1322
|
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s oldap:creationDate ?creationDate .'
|
|
@@ -1115,14 +1326,7 @@ class ResourceInstance:
|
|
|
1115
1326
|
for index, prop in enumerate(includeProperties):
|
|
1116
1327
|
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s {prop} ?o{index} .'
|
|
1117
1328
|
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s rdf:type {resClass} .'
|
|
1118
|
-
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?s oldap:grantsPermission ?permset .'
|
|
1119
|
-
sparql += f'\n{blank:{(indent + 1) * indent_inc}}}}'
|
|
1120
|
-
sparql += f'\n{blank:{(indent + 1) * indent_inc}}GRAPH oldap:admin {{'
|
|
1121
|
-
sparql += f'\n{blank:{(indent + 2) * indent_inc}}{con.userIri.toRdf} oldap:hasPermissions ?permset .'
|
|
1122
|
-
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?permset oldap:givesPermission ?DataPermission .'
|
|
1123
|
-
sparql += f'\n{blank:{(indent + 2) * indent_inc}}?DataPermission oldap:permissionValue ?permval .'
|
|
1124
1329
|
sparql += f'\n{blank:{(indent + 1) * indent_inc}}}}'
|
|
1125
|
-
sparql += f'\n{blank:{(indent + 1) * indent_inc}}FILTER(?permval >= {DataPermission.DATA_VIEW.numeric.toRdf})'
|
|
1126
1330
|
sparql += f'\n{blank:{indent * indent_inc}}}}'
|
|
1127
1331
|
|
|
1128
1332
|
if sortBy:
|
|
@@ -1187,23 +1391,23 @@ class ResourceInstance:
|
|
|
1187
1391
|
context = Context(name=con.context_name)
|
|
1188
1392
|
sparql = context.sparql_context
|
|
1189
1393
|
|
|
1190
|
-
sparql += f"""
|
|
1394
|
+
sparql += textwrap.dedent(f"""
|
|
1191
1395
|
SELECT ?subject ?graph ?path ?prop ?val ?permval
|
|
1192
1396
|
WHERE {{
|
|
1193
1397
|
VALUES ?inputImageId {{ {mediaObjectId.toRdf} }}
|
|
1194
1398
|
?subject rdf:type shared:MediaObject .
|
|
1399
|
+
GRAPH oldap:admin {{
|
|
1400
|
+
{con.userIri.toRdf} oldap:hasRole ?role .
|
|
1401
|
+
?dataperm oldap:permissionValue ?permval .
|
|
1402
|
+
}}
|
|
1195
1403
|
GRAPH ?graph {{
|
|
1196
|
-
?subject oldap:
|
|
1404
|
+
?subject oldap:attachedToRole ?role .
|
|
1405
|
+
<<?subject oldap:attachedToRole ?role>> oldap:hasDataPermission ?dataperm .
|
|
1197
1406
|
?subject shared:imageId ?inputImageId .
|
|
1198
1407
|
?subject ?prop ?val .
|
|
1199
1408
|
}}
|
|
1200
|
-
GRAPH oldap:admin {{
|
|
1201
|
-
{con.userIri.toRdf} oldap:hasPermissions ?permset .
|
|
1202
|
-
?permset oldap:givesPermission ?DataPermission .
|
|
1203
|
-
?DataPermission oldap:permissionValue ?permval .
|
|
1204
|
-
}}
|
|
1205
1409
|
}}
|
|
1206
|
-
"""
|
|
1410
|
+
""")
|
|
1207
1411
|
try:
|
|
1208
1412
|
jsonres = con.query(sparql)
|
|
1209
1413
|
except OldapError:
|
|
@@ -1221,7 +1425,8 @@ class ResourceInstance:
|
|
|
1221
1425
|
if str(r['prop']) == 'rdf:type':
|
|
1222
1426
|
continue
|
|
1223
1427
|
if str(r['prop']) in {'oldap:createdBy', 'oldap:creationDate', 'oldap:lastModifiedBy', 'oldap:lastModificationDate',
|
|
1224
|
-
'
|
|
1428
|
+
'dcterms:type', 'shared:imageId', 'shared:originalName', 'shared:originalMimeType',
|
|
1429
|
+
'shared:serverUrl', 'shared:path', 'shared:protocol'}:
|
|
1225
1430
|
result[str(r['prop'])] = r['val']
|
|
1226
1431
|
else:
|
|
1227
1432
|
if result.get(str(r['prop'])) is None:
|
|
@@ -1259,19 +1464,17 @@ class ResourceInstance:
|
|
|
1259
1464
|
SELECT ?graph ?prop ?val ?permval
|
|
1260
1465
|
WHERE {{
|
|
1261
1466
|
{mediaObjectIri.toRdf} rdf:type shared:MediaObject .
|
|
1467
|
+
GRAPH oldap:admin {{
|
|
1468
|
+
{con.userIri.toRdf} oldap:hasRole ?role .
|
|
1469
|
+
?dataperm oldap:permissionValue ?permval .
|
|
1470
|
+
}}
|
|
1262
1471
|
GRAPH ?graph {{
|
|
1263
|
-
{mediaObjectIri.toRdf} oldap:
|
|
1264
|
-
{mediaObjectIri.toRdf}
|
|
1472
|
+
{mediaObjectIri.toRdf} oldap:attachedToRole ?role .
|
|
1473
|
+
<<{mediaObjectIri.toRdf} oldap:attachedToRole ?role>> oldap:hasDataPermission ?dataperm .
|
|
1265
1474
|
{mediaObjectIri.toRdf} ?prop ?val .
|
|
1266
1475
|
}}
|
|
1267
|
-
GRAPH oldap:admin {{
|
|
1268
|
-
{con.userIri.toRdf} oldap:hasPermissions ?permset .
|
|
1269
|
-
?permset oldap:givesPermission ?DataPermission .
|
|
1270
|
-
?DataPermission oldap:permissionValue ?permval .
|
|
1271
|
-
}}
|
|
1272
1476
|
}}
|
|
1273
1477
|
"""
|
|
1274
|
-
print(sparql)
|
|
1275
1478
|
try:
|
|
1276
1479
|
jsonres = con.query(sparql)
|
|
1277
1480
|
except OldapError:
|
|
@@ -1289,7 +1492,8 @@ class ResourceInstance:
|
|
|
1289
1492
|
if str(r['prop']) == 'rdf:type':
|
|
1290
1493
|
continue
|
|
1291
1494
|
if str(r['prop']) in {'oldap:createdBy', 'oldap:creationDate', 'oldap:lastModifiedBy', 'oldap:lastModificationDate',
|
|
1292
|
-
'
|
|
1495
|
+
'dcterms:type', 'shared:imageId', 'shared:originalName', 'shared:originalMimeType',
|
|
1496
|
+
'shared:serverUrl', 'shared:path', 'shared:protocol'}:
|
|
1293
1497
|
result[str(r['prop'])] = r['val']
|
|
1294
1498
|
else:
|
|
1295
1499
|
if result.get(str(r['prop'])) is None:
|
|
@@ -1349,6 +1553,7 @@ class ResourceInstanceFactory:
|
|
|
1349
1553
|
_sharedProject: Project
|
|
1350
1554
|
_datamodel: DataModel
|
|
1351
1555
|
_sharedModel: DataModel
|
|
1556
|
+
_user_default_roles: Dict[Xsd_QName, DataPermission] = {}
|
|
1352
1557
|
|
|
1353
1558
|
def __init__(self,
|
|
1354
1559
|
con: IConnection,
|
|
@@ -1359,6 +1564,7 @@ class ResourceInstanceFactory:
|
|
|
1359
1564
|
else:
|
|
1360
1565
|
self._project = Project.read(self._con, project)
|
|
1361
1566
|
self._sharedProject = Project.read(self._con, "oldap:SharedProject")
|
|
1567
|
+
self._user_default_roles = {r: DataPermission.from_qname(p) for r, p in self._con._userdata.hasRole.items()}
|
|
1362
1568
|
|
|
1363
1569
|
self._datamodel = DataModel.read(con=self._con, project=self._project)
|
|
1364
1570
|
self._sharedModel = DataModel.read(con=self._con, project=self._sharedProject)
|
|
@@ -1384,7 +1590,9 @@ class ResourceInstanceFactory:
|
|
|
1384
1590
|
'name': resclass.owl_class_iri,
|
|
1385
1591
|
'factory': self,
|
|
1386
1592
|
'properties': resclass.properties,
|
|
1387
|
-
'superclass': resclass.superclass
|
|
1593
|
+
'superclass': resclass.superclass,
|
|
1594
|
+
'user_default_roles': self._user_default_roles,
|
|
1595
|
+
})
|
|
1388
1596
|
|
|
1389
1597
|
|
|
1390
1598
|
def read(self, iri: Iri | str) -> ResourceInstance:
|
|
@@ -1393,22 +1601,41 @@ class ResourceInstanceFactory:
|
|
|
1393
1601
|
graph = self._project.projectShortName
|
|
1394
1602
|
context = Context(name=self._con.context_name)
|
|
1395
1603
|
sparql = context.sparql_context
|
|
1396
|
-
sparql += f'''
|
|
1397
|
-
SELECT ?predicate ?value
|
|
1604
|
+
sparql += textwrap.dedent(f'''
|
|
1605
|
+
SELECT DISTINCT ?predicate ?value
|
|
1398
1606
|
WHERE {{
|
|
1399
|
-
|
|
1607
|
+
# 1) compute the max permval for this user + this resource
|
|
1608
|
+
{{
|
|
1609
|
+
SELECT (MAX(?pv) AS ?permval)
|
|
1610
|
+
WHERE {{
|
|
1611
|
+
GRAPH oldap:admin {{
|
|
1612
|
+
{self._con.userIri.toRdf} oldap:hasRole ?role .
|
|
1613
|
+
}}
|
|
1614
|
+
GRAPH {graph}:data {{
|
|
1615
|
+
{iri.toRdf} oldap:attachedToRole ?role .
|
|
1616
|
+
<< {iri.toRdf} oldap:attachedToRole ?role >> oldap:hasDataPermission ?dataperm .
|
|
1617
|
+
}}
|
|
1618
|
+
GRAPH oldap:admin {{
|
|
1619
|
+
?dataperm oldap:permissionValue ?pv .
|
|
1620
|
+
}}
|
|
1621
|
+
}}
|
|
1622
|
+
}}
|
|
1623
|
+
|
|
1624
|
+
# 2) return the resource triples, but only if there exists a role with that max permval
|
|
1400
1625
|
GRAPH {graph}:data {{
|
|
1401
|
-
|
|
1402
|
-
?iri oldap:grantsPermission ?permset .
|
|
1626
|
+
{iri.toRdf} ?predicate ?value .
|
|
1403
1627
|
}}
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1628
|
+
FILTER EXISTS {{
|
|
1629
|
+
GRAPH oldap:admin {{
|
|
1630
|
+
{self._con.userIri.toRdf} oldap:hasRole ?role .
|
|
1631
|
+
?dataperm oldap:permissionValue ?permval .
|
|
1632
|
+
}}
|
|
1633
|
+
GRAPH {graph}:data {{
|
|
1634
|
+
{iri.toRdf} oldap:attachedToRole ?role .
|
|
1635
|
+
<< {iri.toRdf} oldap:attachedToRole ?role >> oldap:hasDataPermission ?dataperm .
|
|
1636
|
+
}}
|
|
1409
1637
|
}}
|
|
1410
|
-
|
|
1411
|
-
}}'''
|
|
1638
|
+
}}''')
|
|
1412
1639
|
jsonres = self._con.query(sparql)
|
|
1413
1640
|
res = QueryProcessor(context, jsonres)
|
|
1414
1641
|
objtype = None
|
|
@@ -1435,6 +1662,22 @@ class ResourceInstanceFactory:
|
|
|
1435
1662
|
raise OldapErrorInconsistency(f"Expected QName as predicate, got {r['predicate']}")
|
|
1436
1663
|
if objtype is None:
|
|
1437
1664
|
raise OldapErrorNotFound(f'Resource with iri <{iri}> not found.')
|
|
1665
|
+
sparql = context.sparql_context
|
|
1666
|
+
sparql += textwrap.dedent(f'''
|
|
1667
|
+
SELECT DISTINCT ?role ?dataperm
|
|
1668
|
+
WHERE {{
|
|
1669
|
+
GRAPH {graph}:data {{
|
|
1670
|
+
<< {iri.toRdf} oldap:attachedToRole ?role >> oldap:hasDataPermission ?dataperm .
|
|
1671
|
+
}}
|
|
1672
|
+
}}
|
|
1673
|
+
''')
|
|
1674
|
+
jsonres = self._con.query(sparql)
|
|
1675
|
+
res = QueryProcessor(context, jsonres)
|
|
1676
|
+
roles = {}
|
|
1677
|
+
for r in res:
|
|
1678
|
+
roles[r['role']] = DataPermission.from_qname(r['dataperm'])
|
|
1679
|
+
kwargs['attachedToRole'] = roles
|
|
1680
|
+
|
|
1438
1681
|
Instance = self.createObjectInstance(objtype)
|
|
1439
1682
|
return Instance(iri=iri, **kwargs)
|
|
1440
1683
|
|