Auto suggest new class times
This commit is contained in:
parent
ab1a04d800
commit
41f6969a4a
|
@ -11,7 +11,7 @@ from rest_auth.registration.serializers import RegisterSerializer
|
||||||
from rest_auth.serializers import PasswordChangeSerializer, PasswordResetSerializer, PasswordResetConfirmSerializer, LoginSerializer
|
from rest_auth.serializers import PasswordChangeSerializer, PasswordResetSerializer, PasswordResetConfirmSerializer, LoginSerializer
|
||||||
from rest_auth.serializers import UserDetailsSerializer
|
from rest_auth.serializers import UserDetailsSerializer
|
||||||
import re
|
import re
|
||||||
import datetime, time
|
import datetime, time, calendar
|
||||||
|
|
||||||
from . import models, fields, utils, utils_ldap, utils_auth, utils_stats
|
from . import models, fields, utils, utils_ldap, utils_auth, utils_stats
|
||||||
from .. import settings, secrets
|
from .. import settings, secrets
|
||||||
|
@ -528,10 +528,80 @@ class CourseDetailSerializer(serializers.ModelSerializer):
|
||||||
sessions = SessionListSerializer(many=True, read_only=True)
|
sessions = SessionListSerializer(many=True, read_only=True)
|
||||||
name = serializers.CharField(max_length=100)
|
name = serializers.CharField(max_length=100)
|
||||||
description = fields.HTMLField(max_length=6000)
|
description = fields.HTMLField(max_length=6000)
|
||||||
|
suggestion = serializers.SerializerMethodField()
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Course
|
model = models.Course
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
|
def get_suggestion(self, obj):
|
||||||
|
def iter_dates():
|
||||||
|
start_of_month = utils.today_alberta_tz().replace(day=1)
|
||||||
|
for i in range(90):
|
||||||
|
yield start_of_month + datetime.timedelta(days=i)
|
||||||
|
|
||||||
|
def iter_matching_dates(weekday, week_num=False):
|
||||||
|
week_num_counts = [0] * 13
|
||||||
|
for date in iter_dates():
|
||||||
|
if date.weekday() == weekday:
|
||||||
|
week_num_counts[date.month] += 1
|
||||||
|
if week_num and week_num_counts[date.month] != week_num:
|
||||||
|
continue
|
||||||
|
yield date
|
||||||
|
|
||||||
|
def next_date(weekday, week_num=False):
|
||||||
|
for date in iter_matching_dates(weekday, week_num):
|
||||||
|
if date > utils.today_alberta_tz():
|
||||||
|
return date
|
||||||
|
raise
|
||||||
|
|
||||||
|
def course_is_usually_monthly(course):
|
||||||
|
two_months_ago = utils.today_alberta_tz() - datetime.timedelta(days=61)
|
||||||
|
recent_sessions = obj.sessions.filter(datetime__gte=two_months_ago)
|
||||||
|
if recent_sessions.count() < 3:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
prev_session = obj.sessions.last()
|
||||||
|
|
||||||
|
if obj.id == 273: # monthly clean 10:00 AM 3rd Saturday of each month
|
||||||
|
date = next_date(calendar.SATURDAY, week_num=3)
|
||||||
|
time = datetime.time(10, 0)
|
||||||
|
dt = datetime.datetime.combine(date, time)
|
||||||
|
dt = utils.TIMEZONE_CALGARY.localize(dt)
|
||||||
|
cost = 0
|
||||||
|
max_students = None
|
||||||
|
elif obj.id == 317: # members' meeting 7:00 PM 3rd Thursday of odd months, Wednesday of even months
|
||||||
|
if utils.today_alberta_tz().month % 2 == 0:
|
||||||
|
date = next_date(calendar.WEDNESDAY, week_num=3)
|
||||||
|
else:
|
||||||
|
date = next_date(calendar.THURSDAY, week_num=3)
|
||||||
|
time = datetime.time(19, 0)
|
||||||
|
dt = datetime.datetime.combine(date, time)
|
||||||
|
dt = utils.TIMEZONE_CALGARY.localize(dt)
|
||||||
|
cost = 0
|
||||||
|
max_students = None
|
||||||
|
elif prev_session:
|
||||||
|
prev_session = obj.sessions.last()
|
||||||
|
dt = prev_session.datetime
|
||||||
|
|
||||||
|
if course_is_usually_monthly(obj):
|
||||||
|
offset_weeks = 4
|
||||||
|
else:
|
||||||
|
offset_weeks = 1
|
||||||
|
dt = dt + datetime.timedelta(weeks=offset_weeks)
|
||||||
|
|
||||||
|
five_days_from_now = utils.now_alberta_tz() + datetime.timedelta(days=5)
|
||||||
|
while dt < five_days_from_now:
|
||||||
|
dt = dt + datetime.timedelta(weeks=offset_weeks)
|
||||||
|
|
||||||
|
cost = prev_session.cost
|
||||||
|
max_students = prev_session.max_students
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return dict(datetime=dt, cost=str(cost), max_students=max_students)
|
||||||
|
|
||||||
|
|
||||||
class UserTrainingSerializer(serializers.ModelSerializer):
|
class UserTrainingSerializer(serializers.ModelSerializer):
|
||||||
session = SessionListSerializer()
|
session = SessionListSerializer()
|
||||||
|
|
|
@ -420,6 +420,11 @@ export function InstructorClassList(props) {
|
||||||
).sort((a, b) => a.datetime > b.datetime ? 1 : -1));
|
).sort((a, b) => a.datetime > b.datetime ? 1 : -1));
|
||||||
}, [input.datetime]);
|
}, [input.datetime]);
|
||||||
|
|
||||||
|
const fillSuggestion = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setInput({ ...input, ...course.suggestion });
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Header size='medium'>Instructor Panel</Header>
|
<Header size='medium'>Instructor Panel</Header>
|
||||||
|
@ -434,6 +439,10 @@ export function InstructorClassList(props) {
|
||||||
|
|
||||||
<p>Documentation: <a href='https://wiki.protospace.ca/Be_a_Course_Instructor' target='_blank' rel='noopener noreferrer'>https://wiki.protospace.ca/Be_a_Course_Instructor</a></p>
|
<p>Documentation: <a href='https://wiki.protospace.ca/Be_a_Course_Instructor' target='_blank' rel='noopener noreferrer'>https://wiki.protospace.ca/Be_a_Course_Instructor</a></p>
|
||||||
|
|
||||||
|
{course.suggestion &&
|
||||||
|
<p><Button onClick={fillSuggestion}>Suggest</Button> based off previous classes.</p>
|
||||||
|
}
|
||||||
|
|
||||||
<InstructorClassEditor input={input} setInput={setInput} error={error} token={token} />
|
<InstructorClassEditor input={input} setInput={setInput} error={error} token={token} />
|
||||||
|
|
||||||
<Form.Button loading={loading} error={error.non_field_errors}>
|
<Form.Button loading={loading} error={error.non_field_errors}>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user