|
5 | 5 | import json |
6 | 6 | import re |
7 | 7 | from base64 import b64encode |
| 8 | +from collections.abc import Awaitable |
8 | 9 | from collections.abc import Callable |
9 | 10 | from datetime import date |
10 | 11 | from datetime import datetime |
|
65 | 66 |
|
66 | 67 | from ...version import Version as GraphQLVersion |
67 | 68 | from .filters import EmployeeFilter |
| 69 | +from .filters import ITSystemFilter |
68 | 70 | from .filters import ITUserFilter |
69 | 71 | from .filters import ManagerFilter |
70 | 72 | from .filters import OrganisationUnitFilter |
@@ -166,29 +168,6 @@ async def wrapper(*args: Any, **kwargs: Any) -> R | None: |
166 | 168 | return wrapper |
167 | 169 |
|
168 | 170 |
|
169 | | -def result_translation(mapper: Callable) -> Callable: |
170 | | - def wrapper(resolver_func: Callable) -> Callable: |
171 | | - @wraps(resolver_func) |
172 | | - async def mapped_resolver(*args: Any, **kwargs: Any) -> Any: |
173 | | - result = await resolver_func(*args, **kwargs) |
174 | | - return mapper(result) |
175 | | - |
176 | | - return mapped_resolver |
177 | | - |
178 | | - return wrapper |
179 | | - |
180 | | - |
181 | | -to_list = result_translation( |
182 | | - lambda result: list(chain.from_iterable(result.values())), |
183 | | -) |
184 | | -to_only = result_translation( |
185 | | - lambda result: only(chain.from_iterable(result.values())), |
186 | | -) |
187 | | -to_one = result_translation( |
188 | | - lambda result: one(chain.from_iterable(result.values())), |
189 | | -) |
190 | | - |
191 | | - |
192 | 171 | def uuid2list(uuid: UUID | None) -> list[UUID]: |
193 | 172 | """Convert an optional uuid to a list. |
194 | 173 |
|
@@ -404,6 +383,66 @@ async def validities( |
404 | 383 | ) |
405 | 384 |
|
406 | 385 |
|
| 386 | +ResolverResult = dict[UUID, list[MOObject]] |
| 387 | +ResolverFunction = Callable[..., Awaitable[ResolverResult]] |
| 388 | + |
| 389 | + |
| 390 | +def result_translation( |
| 391 | + mapper: Callable[[ResolverResult], R], |
| 392 | +) -> Callable[[ResolverFunction], Callable[..., Awaitable[R]]]: |
| 393 | + def wrapper( |
| 394 | + resolver_func: ResolverFunction, |
| 395 | + ) -> Callable[..., Awaitable[R]]: |
| 396 | + @wraps(resolver_func) |
| 397 | + async def mapped_resolver(*args: Any, **kwargs: Any) -> Any: |
| 398 | + result = await resolver_func(*args, **kwargs) |
| 399 | + return mapper(result) |
| 400 | + |
| 401 | + return mapped_resolver |
| 402 | + |
| 403 | + return wrapper |
| 404 | + |
| 405 | + |
| 406 | +def to_response_list( |
| 407 | + model: type[MOObject], |
| 408 | +) -> Callable[[ResolverFunction], Callable[..., Awaitable[list[Response[MOObject]]]]]: |
| 409 | + def result2response_list(result: ResolverResult) -> list[Response[MOObject]]: |
| 410 | + # The type checker really does not like the below code. |
| 411 | + # |
| 412 | + # Mypy says: 'error: Variable "model" is not valid as a type', however every |
| 413 | + # attept to appease mypy by fixing the typing has ended up making the code |
| 414 | + # non-functional on runtime. |
| 415 | + # |
| 416 | + # Additionally it complains about construction of the Response object being |
| 417 | + # illegal as it 'Expected no arguments to "Response" constructor', however |
| 418 | + # attempting to resolve this using Pydantic's 'parse_obj_as' results in an |
| 419 | + # 'Fields of type \"<class 'Response'>\" are not supported."' error from |
| 420 | + # strawberry on runtime, whether implemented as: |
| 421 | + # '[parse_obj_as(T, x) for x in xs]' or 'parse_obj_as(list[T], xs)'. |
| 422 | + # |
| 423 | + # If you try to fix this typing issues here, please increment the following |
| 424 | + # counter as a warning to the next guy: |
| 425 | + # |
| 426 | + # total_hours_wasted_here = 4 |
| 427 | + return [ |
| 428 | + Response[model](uuid=uuid, object_cache=objects) # type: ignore |
| 429 | + for uuid, objects in result.items() |
| 430 | + ] |
| 431 | + |
| 432 | + return result_translation(result2response_list) |
| 433 | + |
| 434 | + |
| 435 | +to_list = result_translation( |
| 436 | + lambda result: list(chain.from_iterable(result.values())), |
| 437 | +) |
| 438 | +to_only = result_translation( |
| 439 | + lambda result: only(chain.from_iterable(result.values())), |
| 440 | +) |
| 441 | +to_one = result_translation( |
| 442 | + lambda result: one(chain.from_iterable(result.values())), |
| 443 | +) |
| 444 | + |
| 445 | + |
407 | 446 | def response2model(response: Response[MOObject]) -> MOObject: |
408 | 447 | if not hasattr(response, "__orig_class__"): # pragma: no cover |
409 | 448 | raise ValueError( |
@@ -2569,6 +2608,39 @@ async def name(self, root: ITSystemRead) -> str: |
2569 | 2608 | async def user_key(self, root: ITSystemRead) -> str: |
2570 | 2609 | return root.user_key |
2571 | 2610 |
|
| 2611 | + roles: list[Response[LazyClass]] = strawberry.field( |
| 2612 | + resolver=to_response_list(LazyClass)( |
| 2613 | + seed_resolver( |
| 2614 | + class_resolver, |
| 2615 | + { |
| 2616 | + "it_system": lambda root: ITSystemFilter( |
| 2617 | + uuids=uuid2list(root.uuid), |
| 2618 | + # The following two arguments are not strictly necessary because |
| 2619 | + # we are filtering by UUIDs which handles dates differently than |
| 2620 | + # normal filters. |
| 2621 | + # If we were to instead filter by say 'user_keys' the arguments |
| 2622 | + # would be necessary. They are added here anyway to simplify the |
| 2623 | + # migration in the future when our filtering achieve consistent |
| 2624 | + # behavior across all filters. |
| 2625 | + from_date=None, |
| 2626 | + to_date=None, |
| 2627 | + ) |
| 2628 | + }, |
| 2629 | + ) |
| 2630 | + ), |
| 2631 | + description=dedent( |
| 2632 | + """\ |
| 2633 | + Rolebinding roles related to the IT-system. |
| 2634 | +
|
| 2635 | + Examples of user-keys: |
| 2636 | + * `"AD Read"` |
| 2637 | + * `"AD Write"` |
| 2638 | + * `"SAP Admin"` |
| 2639 | + """ |
| 2640 | + ), |
| 2641 | + permission_classes=[IsAuthenticatedPermission, gen_read_permission("class")], |
| 2642 | + ) |
| 2643 | + |
2572 | 2644 | # TODO: Document this |
2573 | 2645 | system_type: str | None = strawberry.auto |
2574 | 2646 |
|
|
0 commit comments