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