Add school schedules page & logic

remotes/origin/hasaccess
Ivlev Denis 8 years ago
parent a8d0532e63
commit 8f8b20682a
  1. 2
      apps/school/fixtures/school_schedules.json
  2. 17
      apps/school/migrations/0012_auto_20180417_1344.py
  3. 63
      apps/school/models.py
  4. 36
      apps/school/templates/blocks/schedule.html
  5. 28
      apps/school/views.py
  6. 17
      project/templates/blocks/header.html
  7. 11
      project/views.py

@ -34,7 +34,7 @@
"pk": 3, "pk": 3,
"fields": { "fields": {
"weekday": 3, "weekday": 3,
"title": "Пластелин", "title": "Пластилин",
"short_description": "Однажды он затеял скандал на торговой площади ради леденца", "short_description": "Однажды он затеял скандал на торговой площади ради леденца",
"description": "Однажды он затеял скандал на торговой площади ради леденца, вокруг собралась толпа, и полицейские попросили хозяина лавки открыть её во время сиесты и подарить мальчику сладость.", "description": "Однажды он затеял скандал на торговой площади ради леденца, вокруг собралась толпа, и полицейские попросили хозяина лавки открыть её во время сиесты и подарить мальчику сладость.",
"materials": "Он добивался своего капризами и симуляцией, всегда стремился выделиться и привлечь к себе внимание.", "materials": "Он добивался своего капризами и симуляцией, всегда стремился выделиться и привлечь к себе внимание.",

@ -0,0 +1,17 @@
# Generated by Django 2.0.3 on 2018-04-17 10:44
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('school', '0011_schoolschedule_short_description'),
]
operations = [
migrations.AlterModelOptions(
name='schoolscheduleimage',
options={'ordering': ('-created_at',), 'verbose_name': 'Изображение работ', 'verbose_name_plural': 'Изображения работ'},
),
]

@ -1,9 +1,10 @@
from django.db import models from django.db import models
from django.utils.timezone import now
from project.mixins import BaseModel, DeactivatedMixin from project.mixins import BaseModel, DeactivatedMixin
from apps.content.models import ImageObject from apps.content.models import ImageObject
from apps.course.models import Comment from apps.payment import models as payment_models
class SchoolSchedule(models.Model): class SchoolSchedule(models.Model):
@ -16,14 +17,20 @@ class SchoolSchedule(models.Model):
(6, 'суббота'), (6, 'суббота'),
(7, 'воскресенье'), (7, 'воскресенье'),
) )
weekday = models.PositiveSmallIntegerField('День недели', choices=WEEKDAY_CHOICES, unique=True) weekday = models.PositiveSmallIntegerField(
'День недели', choices=WEEKDAY_CHOICES, unique=True
)
title = models.CharField('Заголовок', default='', max_length=100, db_index=True) title = models.CharField('Заголовок', default='', max_length=100, db_index=True)
short_description = models.CharField('Короткое описание', default='', max_length=100, db_index=True) short_description = models.CharField(
'Короткое описание', default='', max_length=100, db_index=True
)
description = models.TextField('Описание') description = models.TextField('Описание')
materials = models.TextField('Материалы') materials = models.TextField('Материалы')
age = models.PositiveSmallIntegerField('Возраст', default=0) age = models.PositiveSmallIntegerField('Возраст', default=0)
month_price = models.DecimalField('Цена', max_digits=8, decimal_places=2, default=0) month_price = models.DecimalField('Цена', max_digits=8, decimal_places=2, default=0)
day_discount = models.DecimalField('Скидка, в валюте', max_digits=8, decimal_places=2, default=0) day_discount = models.DecimalField(
'Скидка, в валюте', max_digits=8, decimal_places=2, default=0
)
start_at = models.TimeField('Начало урока', null=True) start_at = models.TimeField('Начало урока', null=True)
class Meta: class Meta:
@ -34,16 +41,45 @@ class SchoolSchedule(models.Model):
def __str__(self): def __str__(self):
return dict(self.WEEKDAY_CHOICES).get(self.weekday, '') return dict(self.WEEKDAY_CHOICES).get(self.weekday, '')
def is_online(self):
return now().isoweekday() == self.weekday and now().time() >= self.start_at
def is_purchased(self):
try:
school_payment = payment_models.SchoolPayment.objects.get(
weekdays__contains=[self.weekday],
date_start__gte=now().date(),
date_end__lte=now().date(),
)
except payment_models.SchoolPayment.DoesNotExist:
return False
else:
return school_payment.is_deliverable()
def current_live_lesson(self):
now_time = now()
weekday = self.weekday
live_lesson = LiveLesson.objects.filter(
date__week_day=weekday + 1 if weekday % 7 else 1,
date__gte=now_time.date(),
).first()
return live_lesson
class SchoolScheduleImage(models.Model): class SchoolScheduleImage(models.Model):
schoolschedule = models.ForeignKey( schoolschedule = models.ForeignKey(
SchoolSchedule, on_delete=models.CASCADE, SchoolSchedule,
verbose_name='День занятия', related_name='schoolschedule_images' on_delete=models.CASCADE,
verbose_name='День занятия',
related_name='schoolschedule_images',
) )
img = models.ForeignKey( img = models.ForeignKey(
ImageObject, related_name='schoolschedule_images', ImageObject,
verbose_name='Объект изображения', on_delete=models.CASCADE, related_name='schoolschedule_images',
null=True, blank=True, verbose_name='Объект изображения',
on_delete=models.CASCADE,
null=True,
blank=True,
) )
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
@ -61,9 +97,12 @@ class LiveLesson(BaseModel, DeactivatedMixin):
stream = models.URLField('Ссылка на VIMEO', default='', blank=True) stream = models.URLField('Ссылка на VIMEO', default='', blank=True)
date = models.DateField(null=True, blank=True) date = models.DateField(null=True, blank=True)
cover = models.ForeignKey( cover = models.ForeignKey(
ImageObject, related_name='livelesson_covers', ImageObject,
verbose_name='Обложка урока школы', on_delete=models.CASCADE, related_name='livelesson_covers',
null=True, blank=True, verbose_name='Обложка урока школы',
on_delete=models.CASCADE,
null=True,
blank=True,
) )
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)

@ -1,31 +1,44 @@
{% load static %} {% load static %}
{% load thumbnail %}
<div class="section"> <div class="section">
<div class="section__center center center_md"> <div class="section__center center center_md">
<div class="title title_center">Расписание</div> <div class="title title_center">Расписание</div>
<div class="timing js-timing"> <div class="timing js-timing">
<div class="timing__week"> <div class="timing__week">
{% for school_schedule in school_schedules %} {% for school_schedule in school_schedules %}
{% with current_live_lesson=school_schedule.current_live_lesson %}
<div class="timing__item js-timing-item"> <div class="timing__item js-timing-item">
<div class="timing__cell"> <div class="timing__cell">
<div class="timing__info"> <div class="timing__info">
<div class="timing__day active">{{ school_schedule }}</div> <div class="timing__day{% if school_schedule.is_online %} active{% endif %}">
<div class="timing__date">2 апреля</div> {{ school_schedule }}
</div>
{% if current_live_lesson %}
<div class="timing__date">{{ current_live_lesson.date }}</div>
{% endif %}
</div> </div>
<div class="timing__buy"> <div class="timing__buy">
<div class="timing__time">17:00 (МСК)</div> <div class="timing__time">{{ school_schedule.start_at }} (МСК)</div>
<a class="timing__btn btn" href="#">купить</a> {% include './pay_btn.html' %}
</div> </div>
</div> </div>
<div class="timing__cell"> <div class="timing__cell">
<div class="timing__preview"> <div class="timing__preview">
<img class="timing__pic" src="{% static 'img/user.jpg' %}"> {% thumbnail current_live_lesson.cover.image "70x70" crop="center" as im %}
<img class="timing__pic" src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}"/>
{% empty %}
<img class="timing__pic" src="{% static 'img/no_cover.png' %}" width="70px" height="70px"/>
{% endthumbnail %}
</div> </div>
</div> </div>
<div class="timing__cell"> <div class="timing__cell">
<div class="timing__title">{{ school_schedule.title }}, <div class="timing__title">{{ school_schedule.title }}{% if current_live_lesson %},
<span class="bold">Санкт-Петербург</span> <span class="bold">{{ current_live_lesson.title }}</span>
{% endif %}
</div> </div>
<div class="timing__content">{{ school_schedule.short_description }}</div> {% if current_live_lesson %}
<div class="timing__content">{{ current_live_lesson.short_description }}</div>
{% endif %}
<div class="timing__more"> <div class="timing__more">
<div class="timing__head">Материалы</div> <div class="timing__head">Материалы</div>
<div class="timing__row"> <div class="timing__row">
@ -45,7 +58,9 @@
<div class="timing__works"> <div class="timing__works">
{% for image in school_schedule.schoolschedule_images.all %} {% for image in school_schedule.schoolschedule_images.all %}
<a class="timing__work" href="#"> <a class="timing__work" href="#">
<img class="timing__pic" src="{{ image.img.image.url }}"> {% thumbnail image.img.image "48x48" crop="center" as im %}
<img class="timing__pic" src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}"/>
{% endthumbnail %}
</a> </a>
{% endfor %} {% endfor %}
</div> </div>
@ -60,6 +75,7 @@
</button> </button>
</div> </div>
</div> </div>
{% endwith %}
{% endfor %} {% endfor %}
{% comment %} {% comment %}
<div class="timing__item js-timing-item"> <div class="timing__item js-timing-item">
@ -516,7 +532,7 @@
{% endcomment %} {% endcomment %}
</div> </div>
<div class="timing__foot"> <div class="timing__foot">
<a class="timing__btn btn" href="#">купить</a> {% include './pay_btn.html' %}
<a class="timing__print" href="#">Распечатать расписание <a class="timing__print" href="#">Распечатать расписание
<span class="bold">чтобы не забыть</span> <span class="bold">чтобы не забыть</span>
<svg class="icon icon-print"> <svg class="icon icon-print">

@ -1,10 +1,13 @@
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.auth.decorators import login_required, user_passes_test from django.contrib.auth.decorators import login_required, user_passes_test
from django.db.models import Min from django.db.models import Min
from django.http import Http404
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.utils.timezone import now
from django.views.generic import ListView, UpdateView, TemplateView, DetailView from django.views.generic import ListView, UpdateView, TemplateView, DetailView
from apps.payment.models import SchoolPayment
from .models import LiveLesson, SchoolSchedule from .models import LiveLesson, SchoolSchedule
User = get_user_model() User = get_user_model()
@ -12,11 +15,11 @@ User = get_user_model()
def is_admin_or_teacher(function=None, login_url=None): def is_admin_or_teacher(function=None, login_url=None):
actual_decorator = user_passes_test( actual_decorator = user_passes_test(
lambda u: u.role in [User.ADMIN_ROLE, User.TEACHER_ROLE], lambda u: u.role in [User.ADMIN_ROLE, User.TEACHER_ROLE], login_url=login_url
login_url=login_url,
) )
if function: if function:
return actual_decorator(function) return actual_decorator(function)
return actual_decorator return actual_decorator
@ -26,11 +29,28 @@ class LiveLessonsView(ListView):
template_name = 'school/livelessons_list.html' template_name = 'school/livelessons_list.html'
@method_decorator([login_required, is_admin_or_teacher], name='dispatch') @method_decorator(login_required, name='dispatch')
class LiveLessonsDetailView(DetailView): class LiveLessonsDetailView(DetailView):
model = LiveLesson model = LiveLesson
template_name = 'school/livelesson_detail.html' template_name = 'school/livelesson_detail.html'
def get(self, request, pk=None):
response = super().get(request, pk=pk)
try:
school_payment = SchoolPayment.objects.get(
user=request.user, date_start__gte=now(), date__end__lte=now()
)
except SchoolPayment.DoesNotExist:
school_payment = None
if request.user.role not in [User.ADMIN_ROLE, User.TEACHER_ROLE] or not (
request.user.role == User.USER_ROLE and
school_payment and
school_payment.is_deliverable()
):
raise Http404
return response
@method_decorator([login_required, is_admin_or_teacher], name='dispatch') @method_decorator([login_required, is_admin_or_teacher], name='dispatch')
class LiveLessonEditView(TemplateView): class LiveLessonEditView(TemplateView):
@ -57,6 +77,6 @@ class SchoolView(TemplateView):
context = super().get_context_data() context = super().get_context_data()
context.update({ context.update({
'school_schedules': SchoolSchedule.objects.all(), 'school_schedules': SchoolSchedule.objects.all(),
'min_school_price': SchoolSchedule.objects.all().aggregate(Min('month_price'))['month_price__min'], 'min_school_price': SchoolSchedule.objects.aggregate(Min('month_price'))['month_price__min'],
}) })
return context return context

@ -1,4 +1,4 @@
{% load static %} {% load active_link_tags %} {% load category_menu_items from lilcity_category %} {% load static %} {% load thumbnail %} {% load active_link_tags %} {% load category_menu_items from lilcity_category %}
<header class="header header_bg js-header"> <header class="header header_bg js-header">
<div class="header__center center"> <div class="header__center center">
<div class="header__container"> <div class="header__container">
@ -27,8 +27,9 @@
<nav class="header__nav"> <nav class="header__nav">
<div class="header__group"> <div class="header__group">
<a class="header__section header__section_sub js-header-section {% active_link 'school:school' %}" href="{% url 'school:school' %}"> <a class="header__section header__section_sub js-header-section {% active_link 'school:school' %}" href="{% url 'school:school' %}">
ОНЛАЙН-ШКОЛА ОНЛАЙН-ШКОЛА {% if online %}
<div class="header__dot"></div> <div class="header__dot"></div>
{% endif %}
</a> </a>
<div class="header__list js-header-list"> <div class="header__list js-header-list">
<a class="header__link" data-scroll href="/#about"> <a class="header__link" data-scroll href="/#about">
@ -81,15 +82,13 @@
</div> </div>
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
<div class="header__login"> <div class="header__login">
{% if request.user.photo %}
<div class="header__ava ava"> <div class="header__ava ava">
<img class="ava__pic" src="{{ request.user.photo.url }}"> {% thumbnail request.user.photo "48x48" crop="center" as im %}
<img class="ava__pic" src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}" />
{% empty %}
<img class="ava__pic" src="{% static 'img/no_cover.png' %}" width="48px" height="48px" />
{% endthumbnail %}
</div> </div>
{% else %}
<div class="header__ava ava">
<img class="ava__pic" src="{% static 'img/user.jpg' %}">
</div>
{% endif %}
<div class="header__drop"> <div class="header__drop">
{% if request.user.role >= request.user.AUTHOR_ROLE %} {% if request.user.role >= request.user.AUTHOR_ROLE %}
<a class="header__link header__link_border" href="{% url 'user-edit-payments' request.user.id %}">{{ request.user.balance }} руб.</a> <a class="header__link header__link_border" href="{% url 'user-edit-payments' request.user.id %}">{{ request.user.balance }} руб.</a>

@ -1,6 +1,7 @@
from django.db.models import Min from django.db.models import Min
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.views.generic import TemplateView from django.views.generic import TemplateView
from django.utils.timezone import now
from apps.course.models import Course from apps.course.models import Course
from apps.school.models import SchoolSchedule from apps.school.models import SchoolSchedule
@ -13,7 +14,17 @@ class IndexView(TemplateView):
def get_context_data(self): def get_context_data(self):
context = super().get_context_data() context = super().get_context_data()
now_time = now()
try:
school_schedule = SchoolSchedule.objects.get(weekday=now_time.isoweekday())
except SchoolSchedule.DoesNotExist:
online = False
else:
online = school_schedule.start_at <= now().time()
context.update({ context.update({
'online': online,
'course_items': Course.objects.filter(status=Course.PUBLISHED)[:6], 'course_items': Course.objects.filter(status=Course.PUBLISHED)[:6],
'school_schedules': SchoolSchedule.objects.all(), 'school_schedules': SchoolSchedule.objects.all(),
'min_school_price': SchoolSchedule.objects.all().aggregate(Min('month_price'))['month_price__min'], 'min_school_price': SchoolSchedule.objects.all().aggregate(Min('month_price'))['month_price__min'],

Loading…
Cancel
Save