from datetime import datetime, timedelta, date from paymentwall import Pingback from django.contrib.auth import get_user_model from django.contrib.auth.decorators import login_required, user_passes_test from django.db.utils import IntegrityError from django.db.models import Min, F, Func, Q, Value from django.http import Http404 from django.shortcuts import get_object_or_404, redirect from django.utils.decorators import method_decorator from django.utils.timezone import now from django.views.generic import ListView, UpdateView, TemplateView, DetailView from apps.course.models import Course from apps.payment.models import SchoolPayment from .models import LiveLesson, SchoolSchedule User = get_user_model() def is_admin_or_teacher(function=None, login_url=None): actual_decorator = user_passes_test( lambda u: u.role in [User.ADMIN_ROLE, User.TEACHER_ROLE], login_url=login_url ) if function: return actual_decorator(function) return actual_decorator @method_decorator([login_required, is_admin_or_teacher], name='dispatch') class LiveLessonsView(ListView): model = LiveLesson template_name = 'school/livelessons_list.html' def get_queryset(self): september2018 = date(2018, 9, 1) date_start = (now() - timedelta(days=7)).date() if date_start < september2018: date_start = september2018 date_range = Q( date__range=[ date_start, date_start + timedelta(days=17), ] ) queryset = LiveLesson.objects.filter(date_range) if queryset.count() < 17: for i in range(18): try: LiveLesson.objects.create( date=date_start + timedelta(days=i), ) except IntegrityError: pass queryset = LiveLesson.objects.filter(date_range) return queryset class LiveLessonsDetailView(DetailView): model = LiveLesson template_name = 'school/livelesson_detail.html' def get(self, request, pk=None): self.object = self.get_object() if request.user.is_authenticated: is_purchased = SchoolPayment.objects.filter( user=request.user, date_start__lte=now(), date_end__gte=now() - timedelta(days=7), status__in=[ Pingback.PINGBACK_TYPE_REGULAR, Pingback.PINGBACK_TYPE_GOODWILL, Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED, ], weekdays__contains=[self.object.date.weekday() + 1], ).exists() if not is_purchased and request.user.role not in [User.ADMIN_ROLE, User.TEACHER_ROLE]: raise Http404 else: self.template_name = 'school/livelesson_detail_unauth.html' context = self.get_context_data(object=self.object) return self.render_to_response(context) @method_decorator([login_required, is_admin_or_teacher], name='dispatch') class LiveLessonEditView(TemplateView): template_name = 'course/course_edit.html' def get(self, request, pk=None): if pk: self.object = get_object_or_404(LiveLesson, pk=pk) else: try: self.object = LiveLesson.objects.get(date=now().date()) except LiveLesson.DoesNotExist: self.object = LiveLesson.objects.create() return super().get(request) def get_context_data(self): context = super().get_context_data() context['object'] = self.object context['live'] = 'true' return context class SchoolView(TemplateView): template_name = 'school/summer_school.html' def get_context_data(self): context = super().get_context_data() date_now = now().date() now_time = now() try: school_schedule = SchoolSchedule.objects.get(weekday=now_time.isoweekday()) except SchoolSchedule.DoesNotExist: online = False else: end_at = datetime.combine(now_time.today(), school_schedule.start_at) online = ( school_schedule.start_at <= now_time.time() and (end_at + timedelta(hours=1)).time() >= now_time.time() and school_schedule.current_live_lesson ) school_schedules = SchoolSchedule.objects.all() try: school_schedules_sorted = sorted(school_schedules, key=lambda ss: ss.current_live_lesson and ss.current_live_lesson.date) except Exception: school_schedules_sorted = school_schedules prev_live_lessons = [] prev_live_lessons_exists = False subscription_ends = None school_payment_exists = False school_schedules_purchased = [] school_purchased_future = False prev_school_payments = None prev_range = [date_now - timedelta(days=8), date_now - timedelta(days=1)] if self.request.user.is_authenticated: school_payment = SchoolPayment.objects.filter( user=self.request.user, status__in=SchoolPayment.PW_PAID_STATUSES, date_start__lte=date_now, date_end__gte=date_now ) school_payment_exists = school_payment.exists() school_purchased_future = SchoolPayment.objects.filter( user=self.request.user, status__in=SchoolPayment.PW_PAID_STATUSES, date_start__gt=date_now, date_end__gt=date_now ) if school_purchased_future.exists(): subscription_ends = school_purchased_future.filter(add_days=False).latest( 'date_end').date_end elif school_payment_exists: subscription_ends = school_payment.filter(add_days=False).latest('date_end').date_end school_schedules_purchased = school_payment.annotate( joined_weekdays=Func(F('weekdays'), function='unnest',) ).values_list('joined_weekdays', flat=True).distinct() prev_school_payments = SchoolPayment.objects.filter( date_start__lte=prev_range[1], date_end__gte=prev_range[0], user=self.request.user, status__in=[ Pingback.PINGBACK_TYPE_REGULAR, Pingback.PINGBACK_TYPE_GOODWILL, Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED, ], weekdays__len__gt=0, ) # берем все подписки, которые были в периоде for sp in prev_school_payments: # берем все уроки в оплаченном промежутке date_range = [max(sp.date_start, prev_range[0]), min(sp.date_end, prev_range[1])] prev_live_lessons += list(LiveLesson.objects.filter( date__range=date_range, deactivated_at__isnull=True, date__week_day__in=list(map(lambda x: 1 if x == 7 else x+1, sp.weekdays)), ).values_list('id', flat=True)) prev_live_lessons = LiveLesson.objects.filter(id__in=set(prev_live_lessons)).order_by('-date') prev_live_lessons_exists = prev_live_lessons.exists() if prev_live_lessons_exists: school_schedules_dict = {ss.weekday: ss for ss in school_schedules} school_schedules_dict[0] = school_schedules_dict.get(7) for ll in prev_live_lessons: ll.school_schedule = school_schedules_dict.get(ll.date.isoweekday()) context.update({ 'online': online, 'prev_live_lessons': prev_live_lessons, 'prev_live_lessons_exists': prev_live_lessons_exists, 'course_items': Course.objects.filter(status=Course.PUBLISHED)[:6], 'is_purchased': school_payment_exists, 'is_purchased_future': False, 'min_school_price': SchoolSchedule.objects.aggregate(Min('month_price'))['month_price__min'], 'school_schedules_sorted': school_schedules_sorted, 'school_schedules': school_schedules, 'school_schedules_purchased': school_schedules_purchased, 'school_purchased_future': school_purchased_future, 'prev_school_payments_exists': prev_school_payments and prev_school_payments.exists(), 'subscription_ends': subscription_ends, 'prolong_date_start': subscription_ends + timedelta(days=1) if subscription_ends else None, 'allow_prolong': subscription_ends - date_now <= timedelta(days=7) if not school_purchased_future and subscription_ends else False, }) return context class SchoolSchedulesPrintView(TemplateView): template_name = 'school/schedules_print.html' def get_context_data(self): context = super().get_context_data() context['school_schedules'] = SchoolSchedule.objects.all() return context