import arrow from io import BytesIO from PIL import Image from os.path import splitext from datetime import timedelta from paymentwall import Pingback from django.conf import settings from django.contrib.auth import login from django.core.exceptions import ValidationError from django.shortcuts import render, reverse, redirect from django.views.generic import DetailView, UpdateView, TemplateView, FormView from django.contrib import messages from django.contrib.auth import get_user_model from django.contrib.auth.decorators import login_required, permission_required from django.contrib.auth.hashers import check_password, make_password from django.http import Http404 from django.urls import reverse_lazy from django.utils.decorators import method_decorator from django.utils.timezone import now from apps.auth.tokens import verification_email_token from apps.course.models import Course from apps.notification.utils import send_email from apps.school.models import SchoolSchedule from apps.payment.models import AuthorBalance, CoursePayment, SchoolPayment from .forms import UserEditForm, WithdrawalForm User = get_user_model() @login_required def resend_email_verify(request): token = verification_email_token.make_token(request.user) url = request.scheme + '://' + request.get_host() + str(reverse_lazy('lilcity:verification-email', args=[token])) send_email('Verification Email', request.user.email, "notification/email/verification_email.html", url=url) messages.info(request, 'Письмо подтверждения отправлено.') return redirect('user-edit-profile', request.user.id) @method_decorator(login_required, name='dispatch') class UserView(DetailView): model = User template_name = 'user/profile.html' def get_context_data(self, object): context = super().get_context_data() context['published'] = Course.objects.filter( author=self.object, ) context['pending'] = Course.objects.filter( author=self.object, status=Course.PENDING ) context['drafts'] = Course.objects.filter( author=self.object, status=Course.DRAFT ) context['paid'] = Course.objects.filter( payments__in=CoursePayment.objects.filter( user=self.object, status__in=[ Pingback.PINGBACK_TYPE_REGULAR, Pingback.PINGBACK_TYPE_GOODWILL, Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED, ], ), ).distinct() school_payment = SchoolPayment.objects.filter( user=self.object, date_start__lte=now(), date_end__gt=now(), status__in=[ Pingback.PINGBACK_TYPE_REGULAR, Pingback.PINGBACK_TYPE_GOODWILL, Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED, ], ).last() context['school_payment'] = school_payment if school_payment and school_payment.date_end: context['school_days_left'] = (school_payment.date_end - now().date()).days context['school_schedules'] = SchoolSchedule.objects.filter( weekday__in=school_payment.weekdays if school_payment else [], ) return context @method_decorator(login_required, name='dispatch') class NotificationEditView(TemplateView): template_name = 'user/notification-settings.html' def get(self, request, pk=None): return super().get(request) @method_decorator(login_required, name='dispatch') class PaymentHistoryView(FormView): template_name = 'user/payment-history.html' form_class = WithdrawalForm def get(self, request, pk=None): return super().get(request) def post(self, request, pk=None): form = self.get_form() if not settings.DEBUG and AuthorBalance.objects.filter(created_at__gte=now() - timedelta(days=30)).exists(): messages.error(request, 'Запрос на вывод средств можно сделать только один раз в 30 дней.') return self.form_invalid(form) if form.is_valid(): if request.user.balance < form.cleaned_data['amount']: form.errors['amount'] = 'Сумма для вывода не может быть меньше средств на счету' return self.form_invalid(form) AuthorBalance.objects.create( author=request.user, type=AuthorBalance.OUT, amount=form.cleaned_data['amount'], status=AuthorBalance.PENDING, card=form.cleaned_data['amount'], ) return self.form_valid(form) else: return self.form_invalid(form) def get_success_url(self): success_url = reverse_lazy('user-edit-payments', args=[self.request.user.id]) return success_url @method_decorator(login_required, name='dispatch') class UserEditView(UpdateView): model = User template_name = 'user/profile-settings.html' form_class = UserEditForm @method_decorator(login_required) def dispatch(self, request, *args, **kwargs): self.object = self.get_object() if request.user != self.object: raise Http404() return super().dispatch(request, *args, **kwargs) def post(self, request, *args, **kwargs): # it's magic *-*-*-*-* if 'photo' in request.FILES: photo_fp = request.FILES.pop('photo')[0] fname = photo_fp.name photo = Image.open(photo_fp) lowest_side = min(photo.size) horizontal_padding = (lowest_side - photo.size[0]) / 2 vertical_padding = (lowest_side - photo.size[1]) / 2 photo = photo.crop( ( -horizontal_padding, -vertical_padding, photo.size[0] + horizontal_padding, photo.size[1] + vertical_padding ) ) if photo.size[0] > 512: photo = photo.resize((512, 512,)) buffer = BytesIO() ext = splitext(fname)[1][1:].upper() if ext == 'JPG': ext = 'JPEG' photo.save(buffer, ext) self.object.photo.save(fname, buffer) buffer.close() if not request.POST._mutable: request.POST._mutable = True old_password = request.POST.pop('old_password')[0] new_password1 = request.POST.pop('new_password1')[0] new_password2 = request.POST.pop('new_password2')[0] if old_password: if request.user.check_password(old_password) and new_password1 == new_password2: request.user.set_password(new_password1) request.user.save() login(request, request.user) else: messages.error(request, 'Неверный пароль.') messages.info(request, 'Данные сохранены.') return super().post(request, *args, **kwargs) def get_success_url(self): return reverse('user-edit-profile', args=[self.object.id])