From 14590aaddcaece8d45a71a0dddcdbb7bd457eace Mon Sep 17 00:00:00 2001 From: Ultradesu Date: Fri, 15 Aug 2025 05:15:13 +0300 Subject: [PATCH] Added TG bot --- telegram_bot/admin.py | 68 ++++++++++++++++++- ...08_accessrequest_selected_existing_user.py | 28 ++++++++ telegram_bot/models.py | 8 +++ 3 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 telegram_bot/migrations/0008_accessrequest_selected_existing_user.py diff --git a/telegram_bot/admin.py b/telegram_bot/admin.py index 34b9838..eb998cc 100644 --- a/telegram_bot/admin.py +++ b/telegram_bot/admin.py @@ -4,6 +4,7 @@ from django.urls import path, reverse from django.shortcuts import redirect from django.contrib import messages from django.utils import timezone +from django import forms from .models import BotSettings, TelegramMessage, AccessRequest from .localization import MessageLocalizer import logging @@ -11,6 +12,27 @@ import logging logger = logging.getLogger(__name__) +class AccessRequestAdminForm(forms.ModelForm): + """Custom form for AccessRequest with existing user selection""" + + class Meta: + model = AccessRequest + fields = '__all__' + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # Rename the field for better UI + if 'selected_existing_user' in self.fields: + self.fields['selected_existing_user'].label = 'Link to existing user' + self.fields['selected_existing_user'].empty_label = "— Create new user —" + self.fields['selected_existing_user'].help_text = "Select an existing user without Telegram to link, or leave empty to create new user" + # Get users without telegram_user_id + from vpn.models import User + self.fields['selected_existing_user'].queryset = User.objects.filter( + telegram_user_id__isnull=True + ).order_by('username') + + @admin.register(BotSettings) class BotSettingsAdmin(admin.ModelAdmin): list_display = ('__str__', 'enabled', 'bot_token_display', 'updated_at') @@ -259,6 +281,7 @@ class TelegramMessageAdmin(admin.ModelAdmin): @admin.register(AccessRequest) class AccessRequestAdmin(admin.ModelAdmin): + form = AccessRequestAdminForm list_display = ( 'created_at', 'user_display', @@ -309,9 +332,10 @@ class AccessRequestAdmin(admin.ModelAdmin): }), ('User Creation', { 'fields': ( + 'selected_existing_user', 'desired_username', ), - 'description': 'Edit username before approving the request' + 'description': 'Choose existing user to link OR specify username for new user' }), ('Telegram User', { 'fields': ( @@ -416,6 +440,35 @@ class AccessRequestAdmin(admin.ModelAdmin): approve_requests.short_description = "✅ Approve selected requests" + def save_model(self, request, obj, form, change): + """Override save to handle existing user linking""" + super().save_model(request, obj, form, change) + + # If approved and existing user was selected, link them + if obj.approved and obj.selected_existing_user and not obj.created_user: + try: + # Link telegram data to selected user + obj.selected_existing_user.telegram_user_id = obj.telegram_user_id + obj.selected_existing_user.telegram_username = obj.telegram_username + obj.selected_existing_user.telegram_first_name = obj.telegram_first_name or "" + obj.selected_existing_user.telegram_last_name = obj.telegram_last_name or "" + obj.selected_existing_user.save() + + # Update the request to reference the linked user + obj.created_user = obj.selected_existing_user + obj.processed_by = request.user + obj.processed_at = timezone.now() + obj.save() + + # Send notification + self._send_approval_notification(obj) + + messages.success(request, f"Successfully linked Telegram user to existing user {obj.selected_existing_user.username}") + logger.info(f"Linked Telegram user {obj.telegram_user_id} to existing user {obj.selected_existing_user.username}") + + except Exception as e: + messages.error(request, f"Failed to link existing user: {e}") + logger.error(f"Failed to link existing user: {e}") def _create_user_from_request(self, access_request, admin_user): """Create User from AccessRequest or link to existing user""" @@ -430,6 +483,19 @@ class AccessRequestAdmin(admin.ModelAdmin): logger.info(f"User already exists: {existing_user.username}") return existing_user + # Check if admin selected an existing user to link + if access_request.selected_existing_user: + selected_user = access_request.selected_existing_user + logger.info(f"Linking Telegram user {access_request.telegram_user_id} to selected existing user {selected_user.username}") + + # Link telegram data to selected user + selected_user.telegram_user_id = access_request.telegram_user_id + selected_user.telegram_username = access_request.telegram_username + selected_user.telegram_first_name = access_request.telegram_first_name or "" + selected_user.telegram_last_name = access_request.telegram_last_name or "" + selected_user.save() + return selected_user + # Check if we can link to existing user by telegram_username if access_request.telegram_username: existing_user_by_username = User.objects.filter( diff --git a/telegram_bot/migrations/0008_accessrequest_selected_existing_user.py b/telegram_bot/migrations/0008_accessrequest_selected_existing_user.py new file mode 100644 index 0000000..2cfb379 --- /dev/null +++ b/telegram_bot/migrations/0008_accessrequest_selected_existing_user.py @@ -0,0 +1,28 @@ +# Generated migration for adding selected_existing_user field + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('telegram_bot', '0007_remove_botsettings_help_message_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='accessrequest', + name='selected_existing_user', + field=models.ForeignKey( + blank=True, + help_text='Existing user selected to link with this Telegram account', + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='selected_for_requests', + to=settings.AUTH_USER_MODEL + ), + ), + ] \ No newline at end of file diff --git a/telegram_bot/models.py b/telegram_bot/models.py index f00a25d..f6577e4 100644 --- a/telegram_bot/models.py +++ b/telegram_bot/models.py @@ -216,6 +216,14 @@ class AccessRequest(models.Model): ) # Related objects + selected_existing_user = models.ForeignKey( + User, + null=True, + blank=True, + on_delete=models.SET_NULL, + related_name='selected_for_requests', + help_text="Existing user selected to link with this Telegram account" + ) created_user = models.ForeignKey( User, null=True,