class Answer(TreeNode): objects: AnswerQuerySet = AnswerQuerySet.as_manager() created = models.DateTimeField(auto_now_add=True, db_index=True) modified = models.DateTimeField(null=True, blank=True, db_index=True) slug = models.UUIDField(db_index=True, unique=True, default=uuid.uuid4) question = models.ForeignKey('homework.Question', on_delete=models.CASCADE) author = models.ForeignKey('users.User', on_delete=models.CASCADE) text = MarkdownxField() class Meta: verbose_name = _('Homework answer') verbose_name_plural = _('Homework answers') ordering = ['created'] permissions = [ ('see_all_answers', _('May see answers from every user')), ] def save(self, *args, **kwargs): if self.pk: self.modified = timezone.now() return super().save(*args, **kwargs)
class Question(TimestampedModel): slug = models.UUIDField(db_index=True, unique=True, default=uuid.uuid4) courses = models.ManyToManyField('products.Course') name = models.CharField(_('Name'), max_length=256) text = MarkdownxField() class Meta: verbose_name = _('Homework') verbose_name_plural = _('Homeworks') permissions = [ ('see_all_questions', _('May see questions for all homeworks')), ] def get_absolute_url(self): return urljoin(settings.FRONTEND_URL, f'homework/questions/{self.slug}/') def dispatch_crosscheck(self, *args, **kwargs): from homework.services import QuestionCrossCheckDispatcher dispatcher = QuestionCrossCheckDispatcher(question=self, *args, **kwargs) return dispatcher()
class Answer(TreeNode): objects: AnswerQuerySet = AnswerQuerySet.as_manager() created = models.DateTimeField(auto_now_add=True, db_index=True) modified = models.DateTimeField(auto_now=True, db_index=True) slug = models.UUIDField(db_index=True, unique=True, default=uuid.uuid4) question = models.ForeignKey('homework.Question', on_delete=models.CASCADE) author = models.ForeignKey('users.User', on_delete=models.CASCADE) do_not_crosscheck = models.BooleanField(_('Exclude from cross-checking'), default=False) text = MarkdownxField() class Meta: verbose_name = _('Homework answer') verbose_name_plural = _('Homework answers') ordering = ['created'] permissions = [ ('see_all_answers', _('May see answers from every user')), ] def get_root_answer(self): ancesorts = self.ancestors() if ancesorts.count(): return ancesorts[0] return self def get_absolute_url(self): root = self.get_root_answer() url = urljoin(settings.FRONTEND_URL, f'homework/answers/{root.slug}/') if root != self: url = f'{url}#{self.slug}' # append hash with current answer id return url def get_purchased_course(self): latest_purchase = Order.objects.paid().filter( user=self.author, course__in=self.question.courses.all()).order_by('-paid').first() if latest_purchase: return latest_purchase.course def get_first_level_descendants(self): return self.descendants().filter(parent=self.id) def __str__(self): LENGTH = 30 text = self.text[:LENGTH] if len(text) == LENGTH: text += '...' return text
class Question(TimestampedModel): slug = models.UUIDField(db_index=True, unique=True, default=uuid.uuid4) courses = models.ManyToManyField('products.Course') name = models.CharField(_('Name'), max_length=256) text = MarkdownxField() class Meta: verbose_name = _('Homework') verbose_name_plural = _('Homeworks') def get_absolute_url(self): return urljoin(settings.FRONTEND_URL, f'/homework/questions/{self.slug}/')
class PasswordlessAuthToken(TimestampedModel): objects = PasswordlessAuthTokenQuerySet.as_manager() user = models.ForeignKey('users.User', on_delete=models.CASCADE) token = models.UUIDField(default=uuid.uuid4, unique=True, db_index=True) expires = models.DateTimeField(default=default_expiration) used = models.DateTimeField(null=True) def get_absolute_url(self): return urljoin(settings.FRONTEND_URL, '/'.join(['auth', 'passwordless', str(self.token), ''])) def mark_as_used(self): if not settings.DANGEROUSLY_MAKE_ONE_TIME_PASSWORDLESS_TOKEN_MULTI_PASS: self.used = timezone.now() self.save()
class User(AbstractUser): subscribed = models.BooleanField(_('Subscribed to newsletter'), default=False) first_name_en = models.CharField(_('first name in english'), max_length=150, blank=True) last_name_en = models.CharField(_('last name in english'), max_length=150, blank=True) uuid = models.UUIDField(db_index=True, unique=True, default=uuid.uuid4) @classmethod def parse_name(cls, name: str) -> dict: if name is None: return {} parts = name.split(' ', 2) if len(parts) == 1: return {'first_name': parts[0]} if len(parts) == 2: return {'first_name': parts[0], 'last_name': parts[1]} return {'first_name': parts[0], 'last_name': ' '.join(parts[1:])} def __str__(self): name = self.first_name + ' ' + self.last_name if len(name) < 3: return self.username return name.strip() def add_perm(self, perm): """Add permission to the user. This is a shortcut method for testing, please do not use in production """ [app_label, model, codename] = perm.split('.') permission = Permission.objects.get_by_natural_key( codename, app_label, model) if permission is not None: self.user_permissions.add(permission)