fastapi-rtk 1.0.8__py3-none-any.whl → 1.0.10__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.
- fastapi_rtk/__init__.py +0 -1
- fastapi_rtk/_version.py +1 -1
- fastapi_rtk/auth/auth.py +0 -9
- fastapi_rtk/bases/file_manager.py +12 -0
- fastapi_rtk/cli/commands/security.py +6 -6
- fastapi_rtk/db.py +1 -0
- fastapi_rtk/dependencies.py +110 -64
- fastapi_rtk/fastapi_react_toolkit.py +109 -161
- fastapi_rtk/file_managers/s3_file_manager.py +63 -32
- fastapi_rtk/security/sqla/apis.py +20 -5
- fastapi_rtk/security/sqla/models.py +8 -23
- fastapi_rtk/security/sqla/security_manager.py +367 -10
- fastapi_rtk/utils/hooks.py +7 -4
- {fastapi_rtk-1.0.8.dist-info → fastapi_rtk-1.0.10.dist-info}/METADATA +1 -1
- {fastapi_rtk-1.0.8.dist-info → fastapi_rtk-1.0.10.dist-info}/RECORD +18 -18
- {fastapi_rtk-1.0.8.dist-info → fastapi_rtk-1.0.10.dist-info}/WHEEL +0 -0
- {fastapi_rtk-1.0.8.dist-info → fastapi_rtk-1.0.10.dist-info}/entry_points.txt +0 -0
- {fastapi_rtk-1.0.8.dist-info → fastapi_rtk-1.0.10.dist-info}/licenses/LICENSE +0 -0
|
@@ -3,6 +3,8 @@ import typing
|
|
|
3
3
|
from datetime import datetime
|
|
4
4
|
|
|
5
5
|
import fastapi_users.exceptions
|
|
6
|
+
import sqlalchemy
|
|
7
|
+
import sqlalchemy.orm
|
|
6
8
|
from pydantic import BaseModel, Field
|
|
7
9
|
from sqlalchemy import select
|
|
8
10
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
@@ -11,7 +13,7 @@ from sqlalchemy.orm import Session
|
|
|
11
13
|
from ...const import logger
|
|
12
14
|
from ...globals import g
|
|
13
15
|
from ...setting import Setting
|
|
14
|
-
from ...utils import merge_schema, safe_call
|
|
16
|
+
from ...utils import T, lazy, merge_schema, safe_call
|
|
15
17
|
from .models import Api, Permission, PermissionApi, Role, User
|
|
16
18
|
|
|
17
19
|
__all__ = ["SecurityManager"]
|
|
@@ -28,6 +30,21 @@ class SecurityManager:
|
|
|
28
30
|
"""
|
|
29
31
|
|
|
30
32
|
toolkit: typing.Optional["FastAPIReactToolkit"]
|
|
33
|
+
builtin_roles = lazy(lambda: Setting.ROLES)
|
|
34
|
+
"""
|
|
35
|
+
The built-in roles defined in the settings.
|
|
36
|
+
|
|
37
|
+
Format:
|
|
38
|
+
```python
|
|
39
|
+
{
|
|
40
|
+
"role_name": [
|
|
41
|
+
(api_name1|api_name2|..., permission_name1|permission_name2|...),
|
|
42
|
+
...
|
|
43
|
+
],
|
|
44
|
+
...
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
"""
|
|
31
48
|
|
|
32
49
|
def __init__(self, toolkit: typing.Optional["FastAPIReactToolkit"] = None) -> None:
|
|
33
50
|
self.toolkit = toolkit
|
|
@@ -385,6 +402,273 @@ class SecurityManager:
|
|
|
385
402
|
-----------------------------------------
|
|
386
403
|
"""
|
|
387
404
|
|
|
405
|
+
def has_access_in_builtin_roles(
|
|
406
|
+
self, role_name: str, api_name: str, permission_name: str
|
|
407
|
+
):
|
|
408
|
+
"""
|
|
409
|
+
Checks if the given role has access to the specified API and permission in the built-in roles.
|
|
410
|
+
|
|
411
|
+
Args:
|
|
412
|
+
role_name (str): The name of the role to check.
|
|
413
|
+
api_name (str): The name of the API to check.
|
|
414
|
+
permission_name (str): The name of the permission to check.
|
|
415
|
+
|
|
416
|
+
Returns:
|
|
417
|
+
bool: True if the role has access, False otherwise.
|
|
418
|
+
"""
|
|
419
|
+
if role_name not in self.builtin_roles:
|
|
420
|
+
return False
|
|
421
|
+
|
|
422
|
+
for api, perm in self.builtin_roles[role_name]:
|
|
423
|
+
api_names = api.split("|")
|
|
424
|
+
perm_names = perm.split("|")
|
|
425
|
+
if api_name in api_names and permission_name in perm_names:
|
|
426
|
+
return True
|
|
427
|
+
return False
|
|
428
|
+
|
|
429
|
+
def get_roles_from_builtin_roles(self):
|
|
430
|
+
"""
|
|
431
|
+
Retrieves the names of the built-in roles.
|
|
432
|
+
|
|
433
|
+
Returns:
|
|
434
|
+
list[str]: The list of built-in role names.
|
|
435
|
+
"""
|
|
436
|
+
return list(self.builtin_roles.keys())
|
|
437
|
+
|
|
438
|
+
def get_api_permission_tuples_from_builtin_roles(self, role: str | None = None):
|
|
439
|
+
"""
|
|
440
|
+
Retrieves the API-permission tuples from the built-in roles.
|
|
441
|
+
|
|
442
|
+
Args:
|
|
443
|
+
role (str | None, optional): The name of the role to filter by. If None, retrieves from all roles. Defaults to None.
|
|
444
|
+
|
|
445
|
+
Returns:
|
|
446
|
+
list[tuple[str, str]]: The list of API-permission tuples.
|
|
447
|
+
"""
|
|
448
|
+
api_permission_tuples = list[tuple[str, str]]()
|
|
449
|
+
for role_name, role_api_permission_list in self.builtin_roles.items():
|
|
450
|
+
if role is not None and role != role_name:
|
|
451
|
+
continue
|
|
452
|
+
|
|
453
|
+
for api, perm in role_api_permission_list:
|
|
454
|
+
api_permission_tuples.append((api, perm))
|
|
455
|
+
return api_permission_tuples
|
|
456
|
+
|
|
457
|
+
def get_role_and_api_permission_tuples_from_builtin_roles(self):
|
|
458
|
+
"""
|
|
459
|
+
Retrieves the role and API-permission tuples from the built-in roles.
|
|
460
|
+
|
|
461
|
+
Returns:
|
|
462
|
+
list[tuple[str, list[tuple[str, str]]]]: The list of role and API-permission tuples.
|
|
463
|
+
"""
|
|
464
|
+
role_api_permission_tuples = list[tuple[str, list[tuple[str, str]]]]()
|
|
465
|
+
for role_name, role_api_permission_list in self.builtin_roles.items():
|
|
466
|
+
api_permission_list = list[tuple[str, str]]()
|
|
467
|
+
for api, perm in role_api_permission_list:
|
|
468
|
+
api_permission_list.append((api, perm))
|
|
469
|
+
role_api_permission_tuples.append((role_name, api_permission_list))
|
|
470
|
+
return role_api_permission_tuples
|
|
471
|
+
|
|
472
|
+
async def create_roles(
|
|
473
|
+
self,
|
|
474
|
+
roles: list[str],
|
|
475
|
+
*,
|
|
476
|
+
session: AsyncSession | Session = None,
|
|
477
|
+
raise_exception: bool = True,
|
|
478
|
+
):
|
|
479
|
+
"""
|
|
480
|
+
Creates new roles with the given names. Existing roles are not duplicated.
|
|
481
|
+
|
|
482
|
+
Args:
|
|
483
|
+
roles (list[str]): The names of the roles to create.
|
|
484
|
+
session (AsyncSession | Session, optional): The database session to use. If not given, a new session will be created. Defaults to None.
|
|
485
|
+
raise_exception (bool, optional): When set to True, raises an exception if an error occurs, otherwise returns None. Defaults to True.
|
|
486
|
+
|
|
487
|
+
Returns:
|
|
488
|
+
list[Role] | None: The created role objects if successful, else None.
|
|
489
|
+
|
|
490
|
+
Raises:
|
|
491
|
+
SomeException: Description of the exception raised, if any.
|
|
492
|
+
"""
|
|
493
|
+
return await self._create_entities(
|
|
494
|
+
Role,
|
|
495
|
+
roles,
|
|
496
|
+
session=session,
|
|
497
|
+
raise_exception=raise_exception,
|
|
498
|
+
on_after_create=lambda role: logger.info(f"ADDING ROLE {role}"),
|
|
499
|
+
)
|
|
500
|
+
|
|
501
|
+
async def create_permissions(
|
|
502
|
+
self,
|
|
503
|
+
permissions: list[str],
|
|
504
|
+
*,
|
|
505
|
+
session: AsyncSession | Session = None,
|
|
506
|
+
raise_exception: bool = True,
|
|
507
|
+
):
|
|
508
|
+
"""
|
|
509
|
+
Creates new permissions with the given names. Existing permissions are not duplicated.
|
|
510
|
+
|
|
511
|
+
Args:
|
|
512
|
+
permissions (list[str]): The names of the permissions to create.
|
|
513
|
+
session (AsyncSession | Session, optional): The database session to use. If not given, a new session will be created. Defaults to None.
|
|
514
|
+
raise_exception (bool, optional): When set to True, raises an exception if an error occurs, otherwise returns None. Defaults to True.
|
|
515
|
+
|
|
516
|
+
Returns:
|
|
517
|
+
list[Permission] | None: The created permission objects if successful, else None.
|
|
518
|
+
|
|
519
|
+
Raises:
|
|
520
|
+
SomeException: Description of the exception raised, if any.
|
|
521
|
+
"""
|
|
522
|
+
return await self._create_entities(
|
|
523
|
+
Permission,
|
|
524
|
+
permissions,
|
|
525
|
+
session=session,
|
|
526
|
+
raise_exception=raise_exception,
|
|
527
|
+
on_after_create=lambda permission: logger.info(
|
|
528
|
+
f"ADDING PERMISSION {permission}"
|
|
529
|
+
),
|
|
530
|
+
)
|
|
531
|
+
|
|
532
|
+
async def create_apis(
|
|
533
|
+
self,
|
|
534
|
+
apis: list[str],
|
|
535
|
+
*,
|
|
536
|
+
session: AsyncSession | Session = None,
|
|
537
|
+
raise_exception: bool = True,
|
|
538
|
+
):
|
|
539
|
+
"""
|
|
540
|
+
Creates new APIs with the given names. Existing APIs are not duplicated.
|
|
541
|
+
|
|
542
|
+
Args:
|
|
543
|
+
apis (list[str]): The names of the APIs to create.
|
|
544
|
+
session (AsyncSession | Session, optional): The database session to use. If not given, a new session will be created. Defaults to None.
|
|
545
|
+
raise_exception (bool, optional): When set to True, raises an exception if an error occurs, otherwise returns None. Defaults to True.
|
|
546
|
+
|
|
547
|
+
Returns:
|
|
548
|
+
list[Api] | None: The created API objects if successful, else None.
|
|
549
|
+
|
|
550
|
+
Raises:
|
|
551
|
+
SomeException: Description of the exception raised, if any.
|
|
552
|
+
"""
|
|
553
|
+
return await self._create_entities(
|
|
554
|
+
Api,
|
|
555
|
+
apis,
|
|
556
|
+
session=session,
|
|
557
|
+
raise_exception=raise_exception,
|
|
558
|
+
on_after_create=lambda api: logger.info(f"ADDING API {api}"),
|
|
559
|
+
)
|
|
560
|
+
|
|
561
|
+
async def associate_list_of_permission_with_api(
|
|
562
|
+
self,
|
|
563
|
+
permission_api_tuples: list[tuple[Permission, Api]],
|
|
564
|
+
*,
|
|
565
|
+
session: AsyncSession | Session = None,
|
|
566
|
+
raise_exception: bool = True,
|
|
567
|
+
):
|
|
568
|
+
"""
|
|
569
|
+
Associates a list of permissions with APIs. Existing associations are not duplicated.
|
|
570
|
+
|
|
571
|
+
Args:
|
|
572
|
+
permission_api_tuples (list[tuple[Permission, Api]]): A list of tuples containing Permission and Api objects to associate.
|
|
573
|
+
session (AsyncSession | Session, optional): The database session to use. If not given, a new session will be created. Defaults to None.
|
|
574
|
+
raise_exception (bool, optional): When set to True, raises an exception if an error occurs, otherwise returns None. Defaults to True.
|
|
575
|
+
|
|
576
|
+
Raises:
|
|
577
|
+
SomeException: Description of the exception raised, if any.
|
|
578
|
+
"""
|
|
579
|
+
try:
|
|
580
|
+
if not session:
|
|
581
|
+
async with db.session() as session:
|
|
582
|
+
await self.associate_list_of_permission_with_api(
|
|
583
|
+
permission_api_tuples,
|
|
584
|
+
session=session,
|
|
585
|
+
raise_exception=raise_exception,
|
|
586
|
+
)
|
|
587
|
+
return
|
|
588
|
+
|
|
589
|
+
conditions = []
|
|
590
|
+
query = select(PermissionApi).options(
|
|
591
|
+
sqlalchemy.orm.joinedload(PermissionApi.api),
|
|
592
|
+
sqlalchemy.orm.joinedload(PermissionApi.permission),
|
|
593
|
+
sqlalchemy.orm.selectinload(PermissionApi.roles),
|
|
594
|
+
)
|
|
595
|
+
for permission, api in permission_api_tuples:
|
|
596
|
+
conditions.append(
|
|
597
|
+
sqlalchemy.and_(
|
|
598
|
+
PermissionApi.permission_id == permission.id,
|
|
599
|
+
PermissionApi.api_id == api.id,
|
|
600
|
+
)
|
|
601
|
+
)
|
|
602
|
+
query = query.where(sqlalchemy.or_(*conditions))
|
|
603
|
+
result = await safe_call(session.scalars(query))
|
|
604
|
+
existing_permission_apis = list(result.all())
|
|
605
|
+
|
|
606
|
+
new_tuples = list[tuple[Permission, Api]]()
|
|
607
|
+
for permission, api in permission_api_tuples:
|
|
608
|
+
exists = False
|
|
609
|
+
for permission_api in existing_permission_apis:
|
|
610
|
+
if (
|
|
611
|
+
permission_api.permission.id == permission.id
|
|
612
|
+
and permission_api.api.id == api.id
|
|
613
|
+
):
|
|
614
|
+
exists = True
|
|
615
|
+
break
|
|
616
|
+
if not exists:
|
|
617
|
+
new_tuples.append((permission, api))
|
|
618
|
+
|
|
619
|
+
new_permission_apis = list[PermissionApi]()
|
|
620
|
+
for permission, api in new_tuples:
|
|
621
|
+
permission_api = PermissionApi(permission=permission, api=api, roles=[])
|
|
622
|
+
session.add(permission_api)
|
|
623
|
+
new_permission_apis.append(permission_api)
|
|
624
|
+
logger.info(f"ASSOCIATING PERMISSION {permission} WITH API {api}")
|
|
625
|
+
await safe_call(session.commit())
|
|
626
|
+
return existing_permission_apis + new_permission_apis
|
|
627
|
+
except Exception as e:
|
|
628
|
+
if not raise_exception:
|
|
629
|
+
return
|
|
630
|
+
raise e
|
|
631
|
+
|
|
632
|
+
async def associate_list_of_role_with_permission_api(
|
|
633
|
+
self,
|
|
634
|
+
role_permission_api_tuples: list[tuple[Role, PermissionApi]],
|
|
635
|
+
*,
|
|
636
|
+
session: AsyncSession | Session = None,
|
|
637
|
+
raise_exception: bool = True,
|
|
638
|
+
):
|
|
639
|
+
"""
|
|
640
|
+
Associates a list of roles with permission APIs. Existing associations are not duplicated.
|
|
641
|
+
|
|
642
|
+
Args:
|
|
643
|
+
role_permission_api_tuples (list[tuple[Role, PermissionApi]]): A list of tuples containing Role and PermissionApi objects to associate.
|
|
644
|
+
session (AsyncSession | Session, optional): The database session to use. If not given, a new session will be created. Defaults to None.
|
|
645
|
+
raise_exception (bool, optional): When set to True, raises an exception if an error occurs, otherwise returns None. Defaults to True.
|
|
646
|
+
|
|
647
|
+
Raises:
|
|
648
|
+
SomeException: Description of the exception raised, if any.
|
|
649
|
+
"""
|
|
650
|
+
try:
|
|
651
|
+
if not session:
|
|
652
|
+
async with db.session() as session:
|
|
653
|
+
await self.associate_list_of_role_with_permission_api(
|
|
654
|
+
role_permission_api_tuples,
|
|
655
|
+
session=session,
|
|
656
|
+
raise_exception=raise_exception,
|
|
657
|
+
)
|
|
658
|
+
return
|
|
659
|
+
|
|
660
|
+
for role, permission_api in role_permission_api_tuples:
|
|
661
|
+
if role not in permission_api.roles:
|
|
662
|
+
permission_api.roles.append(role)
|
|
663
|
+
logger.info(
|
|
664
|
+
f"ASSOCIATING ROLE {role} WITH PERMISSION API {permission_api}"
|
|
665
|
+
)
|
|
666
|
+
await safe_call(session.commit())
|
|
667
|
+
except Exception as e:
|
|
668
|
+
if not raise_exception:
|
|
669
|
+
return
|
|
670
|
+
raise e
|
|
671
|
+
|
|
388
672
|
async def cleanup(self, *, session: AsyncSession | Session = None):
|
|
389
673
|
"""
|
|
390
674
|
Cleanup unused permissions from apis and roles.
|
|
@@ -404,13 +688,12 @@ class SecurityManager:
|
|
|
404
688
|
"FastAPIReactToolkit instance not provided, you must provide it to use this function."
|
|
405
689
|
)
|
|
406
690
|
|
|
407
|
-
api_permission_tuples =
|
|
691
|
+
api_permission_tuples = self.get_api_permission_tuples_from_builtin_roles()
|
|
408
692
|
apis = [api.__class__.__name__ for api in self.toolkit.apis]
|
|
409
693
|
permissions = self.toolkit.total_permissions()
|
|
410
|
-
for
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
permissions.append(permission)
|
|
694
|
+
for api, permission in api_permission_tuples:
|
|
695
|
+
apis.append(api)
|
|
696
|
+
permissions.append(permission)
|
|
414
697
|
|
|
415
698
|
# Clean up unused permissions
|
|
416
699
|
unused_permissions = await safe_call(
|
|
@@ -428,14 +711,20 @@ class SecurityManager:
|
|
|
428
711
|
logger.info(f"DELETING API {api} AND ITS ASSOCIATIONS")
|
|
429
712
|
await safe_call(session.delete(api))
|
|
430
713
|
|
|
431
|
-
roles =
|
|
714
|
+
roles = self.get_roles_from_builtin_roles()
|
|
432
715
|
if g.admin_role is not None:
|
|
433
716
|
roles.append(g.admin_role)
|
|
434
717
|
|
|
435
718
|
# Clean up existing permission-apis, that are no longer connected to any roles
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
719
|
+
permission_apis_in_db = await safe_call(
|
|
720
|
+
session.scalars(
|
|
721
|
+
select(PermissionApi).options(
|
|
722
|
+
sqlalchemy.orm.selectinload(PermissionApi.roles)
|
|
723
|
+
)
|
|
724
|
+
)
|
|
725
|
+
)
|
|
726
|
+
for permission_api in permission_apis_in_db:
|
|
727
|
+
for role in permission_api.roles:
|
|
439
728
|
if role.name not in roles:
|
|
440
729
|
permission_api.roles.remove(role)
|
|
441
730
|
logger.info(
|
|
@@ -443,3 +732,71 @@ class SecurityManager:
|
|
|
443
732
|
)
|
|
444
733
|
|
|
445
734
|
await safe_call(session.commit())
|
|
735
|
+
|
|
736
|
+
"""
|
|
737
|
+
-----------------------------------------
|
|
738
|
+
HELPER FUNCTIONS
|
|
739
|
+
-----------------------------------------
|
|
740
|
+
"""
|
|
741
|
+
|
|
742
|
+
async def _create_entities(
|
|
743
|
+
self,
|
|
744
|
+
entity_class: typing.Type[T],
|
|
745
|
+
names: list[str],
|
|
746
|
+
*,
|
|
747
|
+
session: AsyncSession | Session = None,
|
|
748
|
+
raise_exception: bool = True,
|
|
749
|
+
on_after_create: typing.Optional[
|
|
750
|
+
typing.Callable[[T], typing.Awaitable[None] | None]
|
|
751
|
+
] = None,
|
|
752
|
+
):
|
|
753
|
+
"""
|
|
754
|
+
Helper function to create new entities with the given names.
|
|
755
|
+
Existing entities are not duplicated.
|
|
756
|
+
|
|
757
|
+
Args:
|
|
758
|
+
entity_class (typing.Type[T]): The entity class to create.
|
|
759
|
+
names (list[str]): The names of the entities to create.
|
|
760
|
+
session (AsyncSession | Session, optional): The database session to use. If not given, a new session will be created. Defaults to None.
|
|
761
|
+
raise_exception (bool, optional): When set to True, raises an exception if an error occurs, otherwise returns None. Defaults to True.
|
|
762
|
+
on_after_create (Optional[Callable[[T], Awaitable[None] | None]], optional): An optional callback function to be called after each entity is created. Defaults to None.
|
|
763
|
+
|
|
764
|
+
Returns:
|
|
765
|
+
list[T] | None: The created entity objects if successful, else None.
|
|
766
|
+
|
|
767
|
+
Raises:
|
|
768
|
+
Exception: If an error occurs and raise_exception is True.
|
|
769
|
+
"""
|
|
770
|
+
try:
|
|
771
|
+
if not session:
|
|
772
|
+
async with db.session() as session:
|
|
773
|
+
return await self._create_entities(
|
|
774
|
+
entity_class,
|
|
775
|
+
names,
|
|
776
|
+
session=session,
|
|
777
|
+
raise_exception=raise_exception,
|
|
778
|
+
)
|
|
779
|
+
|
|
780
|
+
# Check for existing entities
|
|
781
|
+
result = await safe_call(
|
|
782
|
+
session.scalars(
|
|
783
|
+
select(entity_class).where(entity_class.name.in_(names))
|
|
784
|
+
)
|
|
785
|
+
)
|
|
786
|
+
existing_entities = list(result.all())
|
|
787
|
+
existing_names = [entity.name for entity in existing_entities]
|
|
788
|
+
|
|
789
|
+
new_names = [name for name in names if name not in existing_names]
|
|
790
|
+
new_entities = list[T]()
|
|
791
|
+
for name in new_names:
|
|
792
|
+
entity = entity_class(name=name)
|
|
793
|
+
session.add(entity)
|
|
794
|
+
new_entities.append(entity)
|
|
795
|
+
if on_after_create:
|
|
796
|
+
await safe_call(on_after_create(entity))
|
|
797
|
+
await safe_call(session.commit())
|
|
798
|
+
return existing_entities + new_entities
|
|
799
|
+
except Exception as e:
|
|
800
|
+
if not raise_exception:
|
|
801
|
+
return
|
|
802
|
+
raise e
|
fastapi_rtk/utils/hooks.py
CHANGED
|
@@ -4,16 +4,19 @@ import typing
|
|
|
4
4
|
__all__ = ["hooks"]
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
def hooks(
|
|
7
|
+
def hooks(
|
|
8
|
+
pre: typing.Callable[..., None] | None = None,
|
|
9
|
+
post: typing.Callable[..., None] | None = None,
|
|
10
|
+
):
|
|
8
11
|
"""
|
|
9
12
|
Decorator to add optional pre and post hook methods to a function.
|
|
10
13
|
|
|
11
14
|
Args:
|
|
12
|
-
pre (Callable): Function to run before the main function.
|
|
13
|
-
post (Callable): Function to run after the main function.
|
|
15
|
+
pre (typing.Callable[..., None] | None): Function to run before the main function. Defaults to None.
|
|
16
|
+
post (typing.Callable[..., None] | None): Function to run after the main function. Defaults to None.
|
|
14
17
|
|
|
15
18
|
Returns:
|
|
16
|
-
Callable: The decorated function.
|
|
19
|
+
typing.Callable[..., typing.Any]: The decorated function.
|
|
17
20
|
"""
|
|
18
21
|
|
|
19
22
|
def decorator(func):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastapi-rtk
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.10
|
|
4
4
|
Summary: A package that provides a set of tools to build a FastAPI application with a Class-Based CRUD API.
|
|
5
5
|
Project-URL: Homepage, https://codeberg.org/datatactics/fastapi-rtk
|
|
6
6
|
Project-URL: Issues, https://codeberg.org/datatactics/fastapi-rtk/issues
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
fastapi_rtk/__init__.py,sha256=
|
|
2
|
-
fastapi_rtk/_version.py,sha256=
|
|
1
|
+
fastapi_rtk/__init__.py,sha256=Lg6Er5blOMcbtQSRJMNWbRQ1VX4PWEPMVFm2ie5r8mA,6183
|
|
2
|
+
fastapi_rtk/_version.py,sha256=5vGk-8GWz6jojEu9w36UP5aNA0LuiwgbNSJ8Umn2rLA,23
|
|
3
3
|
fastapi_rtk/apis.py,sha256=6X_Lhl98m7lKrDRybg2Oe24pLFLJ29eCOQSwCAvpKhY,172
|
|
4
4
|
fastapi_rtk/config.py,sha256=9PZF9E5i1gxmnsZEprZZKxVHSk0dFEklJSplX9NEqdo,14036
|
|
5
5
|
fastapi_rtk/const.py,sha256=sEj_cYeerj9pVwbCu0k5Sy1EYpdr1EHzUjqqbnporgc,4905
|
|
6
|
-
fastapi_rtk/db.py,sha256=
|
|
6
|
+
fastapi_rtk/db.py,sha256=gItbbRYYAtAF7_1YqaZGBeQY5_E0cKvomGEzcCjIhpg,24548
|
|
7
7
|
fastapi_rtk/decorators.py,sha256=HqAFSiO0l5_M0idWs0IcY24FdzbAcDQDQoifM_WgZAQ,14515
|
|
8
|
-
fastapi_rtk/dependencies.py,sha256=
|
|
8
|
+
fastapi_rtk/dependencies.py,sha256=jlcsMrh83yrJsgXvpWJet_mjqwDP3nBZfPSg4Lq8KKE,7757
|
|
9
9
|
fastapi_rtk/exceptions.py,sha256=P0qwd4VkeWFotgMVQHgmdT1NphFQaEznKLFIvJzW4Zs,2594
|
|
10
|
-
fastapi_rtk/fastapi_react_toolkit.py,sha256=
|
|
10
|
+
fastapi_rtk/fastapi_react_toolkit.py,sha256=lvtieBLzCAlozKQU9dkAUVoW7Ofi1ncri_hDyeHazF4,29803
|
|
11
11
|
fastapi_rtk/filters.py,sha256=weCH3suCxpGJQYmwhj9D1iAqMPiRnmbRiN7stK0rhoE,181
|
|
12
12
|
fastapi_rtk/globals.py,sha256=TcoMHCueM7sFwZ8iYorUe4q-3KpVFfV04RAPuMTYFKY,8863
|
|
13
13
|
fastapi_rtk/manager.py,sha256=J86sBByj6E1kZ3CRS0NayI0n5firrfMhAU2d58mz0JM,33965
|
|
@@ -23,7 +23,7 @@ fastapi_rtk/api/__init__.py,sha256=MwFR7HHppnhbjZGg3sOdQ6nqy9uxnHHXvicpswNFMNA,2
|
|
|
23
23
|
fastapi_rtk/api/base_api.py,sha256=42I9v3b25lqxNAMDGEtajA5-btIDSyUWF0xMDgGkA8c,8078
|
|
24
24
|
fastapi_rtk/api/model_rest_api.py,sha256=R-zdfDK6QiVb8u6EBTpZt7cqvH4kP86udNMxdJRiphQ,105254
|
|
25
25
|
fastapi_rtk/auth/__init__.py,sha256=iX7O41NivBYDfdomEaqm4lUx9KD17wI4g3EFLF6kUTw,336
|
|
26
|
-
fastapi_rtk/auth/auth.py,sha256=
|
|
26
|
+
fastapi_rtk/auth/auth.py,sha256=F2qZoR7go_7FnvVJrDxUCd6vtRz5XW8yyOv143MWPts,20664
|
|
27
27
|
fastapi_rtk/auth/hashers/__init__.py,sha256=uBThFj2VPPSMSioxYTktNiM4-mVgtDAjTpKA3ZzWxxs,110
|
|
28
28
|
fastapi_rtk/auth/hashers/pbkdf2.py,sha256=EeusoypVDHVuxneoPP2aXOPpyCwxx_5O22qMeDW51b0,919
|
|
29
29
|
fastapi_rtk/auth/hashers/scrypt.py,sha256=CPGe6vzj7hlKTl_MKDGSgKQW927EpPkgpGM7mVO5MW0,902
|
|
@@ -60,7 +60,7 @@ fastapi_rtk/backends/sqla/extensions/geoalchemy2/filters.py,sha256=L1WgO7UzWuAgs
|
|
|
60
60
|
fastapi_rtk/backends/sqla/extensions/geoalchemy2/geometry_converter.py,sha256=sckNoxPE8ApKCLgBZzE_2dokXrM6mIXvMguHZvyJzIM,3891
|
|
61
61
|
fastapi_rtk/bases/__init__.py,sha256=v3tMVuX20UbvjI_mTWpDAePWAA38e3pjlYEiICgY4j8,440
|
|
62
62
|
fastapi_rtk/bases/db.py,sha256=D27BhF89J0OaLHjALDCa85eNf35lBaTz6VV7EDa4wuM,18711
|
|
63
|
-
fastapi_rtk/bases/file_manager.py,sha256=
|
|
63
|
+
fastapi_rtk/bases/file_manager.py,sha256=n6yRY0jh60itXZt0R3oaSN-2Q_CTRswX1BghE7GN4Sk,8791
|
|
64
64
|
fastapi_rtk/bases/filter.py,sha256=XmWTcLaIcBj9pKF1PMAKdwSnZNpdT8Df3uLeUIOGUDE,1840
|
|
65
65
|
fastapi_rtk/bases/interface.py,sha256=Cq9Duxa3w-tw342P424h88fc0_X1DoxCdTa3rAN-6jM,45380
|
|
66
66
|
fastapi_rtk/bases/model.py,sha256=nUZf0AVs0Mzqh2u_ALiRNYN1bfOU9PzYLvEFHDQ57Y0,1692
|
|
@@ -73,7 +73,7 @@ fastapi_rtk/cli/types.py,sha256=ezJjljcofwSI4HlDz2JWe0oVY9IA6hVvgx7IEWBkyRQ,1364
|
|
|
73
73
|
fastapi_rtk/cli/utils.py,sha256=v7sfL1-S3XYSQ40WTD-CYcH77EfJTcKhuD3jaAImYc8,6285
|
|
74
74
|
fastapi_rtk/cli/commands/__init__.py,sha256=iFkU03MOUgHoAmmyF5FmUxA6wD1YN59JqqP4WD5n6Dk,524
|
|
75
75
|
fastapi_rtk/cli/commands/export.py,sha256=4OuFyljUxSvdyZc0bYzzLfnahJvSYN38fxAUPopoH4M,17572
|
|
76
|
-
fastapi_rtk/cli/commands/security.py,sha256=
|
|
76
|
+
fastapi_rtk/cli/commands/security.py,sha256=tZOUVSbsgBFXjH7_vfH6GMKH5pKkRuhVl8TTh7V8plA,8880
|
|
77
77
|
fastapi_rtk/cli/commands/translate.py,sha256=v6s0XentYi5wLzPEd7qc6QUjgdn6wt89dvTbWzUPeOY,10508
|
|
78
78
|
fastapi_rtk/cli/commands/db/__init__.py,sha256=2clkGMUpGY0czSUaBql8fFSd8YrSJ0oGlzkpBZejjd0,14128
|
|
79
79
|
fastapi_rtk/cli/commands/db/templates/fastapi/README,sha256=dNsmYPHI9RJkhAIE18JqVmXhdJ21OCeQs8GP5DyA8Yo,47
|
|
@@ -87,7 +87,7 @@ fastapi_rtk/cli/commands/db/templates/fastapi-multidb/script.py.mako,sha256=o02U
|
|
|
87
87
|
fastapi_rtk/file_managers/__init__.py,sha256=RZzSSUDq_cIv4MeVePRBGR0mbEiJua7WKccfE6IAawk,198
|
|
88
88
|
fastapi_rtk/file_managers/file_manager.py,sha256=YJzKWtwVOiIYS4-W0CfadYhhWLydNRJ7D_T9vdzcIdU,2612
|
|
89
89
|
fastapi_rtk/file_managers/image_manager.py,sha256=S2mcBuXOzXWlPhmq1in76kRmNKGYrIeEqDMs-c5KXo8,573
|
|
90
|
-
fastapi_rtk/file_managers/s3_file_manager.py,sha256=
|
|
90
|
+
fastapi_rtk/file_managers/s3_file_manager.py,sha256=wjSyAoNrpDa5-SS__hK6Grajm1ZLOQZX9mXptjPd4lY,5538
|
|
91
91
|
fastapi_rtk/file_managers/s3_image_manager.py,sha256=YLPARdmffA_prMPmm5Mzupaz0IakxWgWL7hWaLSznm0,352
|
|
92
92
|
fastapi_rtk/lang/__init__.py,sha256=zJejpbIXx1O-nSuWwrCYgr5f5EtwjYW6kh8jRy_Yo0U,68
|
|
93
93
|
fastapi_rtk/lang/babel.cfg,sha256=ahkzg8wUKyl9G9UqkgAyWEtRlCnaWkjStM5c4FhKuUE,18
|
|
@@ -102,9 +102,9 @@ fastapi_rtk/lang/translations/en/LC_MESSAGES/messages.mo,sha256=Oi0vH4JgE6QmBcbh
|
|
|
102
102
|
fastapi_rtk/lang/translations/en/LC_MESSAGES/messages.po,sha256=GcgnXbNEQyhPM_E1urhOyhsZJxfSl2JMjMC7rBbMzas,6781
|
|
103
103
|
fastapi_rtk/security/__init__.py,sha256=XkYZ_GO2opdyQS_LJwbCH1C6SUkNfLUvLkpFhcO7ZlI,86
|
|
104
104
|
fastapi_rtk/security/sqla/__init__.py,sha256=qKh1mGQezDtMzvRzxzfHZRyKVaks-O7PXrOx16ekSZA,88
|
|
105
|
-
fastapi_rtk/security/sqla/apis.py,sha256=
|
|
106
|
-
fastapi_rtk/security/sqla/models.py,sha256=
|
|
107
|
-
fastapi_rtk/security/sqla/security_manager.py,sha256=
|
|
105
|
+
fastapi_rtk/security/sqla/apis.py,sha256=8Qtd1G73i2TaA9Euo63naaB8d_I9r4EHL8DWtWNJEfs,10699
|
|
106
|
+
fastapi_rtk/security/sqla/models.py,sha256=rEXpbljTMlTkiDp0VIxRXant8xN-WTjpqgQkr-ElXeM,7865
|
|
107
|
+
fastapi_rtk/security/sqla/security_manager.py,sha256=ui0g2cH8Z-YjDuqszcstyj6Li8U4IpuVV4bAVaD69Lc,31395
|
|
108
108
|
fastapi_rtk/utils/__init__.py,sha256=0X4BwrVDl4S3mB7DLyHaZVednefMjRIjBIDT3yv_CHM,1875
|
|
109
109
|
fastapi_rtk/utils/async_task_runner.py,sha256=HzykQSdeAmNjZfVB5vUDVwrSCVFr8__67ACQk60pSsk,15545
|
|
110
110
|
fastapi_rtk/utils/class_factory.py,sha256=jlVw8yCh-tYsMnR5Hm8fgxtL0kvXwnhe6DPJA1sUh7k,598
|
|
@@ -112,7 +112,7 @@ fastapi_rtk/utils/csv_json_converter.py,sha256=7szrPiB7DrK5S-s2GaHVCmEP9_OXk9RFw
|
|
|
112
112
|
fastapi_rtk/utils/deep_merge.py,sha256=PHtKJgXfCngOBGVliX9aVlEFcwCxr-GlzU-w6vjgAIs,2426
|
|
113
113
|
fastapi_rtk/utils/extender_mixin.py,sha256=eu22VAZJIf-r_uD-zVn_2IzvknfuUkmEHn9oo-0KU0k,1388
|
|
114
114
|
fastapi_rtk/utils/flask_appbuilder_utils.py,sha256=nPLQIczDZgKElMtqBRSo_aPJZMOnPs7fRyjqKUtPDbo,2276
|
|
115
|
-
fastapi_rtk/utils/hooks.py,sha256=
|
|
115
|
+
fastapi_rtk/utils/hooks.py,sha256=iGE8HTfDDVfQm7yeD3WqPB8_I1FXFGpBdl3ngyjaRbY,901
|
|
116
116
|
fastapi_rtk/utils/lazy.py,sha256=SlVYQ-RHRcp6pGmcslVNc5lKs5GOSjqLcRsQsSWIB0s,10352
|
|
117
117
|
fastapi_rtk/utils/merge_schema.py,sha256=AStYAS_t2idD63_YQri8sBcRM1jaq0kapjYUpI27syg,1398
|
|
118
118
|
fastapi_rtk/utils/multiple_async_contexts.py,sha256=-juAliUeG4XI1J-p31KknsJvzvM5vX0gXVXst_xZUIo,557
|
|
@@ -126,8 +126,8 @@ fastapi_rtk/utils/timezone.py,sha256=62S0pPWuDFFXxV1YTFCsc4uKiSP_Ba36Fv7S3gYjfhs
|
|
|
126
126
|
fastapi_rtk/utils/update_signature.py,sha256=PIzZgNpGEwvDNgQ3G51Zi-QhVV3mbxvUvSwDwf_-yYs,2209
|
|
127
127
|
fastapi_rtk/utils/use_default_when_none.py,sha256=H2HqhKy_8eYk3i1xijEjuaKak0oWkMIkrdz6T7DK9QU,469
|
|
128
128
|
fastapi_rtk/utils/werkzeug.py,sha256=1Gv-oyqSmhVGrmNbB9fDqpqJzPpANOzWf4zMMrhW9UA,3245
|
|
129
|
-
fastapi_rtk-1.0.
|
|
130
|
-
fastapi_rtk-1.0.
|
|
131
|
-
fastapi_rtk-1.0.
|
|
132
|
-
fastapi_rtk-1.0.
|
|
133
|
-
fastapi_rtk-1.0.
|
|
129
|
+
fastapi_rtk-1.0.10.dist-info/METADATA,sha256=FWjDKJQ40ntwOVswJo9zqpKqasIu4dugohhYo7bWaCU,1271
|
|
130
|
+
fastapi_rtk-1.0.10.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
131
|
+
fastapi_rtk-1.0.10.dist-info/entry_points.txt,sha256=UuTkxSVIokSlVN28TMhoxzRRUaPxlVRSH3Gsx6yip60,53
|
|
132
|
+
fastapi_rtk-1.0.10.dist-info/licenses/LICENSE,sha256=NDrWi4Qwcxal3u1r2lBWGA6TVh3OeW7yMan098mQz98,1073
|
|
133
|
+
fastapi_rtk-1.0.10.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|