You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

259 lines
9.7 KiB

from json import dumps
from rest_framework.authtoken.models import Token
from phonenumber_field.modelfields import PhoneNumberField
from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth.models import AbstractUser, UserManager as BaseUserManager
from django.contrib.postgres import fields as pgfields
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _
from api.v1 import serializers
from apps.notification.utils import send_email
from apps.user.tasks import user_to_mixpanel
class UserManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, username, email, password, **extra_fields):
if not username:
username = email
if not password:
password = self.make_random_password()
email = self.normalize_email(email)
username = self.model.normalize_username(username)
user = self.model(username=username, email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
class User(AbstractUser):
USER_ROLE = 0
AUTHOR_ROLE = 1
TEACHER_ROLE = 2
ADMIN_ROLE = 3
ROLE_CHOICES = (
(USER_ROLE, 'пользователь'),
(AUTHOR_ROLE, 'автор'),
(TEACHER_ROLE, 'преподаватель'),
(ADMIN_ROLE, 'администратор'),
)
NOT_DEFINED = 'n'
MALE = 'm'
FEMALE = 'f'
GENDER_CHOICES = (
(NOT_DEFINED, 'не указан'),
(MALE, 'Мужчина'),
(FEMALE, 'Женщина'),
)
email = models.EmailField(_('email address'), unique=True)
phone = PhoneNumberField(null=True, blank=True, unique=True)
role = models.PositiveSmallIntegerField(
'Роль', default=0, choices=ROLE_CHOICES)
gender = models.CharField(
'Пол', max_length=1, default='n', choices=GENDER_CHOICES)
birthday = models.DateField('День рождения', null=True, blank=True)
country = models.CharField('Страна', max_length=50, null=True, blank=True)
city = models.CharField('Город', max_length=85, null=True, blank=True)
about = models.CharField('О себе', max_length=1000, null=True, blank=True)
instagram = models.URLField(default='', null=True, blank=True)
instagram_hashtag = models.CharField('Инстаграм хештег', max_length=100, null=True, blank=True)
facebook = models.URLField(default='', null=True, blank=True)
twitter = models.URLField(default='', null=True, blank=True)
pinterest = models.URLField(default='', null=True, blank=True)
youtube = models.URLField(default='', null=True, blank=True)
vkontakte = models.URLField('ВКонтакте', default='', null=True, blank=True)
fb_id = models.BigIntegerField(null=True, blank=True, unique=True)
fb_data = pgfields.JSONField(default={}, null=True, blank=True)
is_email_proved = models.BooleanField(
'Верифицирован по email', default=False
)
photo = models.ImageField('Фото', null=True, blank=True, upload_to='users')
show_in_mainpage = models.BooleanField('Показывать на главной странице', default=False)
trial_lesson = models.URLField(default='', null=True, blank=True)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
class Meta(AbstractUser.Meta):
ordering = ('-date_joined',)
def serialized(self):
user_data = serializers.user.UserSerializer(instance=self).data
user_data = dumps(user_data, ensure_ascii=False)
return user_data
@property
def balance(self):
aggregate = self.balances.filter(
type=0,
payment__isnull=False,
payment__status__isnull=False
).aggregate(
models.Sum('amount'),
models.Sum('commission'),
)
amount = aggregate.get('amount__sum') or 0
commission = aggregate.get('commission__sum') or 0
return amount - commission
@receiver(post_save, sender=User)
def create_auth_token(sender, instance=None, created=False, **kwargs):
if (
(instance.is_active or instance.fb_id) and
instance.role in [User.AUTHOR_ROLE, User.TEACHER_ROLE, User.ADMIN_ROLE] and not
hasattr(instance, 'auth_token')
):
Token.objects.create(user=instance)
elif (
not (instance.is_active or instance.fb_id) or
instance.role not in [User.AUTHOR_ROLE, User.TEACHER_ROLE, User.ADMIN_ROLE]
) and hasattr(instance, 'auth_token'):
instance.auth_token.delete()
@receiver(post_save, sender=User)
def send_user_info_to_mixpanel(sender, instance=None, created=False, **kwargs):
user_to_mixpanel.delay(
instance.id,
instance.email,
str(instance.phone),
instance.first_name,
instance.last_name,
instance.date_joined,
dict(User.ROLE_CHOICES).get(instance.role),
[subscription.title.lower() for subscription in instance.email_subscription.categories.all()] if hasattr(instance, 'email_subscription') else [],
)
@receiver(post_save, sender=User)
def auto_create_subscription(sender, instance=None, created=False, **kwargs):
if created:
es, created = EmailSubscription.objects.get_or_create(email=instance.email)
es.user = instance
es.save()
instance.email_subscription.categories.set(SubscriptionCategory.objects.filter(auto_add=True))
class AuthorRequestManager(models.Manager):
def create_by_user(self, user):
obj = self.model(
first_name=user.first_name,
last_name=user.last_name,
email=user.email,
about=user.about,
facebook=user.facebook,
)
self._for_write = True
obj.save(force_insert=True, using=self.db)
return obj
class AuthorRequest(models.Model):
PENDING = 0
ACCEPTED = 1
DECLINED = 2
STATUS_CHOICES = (
(PENDING, 'pending'),
(ACCEPTED, 'accepted'),
(DECLINED, 'declined'),
)
first_name = models.CharField(_('first name'), max_length=30)
last_name = models.CharField(_('last name'), max_length=150)
email = models.EmailField(_('email address'), unique=True)
about = models.CharField('О себе', max_length=1000, null=True, blank=True)
facebook = models.URLField(default='', null=True, blank=True)
status = models.PositiveSmallIntegerField(choices=STATUS_CHOICES, default=PENDING)
cause = models.TextField('Причина отказа', null=True, blank=True)
accepted_send_at = models.DateTimeField(null=True, blank=True)
declined_send_at = models.DateTimeField(null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
update_at = models.DateTimeField(auto_now=True)
objects = AuthorRequestManager()
class Meta:
verbose_name = 'Заявка не преподавателя'
verbose_name_plural = 'Заявки не преподавателя'
ordering = ('-created_at',)
@receiver(post_save, sender=AuthorRequest)
def handle_authorrequest_update(sender, instance=None, created=False, update_fields=[], **kwargs):
if not created:
if instance.status == AuthorRequest.DECLINED and not instance.declined_send_at:
send_email.delay(
'Отказ заявки на преподавателя',
instance.email,
'notification/email/decline_author.html',
cause=instance.cause,
)
instance.declined_send_at = now()
instance.save()
elif instance.status == AuthorRequest.ACCEPTED and not instance.accepted_send_at:
email = None
password = None
try:
user = User.objects.get(email=instance.email)
except User.DoesNotExist:
email = instance.email
password = User.objects.make_random_password()
user = User.objects.create(
first_name=instance.first_name,
last_name=instance.last_name,
username=instance.email,
email=instance.email,
about=instance.about,
facebook=instance.facebook,
is_active=True,
is_email_proved=True,
)
user.set_password(password)
user.role = User.AUTHOR_ROLE
user.save()
send_email.delay(
'Заявка на преподавателя одобрена',
instance.email,
'notification/email/accept_author.html',
email=email,
password=password,
)
instance.accepted_send_at = now()
instance.save()
class SubscriptionCategory(models.Model):
title = models.CharField(max_length=100)
auto_add = models.BooleanField(default=False)
class Meta:
verbose_name = 'Категория подписки'
verbose_name_plural = 'Категории подписки'
ordering = ('title',)
def __str__(self):
return self.title
class EmailSubscription(models.Model):
ERROR = 0
SENT = 1
MAILCHIMP_STATUS_CHOICES = (
(ERROR, 'error'),
(SENT, 'sent'),
)
user = models.OneToOneField(User, null=True, blank=True, on_delete=models.CASCADE, related_name='email_subscription')
email = models.EmailField(_('email address'), unique=True)
categories = models.ManyToManyField(SubscriptionCategory)
mailchimp_status = models.PositiveSmallIntegerField(choices=MAILCHIMP_STATUS_CHOICES, default=ERROR)