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.
 
 
 
 
 
 

377 lines
17 KiB

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.ajust_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.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,
],
).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:
# берем все уроки в оплаченном промежутке
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