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.
378 lines
17 KiB
378 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.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({
|
|
'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=[
|
|
Pingback.PINGBACK_TYPE_REGULAR,
|
|
Pingback.PINGBACK_TYPE_GOODWILL,
|
|
Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED,
|
|
],
|
|
)
|
|
|
|
# берем все подписки, которые были в периоде
|
|
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
|
|
|