fastapi-rtk 1.0.9__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/_version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "1.0.9"
1
+ __version__ = "1.0.10"
@@ -238,7 +238,7 @@ async def _check_roles(name: str, create: bool = False):
238
238
  if not role:
239
239
  if not create:
240
240
  raise Exception(f"Role {name} does not exist")
241
- await g.current_app.security.create_role(name=name, session=session)
241
+ await g.current_app.sm.create_role(name=name, session=session)
242
242
 
243
243
 
244
244
  async def _create_user(
@@ -255,7 +255,7 @@ async def _create_user(
255
255
  """
256
256
  if role:
257
257
  await _check_roles(role, create=create_role)
258
- return await g.current_app.security.create_user(
258
+ return await g.current_app.sm.create_user(
259
259
  email=email,
260
260
  username=username,
261
261
  password=password,
@@ -269,8 +269,8 @@ async def _reset_password(email_or_username: str, password: str):
269
269
  """
270
270
  Reset user password.
271
271
  """
272
- user = await g.current_app.security.get_user(email_or_username)
273
- return await g.current_app.security.reset_password(user, password)
272
+ user = await g.current_app.sm.get_user(email_or_username)
273
+ return await g.current_app.sm.reset_password(user, password)
274
274
 
275
275
 
276
276
  async def export_data(
@@ -281,7 +281,7 @@ async def export_data(
281
281
  """
282
282
  Export data.
283
283
  """
284
- data = await g.current_app.security.export_data(data, type)
284
+ data = await g.current_app.sm.export_data(data, type)
285
285
  with open(file_path, "w") as f:
286
286
  f.write(data)
287
287
 
@@ -290,4 +290,4 @@ async def _cleanup():
290
290
  """
291
291
  Cleanup unused permissions from apis and roles.
292
292
  """
293
- await g.current_app.security.cleanup()
293
+ await g.current_app.sm.cleanup()
fastapi_rtk/db.py CHANGED
@@ -121,6 +121,7 @@ class UserDatabase(SQLAlchemyUserDatabase[UP, ID]):
121
121
  raise NotImplementedError()
122
122
 
123
123
  await safe_call(self.session.refresh(user))
124
+ await user.load("oauth_accounts")
124
125
  oauth_account = self.oauth_account_table(**create_dict)
125
126
  self.session.add(oauth_account)
126
127
  user.oauth_accounts.append(oauth_account)
@@ -85,7 +85,7 @@ def current_permissions(api: BaseApi):
85
85
  """
86
86
 
87
87
  async def current_permissions_depedency(_=Depends(_ensure_roles)):
88
- sm = g.current_app.security
88
+ sm = g.current_app.sm
89
89
  api_name = api.__class__.__name__
90
90
  permissions = set[str]()
91
91
  db_role_ids = list[int]()
@@ -154,10 +154,10 @@ def has_access_dependency(
154
154
 
155
155
  async def check_permission():
156
156
  _ensure_roles(ErrorCode.PERMISSION_DENIED)
157
+ sm = g.current_app.sm
157
158
 
158
159
  # First, check built-in roles (avoiding unnecessary DB queries)
159
160
  # This also covers the case for API and permission name with pipes
160
- sm = g.current_app.security
161
161
  if any(
162
162
  sm.has_access_in_builtin_roles(
163
163
  role.name, api.__class__.__name__, permission
@@ -178,8 +178,9 @@ def has_access_dependency(
178
178
  )
179
179
 
180
180
  api_name = api.__class__.__name__
181
- exist_query = (
182
- sqlalchemy.select(Permission)
181
+ stmt = (
182
+ sqlalchemy.select(sqlalchemy.literal(True))
183
+ .select_from(Permission)
183
184
  .join(PermissionApi)
184
185
  .join(PermissionApi.roles)
185
186
  .join(Api)
@@ -188,11 +189,10 @@ def has_access_dependency(
188
189
  Permission.name == permission,
189
190
  Role.id.in_(db_role_ids),
190
191
  )
191
- .exists()
192
- )
193
- result: bool = await smart_run(
194
- db.current_session.scalar, sqlalchemy.select(exist_query)
192
+ .limit(1)
195
193
  )
194
+ result = await smart_run(db.current_session.scalar, stmt)
195
+ result = bool(result)
196
196
  if result:
197
197
  return
198
198
 
@@ -54,7 +54,7 @@ from .security.sqla.apis import (
54
54
  from .security.sqla.models import Api, Permission, PermissionApi, Role
55
55
  from .security.sqla.security_manager import SecurityManager
56
56
  from .setting import Setting
57
- from .utils import deep_merge, multiple_async_contexts, safe_call, smart_run
57
+ from .utils import deep_merge, lazy, multiple_async_contexts, safe_call, smart_run
58
58
  from .version import __version__
59
59
 
60
60
  __all__ = ["FastAPIReactToolkit"]
@@ -161,7 +161,11 @@ class FastAPIReactToolkit:
161
161
  # Public attributes
162
162
  apis: list[ModelRestApi] = None
163
163
  initialized = False
164
- security: SecurityManager = None
164
+ sm: SecurityManager = None
165
+ security: SecurityManager = lazy(lambda self: self.sm)
166
+ """
167
+ Old attribute for `sm`, kept for backward compatibility.
168
+ """
165
169
  started = False
166
170
  """
167
171
  Indicates whether the application has been started.
@@ -217,7 +221,7 @@ class FastAPIReactToolkit:
217
221
  """
218
222
  g.current_app = self
219
223
  self.apis = []
220
- self.security = SecurityManager(self)
224
+ self.sm = SecurityManager(self)
221
225
 
222
226
  # Database configuration
223
227
  self.create_tables = create_tables
@@ -430,30 +434,30 @@ class FastAPIReactToolkit:
430
434
  session, roles, permission_apis
431
435
  )
432
436
  if self.cleanup:
433
- await self.security.cleanup()
437
+ await self.sm.cleanup()
434
438
  logger.info("DATABASE INITIALIZED")
435
439
 
436
440
  async def _insert_permissions(self, session: SQLASession):
437
441
  permissions = self.total_permissions() + [
438
- x[1] for x in self.security.get_api_permission_tuples_from_builtin_roles()
442
+ x[1] for x in self.sm.get_api_permission_tuples_from_builtin_roles()
439
443
  ]
440
444
  permissions = list(dict.fromkeys(permissions))
441
- return await self.security.create_permissions(permissions, session=session)
445
+ return await self.sm.create_permissions(permissions, session=session)
442
446
 
443
447
  async def _insert_apis(self, session: SQLASession):
444
448
  apis = [api.__class__.__name__ for api in self.apis] + [
445
- x[0] for x in self.security.get_api_permission_tuples_from_builtin_roles()
449
+ x[0] for x in self.sm.get_api_permission_tuples_from_builtin_roles()
446
450
  ]
447
451
  apis = list(dict.fromkeys(apis))
448
- return await self.security.create_apis(apis, session=session)
452
+ return await self.sm.create_apis(apis, session=session)
449
453
 
450
454
  async def _insert_roles(self, session: SQLASession):
451
- roles = self.security.get_roles_from_builtin_roles()
455
+ roles = self.sm.get_roles_from_builtin_roles()
452
456
  if g.admin_role and g.admin_role not in roles:
453
457
  roles.append(g.admin_role)
454
458
  if g.public_role and g.public_role not in roles:
455
459
  roles.append(g.public_role)
456
- return await self.security.create_roles(roles, session=session)
460
+ return await self.sm.create_roles(roles, session=session)
457
461
 
458
462
  async def _associate_permission_with_api(
459
463
  self,
@@ -482,7 +486,7 @@ class FastAPIReactToolkit:
482
486
  for (
483
487
  api_name,
484
488
  perm_name,
485
- ) in self.security.get_api_permission_tuples_from_builtin_roles():
489
+ ) in self.sm.get_api_permission_tuples_from_builtin_roles():
486
490
  if (perm_name, api_name) in added_permission_api:
487
491
  continue
488
492
  permission = permission_map[perm_name]
@@ -490,7 +494,7 @@ class FastAPIReactToolkit:
490
494
  permission_api_tuples.append((permission, api_obj))
491
495
  added_permission_api.add((permission.name, api_obj.name))
492
496
 
493
- return await self.security.associate_list_of_permission_with_api(
497
+ return await self.sm.associate_list_of_permission_with_api(
494
498
  permission_api_tuples, session=session
495
499
  )
496
500
 
@@ -510,7 +514,7 @@ class FastAPIReactToolkit:
510
514
  for (
511
515
  role_name,
512
516
  role_api_permissions,
513
- ) in self.security.get_role_and_api_permission_tuples_from_builtin_roles():
517
+ ) in self.sm.get_role_and_api_permission_tuples_from_builtin_roles():
514
518
  for api_name, permission_name in role_api_permissions:
515
519
  role = role_map[role_name]
516
520
  permission_api = permission_api_map[(permission_name, api_name)]
@@ -528,7 +532,7 @@ class FastAPIReactToolkit:
528
532
  ]:
529
533
  role_permission_api_tuples.append((admin_role, permission_api))
530
534
 
531
- await self.security.associate_list_of_role_with_permission_api(
535
+ await self.sm.associate_list_of_role_with_permission_api(
532
536
  role_permission_api_tuples, session=session
533
537
  )
534
538
 
@@ -164,7 +164,7 @@ class UsersApi(ModelRestApi):
164
164
  col.required = False
165
165
 
166
166
  async def post_add(self, item, params):
167
- await g.current_app.security.update_user(
167
+ await g.current_app.sm.update_user(
168
168
  user_update={"password": item.password},
169
169
  user=item,
170
170
  session=params.session,
@@ -173,7 +173,7 @@ class UsersApi(ModelRestApi):
173
173
 
174
174
  async def post_update(self, item, params):
175
175
  if params.body.password:
176
- await g.current_app.security.update_user(
176
+ await g.current_app.sm.update_user(
177
177
  user_update={"password": params.body.password},
178
178
  user=item,
179
179
  session=params.session,
@@ -76,12 +76,16 @@ class PermissionApi(Model):
76
76
  api_id: Mapped[int] = mapped_column(
77
77
  Integer, ForeignKey(f"{API_TABLE}.id"), name=view_menu_id, nullable=False
78
78
  )
79
- api: Mapped["Api"] = relationship("Api", back_populates="permissions")
79
+ api: Mapped["Api"] = relationship(
80
+ "Api", back_populates="permissions", lazy="joined"
81
+ )
80
82
 
81
83
  permission_id: Mapped[int] = mapped_column(
82
84
  Integer, ForeignKey(f"{PERMISSION_TABLE}.id"), nullable=False
83
85
  )
84
- permission: Mapped["Permission"] = relationship("Permission", back_populates="apis")
86
+ permission: Mapped["Permission"] = relationship(
87
+ "Permission", back_populates="apis", lazy="joined"
88
+ )
85
89
 
86
90
  roles: Mapped[list["Role"]] = relationship(
87
91
  "Role", secondary=assoc_permission_api_role, back_populates="permissions"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi-rtk
3
- Version: 1.0.9
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
1
  fastapi_rtk/__init__.py,sha256=Lg6Er5blOMcbtQSRJMNWbRQ1VX4PWEPMVFm2ie5r8mA,6183
2
- fastapi_rtk/_version.py,sha256=q2ACMkQx0Hm5xKo2YKJFBE7rTruciTSIN6AvWWL9nB8,22
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=nAPIibCCyaGm7Kw9updiVx5LWASkdfX01GxG5Gp12hM,24505
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=4Gv7QA0GQHDXa6EBwr0Ab9Des_wiyCo6OxAFQJ1kAK8,7749
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=K1AX3H4n5shrMDpqATJUXme31YZC87pDkybk0BxxSe8,29739
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
@@ -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=oP1sfQxhgrpNoRmlB-lvbt1dAoGlNXeBEQQXQihAF_k,8916
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
@@ -102,8 +102,8 @@ 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=QgDxswNm_eLbEsrLT-kwv_PauxJCzD1v2ogeg3_f5uA,10711
106
- fastapi_rtk/security/sqla/models.py,sha256=kiTIyGPad-f_0dbaHtLHdtjvfuxkOPWznB0DlI18KFc,7807
105
+ fastapi_rtk/security/sqla/apis.py,sha256=8Qtd1G73i2TaA9Euo63naaB8d_I9r4EHL8DWtWNJEfs,10699
106
+ fastapi_rtk/security/sqla/models.py,sha256=rEXpbljTMlTkiDp0VIxRXant8xN-WTjpqgQkr-ElXeM,7865
107
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
@@ -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.9.dist-info/METADATA,sha256=LuPD3lBTSb2Pk95HYNKh8X4pmOGCUKElzWzluYSJADE,1270
130
- fastapi_rtk-1.0.9.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
131
- fastapi_rtk-1.0.9.dist-info/entry_points.txt,sha256=UuTkxSVIokSlVN28TMhoxzRRUaPxlVRSH3Gsx6yip60,53
132
- fastapi_rtk-1.0.9.dist-info/licenses/LICENSE,sha256=NDrWi4Qwcxal3u1r2lBWGA6TVh3OeW7yMan098mQz98,1073
133
- fastapi_rtk-1.0.9.dist-info/RECORD,,
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,,