import uuid from django.core.validators import (MaxValueValidator, MinLengthValidator, MinValueValidator) from django.db import models from django.db.models.signals import post_delete, pre_delete from django.dispatch import receiver from telegram.bot import Bot # Create your models here. class Timestampable(models.Model): created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) uuid = models.UUIDField(default=uuid.uuid4, editable=False, primary_key=False) class Meta: abstract = True def __str__(self): return repr(self) def __repr__(self): return f'{type(self).__name__}(**{repr(self.__dict__)})' def on_pre_delete(self, sender, instance, **kwargs): pass def on_post_delete(self, sender, instance, **kwargs): pass @receiver(models.signals.post_delete) def timestampable_on_post_delete(sender, instance, **kwargs): if issubclass(sender, Timestampable): instance.on_post_delete(sender, instance, **kwargs) @receiver(models.signals.pre_delete) def timestampable_on_pre_delete(sender, instance, **kwargs): if issubclass(sender, Timestampable): instance.on_pre_delete(sender, instance, **kwargs) class TelegramGroup(Timestampable): AUTO_COLLECT = True telegram_id = models.BigIntegerField() telegram_title = models.CharField(max_length=255) owner = models.ForeignKey(to='TelegramUser', on_delete=models.SET_NULL, blank=False, null=True, related_name='owns') # preferences <- GroupPreferences:group # users_with_pending_captcha <- PendingCaptchaUser:group # admins <- TelegramUser:admins class Meta: ordering = ['telegram_title', 'telegram_id'] class TelegramUser(Timestampable): AUTO_COLLECT = True telegram_id = models.BigIntegerField(blank=False, null=False) telegram_first_name = models.CharField(max_length=255, blank=False, null=False) telegram_last_name = models.CharField(max_length=255, blank=True, null=True) telegram_username = models.CharField(max_length=255, blank=True, null=True) admins = models.ManyToManyField(to=TelegramGroup, related_name='admins') # login_hashes <- LoginHash:telegram_user # pending_captchas <- PendingCaptchaUser:user # bots <- TelegramUserBots:owner class Meta: ordering = ['telegram_first_name', 'telegram_id'] @property def name(self): return f'{self.telegram_first_name} {self.telegram_last_name or ""}'.strip() class TelegramUserBots(Timestampable): owner = models.ForeignKey(to=TelegramUser, on_delete=models.CASCADE, blank=False, null=False, related_name='bots') name = models.CharField(max_length=255, blank=False, null=False) token = models.CharField(max_length=255, blank=False, null=False) telegram_username = models.CharField(max_length=255, blank=False, null=False) telegram_id = models.BigIntegerField() def on_pre_delete(self, sender, instance, **kwargs): if instance.token is not None and instance.token != '': Bot(instance.token).set_webhook(url='') @property def as_user(self): return TelegramUser.objects.get(telegram_id=self.telegram_id) class Meta: ordering = ['name', 'telegram_username', 'telegram_id'] class LoginHash(Timestampable): AUTO_COLLECT = True telegram_user = models.ForeignKey(to=TelegramUser, on_delete=models.CASCADE, blank=False, null=False, related_name='login_hashes') class Meta: ordering = ['telegram_user'] class GroupPreferences(Timestampable): group = models.OneToOneField(to=TelegramGroup, on_delete=models.CASCADE, blank=False, null=False, related_name='preferences') # Anti-Spam combot_anti_spam_use = models.BooleanField(default=False, blank=True, null=False) combot_anti_spam_notification = models.TextField(default='', blank=True, null=False) # Greetings join_message = models.TextField(max_length=4000, default='', blank=True, null=False) leave_message = models.TextField(max_length=4000, default='', blank=True, null=False) # Captcha captcha_use = models.BooleanField(default=False, blank=True, null=False) captcha_chars = models.CharField(max_length=255, default='0123456789', blank=False, null=False, validators=[MinLengthValidator(2)]) captcha_digits = models.IntegerField(default=7, blank=True, null=False, validators=[MinValueValidator(1), MaxValueValidator(24)]) captcha_timeout = models.IntegerField(default=240, blank=True, null=False, validators=[MinValueValidator(15), MaxValueValidator(600)]) captcha_attempts = models.IntegerField(default=5, blank=True, null=False, validators=[MinValueValidator(2), MaxValueValidator(20)]) captcha_first_message = models.TextField(max_length=1000, default='', blank=True, null=False) captcha_retry_message = models.TextField(max_length=1000, default='', blank=True, null=False) captcha_leave_mess = models.BooleanField(default=False, blank=True, null=False) # Canned Messages # canned_messages <- GroupCannedMessage:group_preferences class Meta: ordering = ['group'] class GroupCannedMessage(Timestampable): group_preferences = models.ForeignKey(to=GroupPreferences, on_delete=models.CASCADE, blank=False, null=False, related_name='canned_messages') listen = models.CharField(max_length=255) reply_with = models.TextField(max_length=4000) class Meta: ordering = ['group_preferences', 'listen', 'reply_with'] class PendingCaptchaUser(Timestampable): AUTO_COLLECT = True bot_token = models.CharField(max_length=255, blank=False, null=False) captcha_answer = models.CharField(max_length=255, blank=False, null=False) group = models.ForeignKey(to=TelegramGroup, on_delete=models.CASCADE, related_name='users_with_pending_captcha') user = models.ForeignKey(to=TelegramUser, on_delete=models.CASCADE, related_name='pending_captchas') lifetime = models.IntegerField(blank=True, null=False) attempts_left = models.IntegerField(blank=True, null=False) captcha_message_id = models.IntegerField(blank=True, null=False) class Meta: ordering = ['-lifetime', 'attempts_left', 'user', 'group', 'captcha_answer']