Skip to content

Commit ba08e30

Browse files
x0sinaImMohammad20000
authored andcommitted
perf: reduce backend request latency
1 parent 9d6ea3a commit ba08e30

File tree

5 files changed

+68
-24
lines changed

5 files changed

+68
-24
lines changed

app/db/crud/admin.py

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717
from app.models.stats import Period, UserUsageStat, UserUsageStatsList
1818

1919

20-
async def load_admin_attrs(admin: Admin):
20+
async def load_admin_attrs(admin: Admin, load_users: bool = True, load_usage_logs: bool = True):
2121
try:
22-
await admin.awaitable_attrs.users
23-
await admin.awaitable_attrs.usage_logs
22+
if load_users:
23+
await admin.awaitable_attrs.users
24+
if load_usage_logs:
25+
await admin.awaitable_attrs.usage_logs
2426
except AttributeError:
2527
pass
2628

@@ -49,7 +51,13 @@ async def load_admin_attrs(admin: Admin):
4951
)
5052

5153

52-
async def get_admin(db: AsyncSession, username: str) -> Admin:
54+
async def get_admin(
55+
db: AsyncSession,
56+
username: str,
57+
*,
58+
load_users: bool = True,
59+
load_usage_logs: bool = True,
60+
) -> Admin:
5361
"""
5462
Retrieves an admin by username.
5563
@@ -62,7 +70,7 @@ async def get_admin(db: AsyncSession, username: str) -> Admin:
6270
"""
6371
admin = (await db.execute(select(Admin).where(Admin.username == username))).unique().scalar_one_or_none()
6472
if admin:
65-
await load_admin_attrs(admin)
73+
await load_admin_attrs(admin, load_users=load_users, load_usage_logs=load_usage_logs)
6674
return admin
6775

6876

@@ -138,7 +146,13 @@ async def remove_admin(db: AsyncSession, dbadmin: Admin) -> None:
138146
await db.commit()
139147

140148

141-
async def get_admin_by_id(db: AsyncSession, id: int) -> Admin:
149+
async def get_admin_by_id(
150+
db: AsyncSession,
151+
id: int,
152+
*,
153+
load_users: bool = True,
154+
load_usage_logs: bool = True,
155+
) -> Admin:
142156
"""
143157
Retrieves an admin by their ID.
144158
@@ -151,11 +165,17 @@ async def get_admin_by_id(db: AsyncSession, id: int) -> Admin:
151165
"""
152166
admin = (await db.execute(select(Admin).where(Admin.id == id))).first()
153167
if admin:
154-
await load_admin_attrs(admin)
168+
await load_admin_attrs(admin, load_users=load_users, load_usage_logs=load_usage_logs)
155169
return admin
156170

157171

158-
async def get_admin_by_telegram_id(db: AsyncSession, telegram_id: int) -> Admin:
172+
async def get_admin_by_telegram_id(
173+
db: AsyncSession,
174+
telegram_id: int,
175+
*,
176+
load_users: bool = True,
177+
load_usage_logs: bool = True,
178+
) -> Admin:
159179
"""
160180
Retrieves an admin by their Telegram ID.
161181
@@ -168,11 +188,17 @@ async def get_admin_by_telegram_id(db: AsyncSession, telegram_id: int) -> Admin:
168188
"""
169189
admin = (await db.execute(select(Admin).where(Admin.telegram_id == telegram_id))).scalar_one_or_none()
170190
if admin:
171-
await load_admin_attrs(admin)
191+
await load_admin_attrs(admin, load_users=load_users, load_usage_logs=load_usage_logs)
172192
return admin
173193

174194

175-
async def get_admin_by_discord_id(db: AsyncSession, discord_id: int) -> Admin:
195+
async def get_admin_by_discord_id(
196+
db: AsyncSession,
197+
discord_id: int,
198+
*,
199+
load_users: bool = True,
200+
load_usage_logs: bool = True,
201+
) -> Admin:
176202
"""
177203
Retrieves an admin by their Discord ID.
178204
@@ -185,7 +211,7 @@ async def get_admin_by_discord_id(db: AsyncSession, discord_id: int) -> Admin:
185211
"""
186212
admin = (await db.execute(select(Admin).where(Admin.discord_id == discord_id))).first()
187213
if admin:
188-
await load_admin_attrs(admin)
214+
await load_admin_attrs(admin, load_users=load_users, load_usage_logs=load_usage_logs)
189215
return admin
190216

191217

app/db/crud/user.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from sqlalchemy import and_, case, delete, desc, func, literal, literal_column, not_, or_, select, update
77
from sqlalchemy.ext.asyncio import AsyncSession
8-
from sqlalchemy.orm import joinedload
8+
from sqlalchemy.orm import joinedload, selectinload
99
from sqlalchemy.sql.functions import coalesce
1010

1111
from app.db.compiles_types import DateDiff
@@ -179,7 +179,12 @@ async def get_users(
179179
Returns:
180180
List of users or tuple with (users, count) if return_with_count is True.
181181
"""
182-
stmt = select(User)
182+
stmt = select(User).options(
183+
selectinload(User.admin),
184+
selectinload(User.next_plan),
185+
selectinload(User.usage_logs),
186+
selectinload(User.groups),
187+
)
183188

184189
filters = []
185190
if usernames:
@@ -227,9 +232,6 @@ async def get_users(
227232
result = await db.execute(stmt)
228233
users = list(result.unique().scalars().all())
229234

230-
for user in users:
231-
await load_user_attrs(user)
232-
233235
if return_with_count:
234236
return users, total
235237
return users

app/operation/system.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ async def get_system_stats(db: AsyncSession, admin: AdminDetails, admin_username
2525

2626
admin_param = None
2727
if admin.is_sudo and admin_username:
28-
admin_param = await get_admin(db, admin_username)
28+
admin_param = await get_admin(db, admin_username, load_users=False, load_usage_logs=False)
2929
elif not admin.is_sudo:
3030
admin_param = admin
3131

app/operation/user.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ async def create_user(self, db: AsyncSession, new_user: UserCreate, admin: Admin
215215
await self.get_validated_user_template(db, new_user.next_plan.user_template_id)
216216

217217
all_groups = await self.validate_all_groups(db, new_user)
218-
db_admin = await get_admin(db, admin.username)
218+
db_admin = await get_admin(db, admin.username, load_users=False, load_usage_logs=False)
219219

220220
try:
221221
db_user = await create_user(db, new_user, all_groups, db_admin)
@@ -451,7 +451,9 @@ async def get_users_simple(
451451
await self.raise_error(message=f'"{opt}" is not a valid sort option', code=400)
452452

453453
# Authorization: non-sudo admins see only their users
454-
admin_filter = None if admin.is_sudo else await get_admin(db, admin.username)
454+
admin_filter = (
455+
None if admin.is_sudo else await get_admin(db, admin.username, load_users=False, load_usage_logs=False)
456+
)
455457

456458
# Call CRUD function
457459
rows, total = await get_users_simple(
@@ -694,7 +696,7 @@ def builder(username: str):
694696
if users_to_create:
695697
groups = await self.validate_all_groups(db, users_to_create[0])
696698

697-
db_admin = await get_admin(db, admin.username)
699+
db_admin = await get_admin(db, admin.username, load_users=False, load_usage_logs=False)
698700
subscription_urls = await self._persist_bulk_users(db, admin, db_admin, users_to_create, groups)
699701

700702
return BulkUsersCreateResponse(subscription_urls=subscription_urls, created=len(subscription_urls))

app/routers/authentication.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,29 @@ async def get_admin(db: AsyncSession, token: str) -> AdminDetails | None:
2020
if not payload:
2121
return
2222

23-
db_admin = await get_admin_by_username(db, payload["username"])
23+
db_admin = await get_admin_by_username(db, payload["username"], load_users=False, load_usage_logs=False)
2424
if db_admin:
2525
if db_admin.password_reset_at:
2626
if not payload.get("created_at"):
2727
return
2828
if db_admin.password_reset_at.astimezone(tz.utc) > payload.get("created_at"):
2929
return
3030

31-
return AdminDetails.model_validate(db_admin)
31+
return AdminDetails(
32+
id=db_admin.id,
33+
username=db_admin.username,
34+
is_sudo=db_admin.is_sudo,
35+
used_traffic=db_admin.used_traffic,
36+
is_disabled=db_admin.is_disabled,
37+
telegram_id=db_admin.telegram_id,
38+
discord_webhook=db_admin.discord_webhook,
39+
sub_domain=db_admin.sub_domain,
40+
profile_title=db_admin.profile_title,
41+
support_url=db_admin.support_url,
42+
notification_enable=db_admin.notification_enable,
43+
discord_id=db_admin.discord_id,
44+
sub_template=db_admin.sub_template,
45+
)
3246

3347
elif payload["username"] in SUDOERS and payload["is_sudo"] is True:
3448
return AdminDetails(username=payload["username"], is_sudo=True)
@@ -61,7 +75,7 @@ async def check_sudo_admin(admin: AdminDetails = Depends(get_current)):
6175
async def validate_admin(db: AsyncSession, username: str, password: str) -> AdminValidationResult | None:
6276
"""Validate admin credentials with environment variables or database."""
6377

64-
db_admin = await get_admin_by_username(db, username)
78+
db_admin = await get_admin_by_username(db, username, load_users=False, load_usage_logs=False)
6579
if db_admin and await verify_password(password, db_admin.hashed_password):
6680
return AdminValidationResult(
6781
username=db_admin.username, is_sudo=db_admin.is_sudo, is_disabled=db_admin.is_disabled
@@ -93,7 +107,7 @@ async def validate_mini_app_admin(db: AsyncSession, token: str) -> AdminValidati
93107
headers={"WWW-Authenticate": "Bearer"},
94108
)
95109

96-
db_admin = await get_admin_by_telegram_id(db, data.user.id)
110+
db_admin = await get_admin_by_telegram_id(db, data.user.id, load_users=False, load_usage_logs=False)
97111
if db_admin:
98112
return AdminValidationResult(
99113
username=db_admin.username, is_sudo=db_admin.is_sudo, is_disabled=db_admin.is_disabled

0 commit comments

Comments
 (0)