Skip to content

Commit 8f3071c

Browse files
committed
Add endpoints for group management
1 parent 305557d commit 8f3071c

File tree

7 files changed

+340
-4
lines changed

7 files changed

+340
-4
lines changed

pydatalab/schemas/cell.json

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,57 @@
298298
"name"
299299
]
300300
},
301+
"Group": {
302+
"title": "Group",
303+
"description": "A model that describes a group of users, for the sake\nof applying group permissions.\n\nEach `Person` model can point to a given group.",
304+
"type": "object",
305+
"properties": {
306+
"type": {
307+
"title": "Type",
308+
"default": "groups",
309+
"const": "groups",
310+
"type": "string"
311+
},
312+
"immutable_id": {
313+
"title": "Immutable ID",
314+
"format": "uuid",
315+
"type": "string"
316+
},
317+
"last_modified": {
318+
"title": "Last Modified",
319+
"type": "string",
320+
"format": "date-time"
321+
},
322+
"relationships": {
323+
"title": "Relationships",
324+
"type": "array",
325+
"items": {
326+
"$ref": "#/definitions/TypedRelationship"
327+
}
328+
},
329+
"display_name": {
330+
"title": "Display Name",
331+
"minLength": 1,
332+
"maxLength": 150,
333+
"type": "string"
334+
},
335+
"description": {
336+
"title": "Description",
337+
"type": "string"
338+
},
339+
"group_admins": {
340+
"title": "Group Admins",
341+
"type": "array",
342+
"items": {
343+
"type": "string"
344+
}
345+
}
346+
},
347+
"required": [
348+
"display_name",
349+
"group_admins"
350+
]
351+
},
301352
"AccountStatus": {
302353
"title": "AccountStatus",
303354
"description": "A string enum representing the account status.",
@@ -354,6 +405,13 @@
354405
"type": "string",
355406
"format": "email"
356407
},
408+
"groups": {
409+
"title": "Groups",
410+
"type": "array",
411+
"items": {
412+
"$ref": "#/definitions/Group"
413+
}
414+
},
357415
"managers": {
358416
"title": "Managers",
359417
"type": "array",

pydatalab/schemas/equipment.json

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,57 @@
253253
"name"
254254
]
255255
},
256+
"Group": {
257+
"title": "Group",
258+
"description": "A model that describes a group of users, for the sake\nof applying group permissions.\n\nEach `Person` model can point to a given group.",
259+
"type": "object",
260+
"properties": {
261+
"type": {
262+
"title": "Type",
263+
"default": "groups",
264+
"const": "groups",
265+
"type": "string"
266+
},
267+
"immutable_id": {
268+
"title": "Immutable ID",
269+
"format": "uuid",
270+
"type": "string"
271+
},
272+
"last_modified": {
273+
"title": "Last Modified",
274+
"type": "string",
275+
"format": "date-time"
276+
},
277+
"relationships": {
278+
"title": "Relationships",
279+
"type": "array",
280+
"items": {
281+
"$ref": "#/definitions/TypedRelationship"
282+
}
283+
},
284+
"display_name": {
285+
"title": "Display Name",
286+
"minLength": 1,
287+
"maxLength": 150,
288+
"type": "string"
289+
},
290+
"description": {
291+
"title": "Description",
292+
"type": "string"
293+
},
294+
"group_admins": {
295+
"title": "Group Admins",
296+
"type": "array",
297+
"items": {
298+
"type": "string"
299+
}
300+
}
301+
},
302+
"required": [
303+
"display_name",
304+
"group_admins"
305+
]
306+
},
256307
"AccountStatus": {
257308
"title": "AccountStatus",
258309
"description": "A string enum representing the account status.",
@@ -309,6 +360,13 @@
309360
"type": "string",
310361
"format": "email"
311362
},
363+
"groups": {
364+
"title": "Groups",
365+
"type": "array",
366+
"items": {
367+
"$ref": "#/definitions/Group"
368+
}
369+
},
312370
"managers": {
313371
"title": "Managers",
314372
"type": "array",

pydatalab/schemas/sample.json

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,57 @@
257257
"name"
258258
]
259259
},
260+
"Group": {
261+
"title": "Group",
262+
"description": "A model that describes a group of users, for the sake\nof applying group permissions.\n\nEach `Person` model can point to a given group.",
263+
"type": "object",
264+
"properties": {
265+
"type": {
266+
"title": "Type",
267+
"default": "groups",
268+
"const": "groups",
269+
"type": "string"
270+
},
271+
"immutable_id": {
272+
"title": "Immutable ID",
273+
"format": "uuid",
274+
"type": "string"
275+
},
276+
"last_modified": {
277+
"title": "Last Modified",
278+
"type": "string",
279+
"format": "date-time"
280+
},
281+
"relationships": {
282+
"title": "Relationships",
283+
"type": "array",
284+
"items": {
285+
"$ref": "#/definitions/TypedRelationship"
286+
}
287+
},
288+
"display_name": {
289+
"title": "Display Name",
290+
"minLength": 1,
291+
"maxLength": 150,
292+
"type": "string"
293+
},
294+
"description": {
295+
"title": "Description",
296+
"type": "string"
297+
},
298+
"group_admins": {
299+
"title": "Group Admins",
300+
"type": "array",
301+
"items": {
302+
"type": "string"
303+
}
304+
}
305+
},
306+
"required": [
307+
"display_name",
308+
"group_admins"
309+
]
310+
},
260311
"AccountStatus": {
261312
"title": "AccountStatus",
262313
"description": "A string enum representing the account status.",
@@ -313,6 +364,13 @@
313364
"type": "string",
314365
"format": "email"
315366
},
367+
"groups": {
368+
"title": "Groups",
369+
"type": "array",
370+
"items": {
371+
"$ref": "#/definitions/Group"
372+
}
373+
},
316374
"managers": {
317375
"title": "Managers",
318376
"type": "array",

pydatalab/schemas/startingmaterial.json

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,57 @@
311311
"name"
312312
]
313313
},
314+
"Group": {
315+
"title": "Group",
316+
"description": "A model that describes a group of users, for the sake\nof applying group permissions.\n\nEach `Person` model can point to a given group.",
317+
"type": "object",
318+
"properties": {
319+
"type": {
320+
"title": "Type",
321+
"default": "groups",
322+
"const": "groups",
323+
"type": "string"
324+
},
325+
"immutable_id": {
326+
"title": "Immutable ID",
327+
"format": "uuid",
328+
"type": "string"
329+
},
330+
"last_modified": {
331+
"title": "Last Modified",
332+
"type": "string",
333+
"format": "date-time"
334+
},
335+
"relationships": {
336+
"title": "Relationships",
337+
"type": "array",
338+
"items": {
339+
"$ref": "#/definitions/TypedRelationship"
340+
}
341+
},
342+
"display_name": {
343+
"title": "Display Name",
344+
"minLength": 1,
345+
"maxLength": 150,
346+
"type": "string"
347+
},
348+
"description": {
349+
"title": "Description",
350+
"type": "string"
351+
},
352+
"group_admins": {
353+
"title": "Group Admins",
354+
"type": "array",
355+
"items": {
356+
"type": "string"
357+
}
358+
}
359+
},
360+
"required": [
361+
"display_name",
362+
"group_admins"
363+
]
364+
},
314365
"AccountStatus": {
315366
"title": "AccountStatus",
316367
"description": "A string enum representing the account status.",
@@ -367,6 +418,13 @@
367418
"type": "string",
368419
"format": "email"
369420
},
421+
"groups": {
422+
"title": "Groups",
423+
"type": "array",
424+
"items": {
425+
"$ref": "#/definitions/Group"
426+
}
427+
},
370428
"managers": {
371429
"title": "Managers",
372430
"type": "array",

pydatalab/src/pydatalab/login.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from flask_login import LoginManager, UserMixin
1111

1212
from pydatalab.models import Person
13-
from pydatalab.models.people import AccountStatus, Identity, IdentityType
13+
from pydatalab.models.people import AccountStatus, Group, Identity, IdentityType
1414
from pydatalab.models.utils import UserRole
1515
from pydatalab.mongo import flask_mongo
1616

@@ -68,6 +68,11 @@ def identities(self) -> List[Identity]:
6868
"""Returns the list of identities of the user."""
6969
return self.person.identities
7070

71+
@property
72+
def groups(self) -> List[Group]:
73+
"""Returns the list of groups that the user is a member of."""
74+
return self.person.groups
75+
7176
@property
7277
def identity_types(self) -> List[IdentityType]:
7378
"""Returns a list of the identity types associated with the user."""
@@ -88,6 +93,20 @@ def get_by_id_cached(user_id):
8893
return get_by_id(user_id)
8994

9095

96+
def groups_lookup() -> dict:
97+
return {
98+
"from": "groups",
99+
"let": {"group_ids": "$group_ids"},
100+
"pipeline": [
101+
{"$match": {"$expr": {"$in": ["$_id", {"$ifNull": ["$$group_ids", []]}]}}},
102+
{"$addFields": {"__order": {"$indexOfArray": ["$$group_ids", "$_id"]}}},
103+
{"$sort": {"__order": 1}},
104+
{"$project": {"_id": 1, "display_name": 1}},
105+
],
106+
"as": "groups",
107+
}
108+
109+
91110
def get_by_id(user_id: str) -> Optional[LoginUser]:
92111
"""Lookup the user database ID and create a new `LoginUser`
93112
with the relevant metadata.

pydatalab/src/pydatalab/models/people.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,27 @@ class AccountStatus(str, Enum):
9898
DEACTIVATED = "deactivated"
9999

100100

101+
class Group(Entry):
102+
"""A model that describes a group of users, for the sake
103+
of applying group permissions.
104+
105+
Each `Person` model can point to a given group.
106+
107+
"""
108+
109+
type: str = Field("groups", const=True)
110+
"""The entry type as a string."""
111+
112+
display_name: DisplayName
113+
"""The chosen display name for the group"""
114+
115+
description: Optional[str]
116+
"""A description of the group"""
117+
118+
group_admins: List[PyObjectId]
119+
"""A list of user IDs that can manage this group."""
120+
121+
101122
class Person(Entry):
102123
"""A model that describes an individual and their digital identities."""
103124

@@ -113,6 +134,9 @@ class Person(Entry):
113134
contact_email: Optional[EmailStr]
114135
"""In the case of multiple *verified* email identities, this email will be used as the primary contact."""
115136

137+
groups: Optional[List[Group]]
138+
"""A list of groups that this person belongs to."""
139+
116140
managers: Optional[List[PyObjectId]]
117141
"""A list of user IDs that can manage this person's items."""
118142

0 commit comments

Comments
 (0)