diff --git a/app/main.py b/app/main.py index 5959b03..6a0cc3a 100644 --- a/app/main.py +++ b/app/main.py @@ -218,26 +218,33 @@ async def _process_callback_query(cq: dict): if approve_match: days = int(approve_match.group(1)) - password = _generate_password() username = pending.email + expires = _dtc.datetime.now(_dtc.timezone.utc) + _dtc.timedelta(days=days) + parts = pending.name.strip().split(None, 1) - if db.scalar(select(User).where(User.username == username)): - import secrets as _sec - username = pending.email.split("@")[0] + "_" + _sec.token_hex(3) + existing_user = db.scalar(select(User).where(User.username == username)) + is_renewal = existing_user is not None - expires = _dtc.datetime.now(_dtc.timezone.utc) + _dtc.timedelta(days=days) - parts = pending.name.strip().split(None, 1) - new_user = User( - username=username, - password_hash=hash_password(password), - expires_at=expires, - active=True, - is_admin=False, - first_name=parts[0] if parts else "", - last_name=parts[1] if len(parts) > 1 else "", - ) - db.add(new_user) - db.flush() + if is_renewal: + password = None + existing_user.expires_at = expires + existing_user.active = True + target_user = existing_user + db.flush() + else: + password = _generate_password() + new_user = User( + username=username, + password_hash=hash_password(password), + expires_at=expires, + active=True, + is_admin=False, + first_name=parts[0] if parts else "", + last_name=parts[1] if len(parts) > 1 else "", + ) + db.add(new_user) + db.flush() + target_user = new_user if products: from sqlalchemy import func as _func2 @@ -247,8 +254,13 @@ async def _process_callback_query(cq: dict): Service.active == True, ) ).all() + existing_svc_ids = ( + {a.service_id for a in db.scalars(select(UserServiceAccess).where(UserServiceAccess.user_id == target_user.id)).all()} + if is_renewal else set() + ) for svc in matched: - db.add(UserServiceAccess(user_id=new_user.id, service_id=svc.id)) + if svc.id not in existing_svc_ids: + db.add(UserServiceAccess(user_id=target_user.id, service_id=svc.id)) db.commit() @@ -261,6 +273,16 @@ async def _process_callback_query(cq: dict): ) day_word = "день" if days == 1 else ("дня" if days < 5 else "дней") + email_action = "продлён" if is_renewal else "предоставлен" + email_subject = ("Продление доступа к Инфраструктурному полигону MONT" + if is_renewal else + "Доступ к Инфраструктурному полигону MONT") + email_subhead = "Ваш доступ продлён" if is_renewal else "Ваш запрос одобрен" + cred_row = ( + f'Пароль' + f'{password}' + ) if not is_renewal else "" + access_text = f"Вам {email_action} доступ к полигону на {days} {day_word}." html_email = f""" @@ -268,20 +290,19 @@ async def _process_callback_query(cq: dict):
MONT
-

Доступ к Инфраструктурному полигону MONT

-

Ваш запрос одобрен

+

{email_subject}

+

{email_subhead}


Здравствуйте, {pending.name}!
- Вам предоставлен доступ к полигону на {days} {day_word}.

+ {access_text}

- - + {cred_row}
Адрес портала {portal_url}
Логин {username}
Пароль{password}
Доступ до {expires.strftime("%d.%m.%Y")}
@@ -300,7 +321,7 @@ async def _process_callback_query(cq: dict): db.commit() try: - _send_email(pending.email, "Доступ к Инфраструктурному полигону MONT", html_email) + _send_email(pending.email, email_subject, html_email) email_status = "Email отправлен" except Exception as ex: log_event("email_send_error", error=str(ex)) @@ -309,10 +330,10 @@ async def _process_callback_query(cq: dict): _tg_api("editMessageText", { "chat_id": chat_id, "message_id": msg_id, "text": ( - f"✅ Одобрено на {days} {day_word}\n" - f"👤 Логин: `{username}`\n" - f"🔑 Пароль: `{password}`\n" - f"📧 {email_status}" + (f"🔄 Продлено на {days} {day_word}\n" if is_renewal else f"✅ Одобрено на {days} {day_word}\n") + + f"👤 Логин: `{username}`\n" + + (f"🔑 Пароль: `{password}`\n" if not is_renewal else "") + + f"📧 {email_status}" ), "parse_mode": "Markdown", }) @@ -783,23 +804,31 @@ async def telegram_webhook(request: Request, db: Session = Depends(get_db)): password = _generate_password() username = pending.email - # ensure username unique - if db.scalar(select(User).where(User.username == username)): - username = pending.email.split("@")[0] + "_" + _secrets.token_hex(3) - expires = _dt2.datetime.now(_dt2.timezone.utc) + _dt2.timedelta(days=days) parts = pending.name.strip().split(None, 1) - new_user = User( - username=username, - password_hash=hash_password(password), - expires_at=expires, - active=True, - is_admin=False, - first_name=parts[0] if parts else "", - last_name=parts[1] if len(parts) > 1 else "", - ) - db.add(new_user) - db.flush() + + existing_user = db.scalar(select(User).where(User.username == username)) + is_renewal = existing_user is not None + + if is_renewal: + password = None + existing_user.expires_at = expires + existing_user.active = True + target_user = existing_user + db.flush() + else: + new_user = User( + username=username, + password_hash=hash_password(password), + expires_at=expires, + active=True, + is_admin=False, + first_name=parts[0] if parts else "", + last_name=parts[1] if len(parts) > 1 else "", + ) + db.add(new_user) + db.flush() + target_user = new_user # assign requested services if products: @@ -810,8 +839,13 @@ async def telegram_webhook(request: Request, db: Session = Depends(get_db)): Service.active == True, ) ).all() + existing_svc_ids = ( + {a.service_id for a in db.scalars(select(UserServiceAccess).where(UserServiceAccess.user_id == target_user.id)).all()} + if is_renewal else set() + ) for svc in matched: - db.add(UserServiceAccess(user_id=new_user.id, service_id=svc.id)) + if svc.id not in existing_svc_ids: + db.add(UserServiceAccess(user_id=target_user.id, service_id=svc.id)) db.commit()