from datetime import datetime, timedelta, date import arrow 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 django.conf import settings from apps.content.models import Banner from apps.course.models import Course from apps.payment.models import SchoolPayment, DrawingCampPayment 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): date_start = (now() - timedelta(days=7)).date() date_start, date_end = SchoolPayment.get_date_range(date_start, days=16, is_camp=False) date_range = Q( date__range=[date_start, date_end] ) exist_dates = LiveLesson.objects.filter(date_range, is_camp=False).values_list('date', flat=True) for i in range((date_end - date_start).days + 1): d = date_start + timedelta(days=i) if d not in exist_dates: try: LiveLesson.objects.create( date=date_start + timedelta(days=i), is_camp=False, ) except IntegrityError: pass queryset = LiveLesson.objects.filter(date_range) return queryset @method_decorator([login_required, is_admin_or_teacher], name='dispatch') class DrawingCampLessonsView(ListView): model = LiveLesson template_name = 'school/livelessons_list.html' def get_context_data(self, *args, **kwargs): context = super().get_context_data(*args, **kwargs) context['is_camp'] = True return context def get_queryset(self): date_start = (now() - timedelta(days=7)).date() date_start, date_end = DrawingCampPayment.adjust_date_bounds(date_start, date_start + timedelta(days=23), is_camp=True) date_range = Q( date__range=[date_start, date_end] ) exist_dates = LiveLesson.objects.filter(date_range, is_camp=True).values_list('date', flat=True) for i in range((date_end - date_start).days + 1): d = date_start + timedelta(days=i) if d.isoweekday() in DrawingCampPayment.WEEKDAYS and d not in exist_dates: try: LiveLesson.objects.create( date=date_start + timedelta(days=i), is_camp=True, ) 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, lesson_date=None, is_camp=False): if pk: self.object = self.get_object() if lesson_date: try: self.object = LiveLesson.objects.get(date=datetime.strptime(lesson_date, '%d-%m-%y'), is_camp=is_camp) except Exception: raise Http404() if request.user.is_authenticated: if self.object.is_camp: is_purchased = DrawingCampPayment.objects.all() else: is_purchased = SchoolPayment.objects.filter(weekdays__contains=[self.object.date.weekday() + 1],) is_purchased = is_purchased.paid().filter( user=request.user, date_start__lte=now(), date_end__gte=now() - timedelta(days=7), ).exists() or is_purchased.paid().filter( user=request.user, date_start__lte=now(), date_end__gte=now() - timedelta(days=30), package__duration__lte=9, ).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, is_camp=False): if pk: self.object = get_object_or_404(LiveLesson, pk=pk, is_camp=is_camp) else: try: self.object = LiveLesson.objects.get(date=now().date()) except LiveLesson.DoesNotExist: self.object = LiveLesson.objects.create(is_camp=is_camp) return super().get(request) def get_context_data(self): context = super().get_context_data() context['object'] = self.object context['live'] = 'true' context['is_camp'] = 'true' if self.object.is_camp else 'false' 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(), is_camp=False) 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.filter(is_camp=False) 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=7), 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: # берем все уроки в оплаченном промежутке if sp.package and sp.package.duration >= 9: date_range = [max(sp.date_start, date_now - timedelta(30)), min(sp.date_end, prev_range[1])] else: 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)), ).exclude(title='').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({ 'banners': Banner.get_for_page(Banner.PAGE_SCHOOL), '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': school_purchased_future and school_purchased_future.exists(), '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 and school_purchased_future.last(), '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 class DrawingCampView(TemplateView): template_name = 'school/drawing_camp.html' def get_context_data(self): context = super().get_context_data() date_now = now().date() now_time = now() online = False next_schedule = None next_lesson_start = None if now_time.isoweekday() in DrawingCampPayment.WEEKDAYS: try: school_schedule = SchoolSchedule.objects.get(weekday=now_time.isoweekday(), is_camp=True) 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_camp_lesson ) if school_schedule.current_camp_lesson and school_schedule.start_at > now_time.time(): next_schedule = school_schedule next_lesson_start = next_schedule.start_at_humanize if not next_schedule: next_camp_lesson = LiveLesson.objects.filter(date__gt=date_now, is_camp=True).order_by('date').first() if next_camp_lesson and next_camp_lesson.school_schedule: next_schedule = next_camp_lesson.school_schedule next_lesson_start = arrow.get(datetime.combine(next_camp_lesson.date, next_schedule.start_at), settings.TIME_ZONE).humanize(locale='ru') school_schedules = SchoolSchedule.objects.filter(weekday__in=DrawingCampPayment.WEEKDAYS, is_camp=True) try: school_schedules_sorted = sorted(school_schedules, key=lambda ss: ss.current_camp_lesson and ss.current_camp_lesson.date) except Exception: school_schedules_sorted = school_schedules prev_live_lessons = [] prev_live_lessons_exists = False subscription_ends = None camp_payment_exists = False camp_purchased_future = False prev_camp_payments = None prev_range = [date_now - timedelta(days=7), date_now - timedelta(days=1)] if self.request.user.is_authenticated: camp_payment = DrawingCampPayment.objects.filter( user=self.request.user, status__in=DrawingCampPayment.PW_PAID_STATUSES, date_start__lte=date_now, date_end__gte=date_now ) camp_payment_exists = camp_payment.exists() camp_purchased_future = DrawingCampPayment.objects.filter( user=self.request.user, status__in=DrawingCampPayment.PW_PAID_STATUSES, date_start__gt=date_now, date_end__gt=date_now ) if camp_purchased_future.exists(): subscription_ends = camp_purchased_future.latest('date_end').date_end elif camp_payment_exists: subscription_ends = camp_payment.latest('date_end').date_end prev_camp_payments = DrawingCampPayment.objects.filter( date_start__lte=prev_range[1], date_end__gte=prev_range[0], user=self.request.user, status__in=DrawingCampPayment.PW_PAID_STATUSES, ) # берем все подписки, которые были в периоде for sp in prev_camp_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, is_camp=True, ).exclude(title='').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({ 'next_schedule': next_schedule, 'next_lesson_start': next_lesson_start, 'is_drawing_camp': True, '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': camp_payment_exists, 'is_purchased_future': camp_purchased_future and camp_purchased_future.exists(), 'drawing_camp_price': DrawingCampPayment.MONTH_PRICE, 'school_schedules_sorted': school_schedules_sorted, 'school_schedules': school_schedules, 'school_schedules_purchased': DrawingCampPayment.WEEKDAYS if camp_payment_exists else [], 'school_purchased_future': camp_purchased_future and camp_purchased_future.last(), 'prev_school_payments_exists': prev_camp_payments and prev_camp_payments.exists(), 'subscription_ends': subscription_ends, 'prolong_date_start': subscription_ends + timedelta(days=1) if subscription_ends else None, }) return context class FreeLessonsView(TemplateView): template_name = 'school/free_lessons.html'