oldaplib 0.3.30__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.
@@ -1,9 +1,11 @@
1
+ import textwrap
1
2
  from datetime import datetime
2
- from typing import Self, Set, Iterable
3
+ from typing import Self, Dict
3
4
 
4
5
  from oldaplib.src.enums.adminpermissions import AdminPermission
5
6
  from oldaplib.src.helpers.context import Context
6
7
  from oldaplib.src.helpers.irincname import IriOrNCName
8
+ from oldaplib.src.helpers.observable_dict import ObservableDict
7
9
  from oldaplib.src.helpers.oldaperror import OldapErrorNotFound
8
10
  from oldaplib.src.helpers.query_processor import QueryProcessor
9
11
  from oldaplib.src.helpers.serializeableset import SerializeableSet
@@ -13,39 +15,45 @@ from oldaplib.src.xsd.iri import Iri
13
15
  from oldaplib.src.xsd.xsd_boolean import Xsd_boolean
14
16
  from oldaplib.src.xsd.xsd_datetime import Xsd_dateTime
15
17
  from oldaplib.src.xsd.xsd_ncname import Xsd_NCName
18
+ from oldaplib.src.xsd.xsd_qname import Xsd_QName
16
19
  from oldaplib.src.xsd.xsd_string import Xsd_string
17
20
 
18
21
 
19
-
20
22
  @serializer
21
23
  class UserData:
22
24
  """
23
- Represents a user entity and provides management and query functionalities for a user
24
- in a specific project context.
25
+ Represents user data, including personal information, roles, and project involvement,
26
+ while adhering to a structured and serializable format.
25
27
 
26
- This class is designed to encapsulate properties and behaviors associated with a user.
27
- It provides attributes for managing user metadata, permissions, and project associations.
28
- Additionally, it includes utility methods for constructing SPARQL queries and processing
29
- query results to instantiate user data instances.
28
+ The class serves as a model for user-related information in a SPARQL-based system,
29
+ providing methods for querying, constructing, and managing user-related data.
30
30
 
31
- :ivar userIri: The IRI uniquely identifying the user.
32
- :ivar userId: The NCName uniquely identifying the user.
33
- :ivar familyName: The family name of the user.
34
- :ivar givenName: The given name of the user.
35
- :ivar email: The email address of the user.
36
- :ivar credentials: The hashed credentials or identifier for user authentication.
37
- :ivar isActive: Indicates whether the user's account is active.
38
- :ivar inProject: A representation of the user's association within projects.
39
- :ivar hasPermissions: The set of permissions associated with the user.
31
+ :ivar creator: The IRI of the user who created this entity.
32
+ :type creator: Iri | None
33
+ :ivar created: The datetime when this entity was created.
34
+ :type created: Xsd_dateTime | datetime | None
35
+ :ivar contributor: The IRI of the user who contributed to this entity.
36
+ :type contributor: Iri | None
37
+ :ivar modified: The datetime when this entity was last modified.
38
+ :type modified: Xsd_dateTime | datetime | None
39
+ :ivar userIri: The unique IRI identifying the user.
40
40
  :type userIri: Iri
41
+ :ivar userId: The unique non-colonized identifier (NCName) for the user.
41
42
  :type userId: Xsd_NCName
43
+ :ivar familyName: The family name (surname) of the user.
42
44
  :type familyName: Xsd_string
45
+ :ivar givenName: The given name (first name) of the user.
43
46
  :type givenName: Xsd_string
47
+ :ivar email: The user's email address.
44
48
  :type email: Xsd_string
45
- :type credentials: Xsd_string
49
+ :ivar credentials: The credentials or authentication key for the user, if provided.
50
+ :type credentials: Xsd_string | None
51
+ :ivar isActive: A boolean indicating whether the user is currently active.
46
52
  :type isActive: Xsd_boolean
53
+ :ivar inProject: The project object or relation associated with the user.
47
54
  :type inProject: InProjectClass | None
48
- :type hasPermissions: SerializeableSet[Iri] | None
55
+ :ivar hasRole: A serializable set containing the roles or permissions assigned to the user.
56
+ :type hasRole: SerializeableSet[Iri] | None
49
57
  """
50
58
  _creator: Iri | None
51
59
  _created: Xsd_dateTime | datetime | None
@@ -58,7 +66,8 @@ class UserData:
58
66
  _email: Xsd_string
59
67
  _credentials: Xsd_string
60
68
  _isActive: Xsd_boolean
61
- _inProject: InProjectClass
69
+ _inProject: InProjectClass | None
70
+ _hasRole: ObservableDict | None
62
71
 
63
72
  def __init__(self, *,
64
73
  creator: Iri | None = None,
@@ -73,7 +82,7 @@ class UserData:
73
82
  credentials: Xsd_string | None = None,
74
83
  isActive: Xsd_boolean,
75
84
  inProject: InProjectClass | None = None,
76
- hasPermissions: SerializeableSet[Iri] | set[Iri] | None = None,
85
+ hasRole: ObservableDict | Dict[Xsd_QName, Xsd_QName | None] | Dict[str, str] | None = None,
77
86
  validate: bool = False):
78
87
  self._creator = creator
79
88
  self._created = created
@@ -87,7 +96,13 @@ class UserData:
87
96
  self._credentials = credentials
88
97
  self._isActive = isActive
89
98
  self._inProject = inProject or InProjectClass()
90
- self._hasPermissions = hasPermissions if isinstance(hasPermissions, SerializeableSet) else SerializeableSet(hasPermissions)
99
+ if isinstance(hasRole, ObservableDict):
100
+ self._hasRole = hasRole
101
+ elif isinstance(hasRole, dict):
102
+ tmp = {Xsd_QName(key, validate=validate): Xsd_QName(val, validate=validate) if val else None for key, val in hasRole.items()}
103
+ self._hasRole = ObservableDict(tmp)
104
+ else:
105
+ self._hasRole = None
91
106
 
92
107
  def __str__(self) -> str:
93
108
  res = f'userIri: {self._userIri}\n'
@@ -98,7 +113,7 @@ class UserData:
98
113
  res += f', credentials: {self._credentials}\n'
99
114
  res += f', isActive: {self._isActive}\n'
100
115
  res += f', inProject: {self._inProject}\n'
101
- res += f', hasPermissions: {self._hasPermissions}\n'
116
+ res += f', hasRole: {self._hasRole}\n'
102
117
  return res
103
118
 
104
119
  @property
@@ -150,8 +165,8 @@ class UserData:
150
165
  return self._inProject
151
166
 
152
167
  @property
153
- def hasPermissions(self) -> SerializeableSet[Iri] | None:
154
- return self._hasPermissions
168
+ def hasRole(self) -> Dict[Xsd_QName, Xsd_QName | None] | None:
169
+ return self._hasRole
155
170
 
156
171
  @staticmethod
157
172
  def sparql_query(context: Context, userId: IriOrNCName, validate: bool = False) -> str:
@@ -181,8 +196,8 @@ class UserData:
181
196
  user_id, user_iri = userId.value()
182
197
  sparql = context.sparql_context
183
198
  if user_id is not None:
184
- sparql += f"""
185
- SELECT ?user ?prop ?val ?proj ?rval
199
+ sparql += textwrap.dedent(f"""
200
+ SELECT ?user ?prop ?val ?proj ?rval ?role ?defdp
186
201
  FROM oldap:admin
187
202
  WHERE {{
188
203
  {{
@@ -193,12 +208,16 @@ class UserData:
193
208
  ?user a oldap:User .
194
209
  ?user oldap:userId {user_id.toRdf} .
195
210
  <<?user oldap:inProject ?proj>> oldap:hasAdminPermission ?rval
211
+ }} UNION {{
212
+ ?user a oldap:User .
213
+ ?user oldap:userId {user_id.toRdf} .
214
+ <<?user oldap:hasRole ?role>> oldap:hasDefaultDataPermission ?defdp
196
215
  }}
197
216
  }}
198
- """
217
+ """)
199
218
  elif user_iri is not None:
200
- sparql += f"""
201
- SELECT ?user ?prop ?val ?proj ?rval
219
+ sparql += textwrap.dedent(f"""
220
+ SELECT ?user ?prop ?val ?proj ?rval ?role ?defdp
202
221
  FROM oldap:admin
203
222
  WHERE {{
204
223
  BIND({user_iri.toRdf} as ?user)
@@ -208,9 +227,12 @@ class UserData:
208
227
  }} UNION {{
209
228
  ?user a oldap:User .
210
229
  <<?user oldap:inProject ?proj>> oldap:hasAdminPermission ?rval
230
+ }} UNION {{
231
+ ?user a oldap:User .
232
+ <<?user oldap:hasRole ?role>> oldap:hasDefaultDataPermission ?defdp
211
233
  }}
212
234
  }}
213
- """
235
+ """)
214
236
 
215
237
  return sparql
216
238
 
@@ -245,7 +267,7 @@ class UserData:
245
267
  credentials: Xsd_string | None = None
246
268
  isActive: Xsd_boolean | None = None
247
269
  inProjectDict: dict[Iri | str, set[AdminPermission]] | None = None
248
- hasPermissions: set[Iri] | None = None
270
+ hasRoleDict: ObservableDict | None = None
249
271
  for r in queryresult:
250
272
  match str(r.get('prop')):
251
273
  case 'dcterms:creator':
@@ -274,10 +296,11 @@ class UserData:
274
296
  inProjectDict = {r['val']: set()}
275
297
  else:
276
298
  inProjectDict[r['val']] = set()
277
- case 'oldap:hasPermissions':
278
- if not hasPermissions:
279
- hasPermissions = set()
280
- hasPermissions.add(r['val'])
299
+ case 'oldap:hasRole':
300
+ if not hasRoleDict:
301
+ hasRoleDict = ObservableDict({r['val']: None})
302
+ else:
303
+ hasRoleDict[r['val']] = None
281
304
  case _:
282
305
  if r.get('proj') and r.get('rval'):
283
306
  if not inProjectDict:
@@ -285,6 +308,12 @@ class UserData:
285
308
  if inProjectDict.get(r['proj']) is None:
286
309
  inProjectDict[r['proj']] = set()
287
310
  inProjectDict[r['proj']].add(AdminPermission.from_string(str(r['rval'])))
311
+ if r.get('role') and r.get('defdp'):
312
+ if not hasRoleDict:
313
+ hasRoleDict = {r['role']: None}
314
+ if hasRoleDict.get(r['role']) is None:
315
+ hasRoleDict[r['role']] = None
316
+ hasRoleDict[r['role']] = r['defdp']
288
317
  inProject = InProjectClass(inProjectDict) if inProjectDict else InProjectClass()
289
318
  return cls(created=created,
290
319
  creator=creator,
@@ -298,7 +327,7 @@ class UserData:
298
327
  credentials=credentials,
299
328
  isActive=isActive,
300
329
  inProject=inProject,
301
- hasPermissions=hasPermissions,
330
+ hasRole=hasRoleDict,
302
331
  validate=False)
303
332
 
304
333
  def _as_dict(self) -> dict:
@@ -309,7 +338,7 @@ class UserData:
309
338
  'givenName': self._givenName,
310
339
  'email': self._email,
311
340
  'isActive': self._isActive,
312
- 'hasPermissions': self._hasPermissions,
341
+ 'hasRole': self._hasRole,
313
342
  'inProject': self._inProject
314
343
  }
315
344
 
oldaplib/src/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.3.30"
1
+ __version__ = "0.4.0"
@@ -368,6 +368,8 @@ class TestDataModel(unittest.TestCase):
368
368
  def test_datamodel_read(self):
369
369
  model = DataModel.read(self._connection, self._sysproject, ignore_cache=True)
370
370
  self.assertEqual(set(model.get_propclasses()), {
371
+ Xsd_QName("oldap:hasDataPermission"),
372
+ Xsd_QName("oldap:hasDefaultDataPermission"),
371
373
  Xsd_QName("oldap:hasAdminPermission"),
372
374
  Xsd_QName("oldap:statementProperty"),
373
375
  Xsd_QName("oldap:namespaceIri"),
@@ -379,10 +381,11 @@ class TestDataModel(unittest.TestCase):
379
381
  Xsd_QName("oldap:OldapListNode"),
380
382
  Xsd_QName("oldap:AdminPermission"),
381
383
  Xsd_QName("oldap:DataPermission"),
382
- Xsd_QName("oldap:PermissionSet"),
384
+ Xsd_QName("oldap:Role"),
383
385
  Xsd_QName("oldap:Thing"),
384
386
  Xsd_QName("oldap:ExternalOntology"),
385
- Xsd_QName("oldap:inProjectStatement")
387
+ Xsd_QName("oldap:inProjectStatement"),
388
+ Xsd_QName("oldap:hasRoleStatement")
386
389
  })
387
390
 
388
391
  def test_datamodel_read_shared(self):
@@ -11,8 +11,9 @@ from oldaplib.src.xsd.xsd_string import Xsd_string
11
11
 
12
12
 
13
13
  class TestInproject(unittest.TestCase):
14
+
14
15
  def test_creation(self):
15
- ip = InProjectClass({'test:proj': {AdminPermission.ADMIN_PERMISSION_SETS, 'oldap:ADMIN_RESOURCES'},
16
+ ip = InProjectClass({'test:proj': {AdminPermission.ADMIN_ROLES, 'oldap:ADMIN_RESOURCES'},
16
17
  'https://gaga.com/test': {'ADMIN_MODEL'},
17
18
  Iri('gaga:gugus'): set()})
18
19
  self.assertEqual(len(ip), 3)
@@ -30,10 +31,10 @@ class TestInproject(unittest.TestCase):
30
31
  ip = InProjectClass({'test:proj': {'MODEL_T'}})
31
32
 
32
33
  def test_get_item(self):
33
- ip = InProjectClass({'test:proj': {AdminPermission.ADMIN_PERMISSION_SETS, 'oldap:ADMIN_RESOURCES'},
34
+ ip = InProjectClass({'test:proj': {AdminPermission.ADMIN_ROLES, 'oldap:ADMIN_RESOURCES'},
34
35
  'https://gaga.com/test': {'ADMIN_MODEL'},
35
36
  Iri('gaga:gugus'): set()})
36
- self.assertEqual(ip['test:proj'], {AdminPermission.ADMIN_PERMISSION_SETS, AdminPermission.ADMIN_RESOURCES})
37
+ self.assertEqual(ip['test:proj'], {AdminPermission.ADMIN_ROLES, AdminPermission.ADMIN_RESOURCES})
37
38
  self.assertEqual(ip['https://gaga.com/test'], {AdminPermission.ADMIN_MODEL})
38
39
  self.assertEqual(ip[Iri('gaga:gugus')], set())
39
40
 
@@ -45,13 +46,13 @@ class TestInproject(unittest.TestCase):
45
46
  tmp = ip[Xsd_string('test:proj')]
46
47
 
47
48
  def test_set_item(self):
48
- ip = InProjectClass({'test:proj': {AdminPermission.ADMIN_PERMISSION_SETS, 'oldap:ADMIN_RESOURCES'},
49
+ ip = InProjectClass({'test:proj': {AdminPermission.ADMIN_ROLES, 'oldap:ADMIN_RESOURCES'},
49
50
  'https://gaga.com/test': {'ADMIN_MODEL'},
50
51
  Xsd_QName('gaga:gugus'): set()})
51
52
  ip['test:proj'] = {AdminPermission.ADMIN_OLDAP}
52
53
  self.assertEqual(ip['test:proj'], {AdminPermission.ADMIN_OLDAP})
53
- ip['https://gaga.com/test'] = {AdminPermission.ADMIN_PERMISSION_SETS, 'oldap:ADMIN_RESOURCES'}
54
- self.assertEqual(ip['https://gaga.com/test'], {AdminPermission.ADMIN_PERMISSION_SETS, AdminPermission.ADMIN_RESOURCES})
54
+ ip['https://gaga.com/test'] = {AdminPermission.ADMIN_ROLES, 'oldap:ADMIN_RESOURCES'}
55
+ self.assertEqual(ip['https://gaga.com/test'], {AdminPermission.ADMIN_ROLES, AdminPermission.ADMIN_RESOURCES})
55
56
  ip[Xsd_QName('gaga:gugus')] = {'ADMIN_MODEL'}
56
57
  self.assertEqual(ip[Xsd_QName('gaga:gugus')], {AdminPermission.ADMIN_MODEL})
57
58
 
@@ -61,7 +62,7 @@ class TestInproject(unittest.TestCase):
61
62
  ip[Xsd_QName('XYZ')] = {'ADMIN_MODEL'}
62
63
 
63
64
  def test_del_item(self):
64
- ip = InProjectClass({'test:proj': {AdminPermission.ADMIN_PERMISSION_SETS, 'oldap:ADMIN_RESOURCES'},
65
+ ip = InProjectClass({'test:proj': {AdminPermission.ADMIN_ROLES, 'oldap:ADMIN_RESOURCES'},
65
66
  'https://gaga.com/test': {'ADMIN_MODEL'},
66
67
  Xsd_QName('gaga:gugus'): set()})
67
68
  del ip['test:proj']
@@ -72,7 +73,7 @@ class TestInproject(unittest.TestCase):
72
73
  del ip[Xsd_QName('gaga:blabla')]
73
74
 
74
75
  def test_str(self):
75
- ip = InProjectClass({'test:proj': {AdminPermission.ADMIN_PERMISSION_SETS, 'oldap:ADMIN_RESOURCES'},
76
+ ip = InProjectClass({'test:proj': {AdminPermission.ADMIN_ROLES, 'oldap:ADMIN_RESOURCES'},
76
77
  'https://gaga.com/test': {'ADMIN_MODEL'},
77
78
  Xsd_QName('gaga:gugus'): set()})
78
79
  projs = str(ip).strip().split('\n')
@@ -81,7 +82,7 @@ class TestInproject(unittest.TestCase):
81
82
  proj, permset = projstr.split(' : ')
82
83
  match proj:
83
84
  case 'test:proj':
84
- self.assertEqual(permset, "['oldap:ADMIN_PERMISSION_SETS', 'oldap:ADMIN_RESOURCES']")
85
+ self.assertEqual(permset, "['oldap:ADMIN_RESOURCES', 'oldap:ADMIN_ROLES']")
85
86
  case 'https://gaga.com/test':
86
87
  self.assertEqual(permset, "['oldap:ADMIN_MODEL']")
87
88
  case 'gaga:gugus':
@@ -90,13 +91,13 @@ class TestInproject(unittest.TestCase):
90
91
  raise Exception("Unexpected project")
91
92
 
92
93
  def test_bool(self):
93
- ip = InProjectClass({'test:proj': {AdminPermission.ADMIN_PERMISSION_SETS, 'oldap:ADMIN_RESOURCES'},
94
+ ip = InProjectClass({'test:proj': {AdminPermission.ADMIN_ROLES, 'oldap:ADMIN_RESOURCES'},
94
95
  'https://gaga.com/test': {'ADMIN_MODEL'},
95
96
  Xsd_QName('gaga:gugus'): set()})
96
97
  self.assertTrue(bool(ip))
97
98
 
98
99
  def test_serialization(self):
99
- val = InProjectClass({'test:proj': {AdminPermission.ADMIN_PERMISSION_SETS, 'oldap:ADMIN_RESOURCES'},
100
+ val = InProjectClass({'test:proj': {AdminPermission.ADMIN_ROLES, 'oldap:ADMIN_RESOURCES'},
100
101
  'https://gaga.com/test': {'ADMIN_MODEL'},
101
102
  Xsd_QName('gaga:gugus'): set()})
102
103
  jsonstr = json.dumps(val, default=serializer.encoder_default)
@@ -104,43 +105,43 @@ class TestInproject(unittest.TestCase):
104
105
  self.assertEqual(val, val2)
105
106
 
106
107
  def test_copy_eq_ne(self):
107
- val = InProjectClass({'test:proj': {AdminPermission.ADMIN_PERMISSION_SETS, 'oldap:ADMIN_RESOURCES'},
108
+ val = InProjectClass({'test:proj': {AdminPermission.ADMIN_ROLES, 'oldap:ADMIN_RESOURCES'},
108
109
  'https://gaga.com/test': {'ADMIN_MODEL'},
109
110
  Xsd_QName('gaga:gugus'): set()})
110
- val2 = InProjectClass({'test:proj': {AdminPermission.ADMIN_PERMISSION_SETS, 'oldap:ADMIN_RESOURCES'},
111
+ val2 = InProjectClass({'test:proj': {AdminPermission.ADMIN_ROLES, 'oldap:ADMIN_RESOURCES'},
111
112
  'https://gaga.com/test': {'ADMIN_MODEL'},
112
113
  Xsd_QName('gaga:gugus'): set()})
113
114
  self.assertTrue(val == val2)
114
115
  self.assertFalse(val != val2)
115
116
 
116
- val = InProjectClass({'test:proj': {AdminPermission.ADMIN_PERMISSION_SETS, 'oldap:ADMIN_RESOURCES'},
117
+ val = InProjectClass({'test:proj': {AdminPermission.ADMIN_ROLES, 'oldap:ADMIN_RESOURCES'},
117
118
  'https://gaga.com/test': {'ADMIN_MODEL'},
118
119
  Xsd_QName('gaga:gugus'): set()})
119
- val2 = InProjectClass({'test:proj': {AdminPermission.ADMIN_PERMISSION_SETS, 'oldap:ADMIN_RESOURCES'},
120
+ val2 = InProjectClass({'test:proj': {AdminPermission.ADMIN_ROLES, 'oldap:ADMIN_RESOURCES'},
120
121
  'https://gaga.com/test': {'ADMIN_MODEL'},
121
122
  Xsd_QName('gaga:gaga'): set()})
122
123
  self.assertFalse(val == val2)
123
124
  self.assertTrue(val != val2)
124
125
 
125
- val = InProjectClass({'test:proj': {AdminPermission.ADMIN_PERMISSION_SETS, 'oldap:ADMIN_RESOURCES'},
126
+ val = InProjectClass({'test:proj': {AdminPermission.ADMIN_ROLES, 'oldap:ADMIN_RESOURCES'},
126
127
  'https://gaga.com/test': {'ADMIN_MODEL'},
127
128
  Xsd_QName('gaga:gugus'): {AdminPermission.ADMIN_RESOURCES}})
128
- val2 = InProjectClass({'test:proj': {AdminPermission.ADMIN_PERMISSION_SETS, 'oldap:ADMIN_RESOURCES'},
129
+ val2 = InProjectClass({'test:proj': {AdminPermission.ADMIN_ROLES, 'oldap:ADMIN_RESOURCES'},
129
130
  'https://gaga.com/test': {'ADMIN_MODEL'},
130
- Xsd_QName('gaga:gugus'): {AdminPermission.ADMIN_RESOURCES, AdminPermission.ADMIN_PERMISSION_SETS}})
131
+ Xsd_QName('gaga:gugus'): {AdminPermission.ADMIN_RESOURCES, AdminPermission.ADMIN_ROLES}})
131
132
  self.assertFalse(val == val2)
132
133
  self.assertTrue(val != val2)
133
134
 
134
135
 
135
136
  def test_items(self):
136
- ip = InProjectClass({'test:proj': {AdminPermission.ADMIN_PERMISSION_SETS, 'oldap:ADMIN_RESOURCES'},
137
+ ip = InProjectClass({'test:proj': {AdminPermission.ADMIN_ROLES, 'oldap:ADMIN_RESOURCES'},
137
138
  'https://gaga.com/test': {'ADMIN_MODEL'},
138
139
  Xsd_QName('gaga:gugus'): set()})
139
140
  for proj, perms in ip.items():
140
141
  self.assertTrue(proj in ['test:proj', 'https://gaga.com/test', Iri('gaga:gugus')])
141
142
 
142
143
  def test_keys(self):
143
- ip = InProjectClass({'test:proj': {AdminPermission.ADMIN_PERMISSION_SETS, 'oldap:ADMIN_RESOURCES'},
144
+ ip = InProjectClass({'test:proj': {AdminPermission.ADMIN_ROLES, 'oldap:ADMIN_RESOURCES'},
144
145
  'https://gaga.com/test': {'ADMIN_MODEL'},
145
146
  Iri('gaga:gugus'): set()})
146
147
  keys = set(ip.keys())