bornhack-website/src/teams/views/shifts.py

313 lines
9.9 KiB
Python
Raw Normal View History

from django import forms
from django.contrib import messages
2018-07-02 21:52:52 +00:00
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponseRedirect
from django.template import Context, Template
from django.urls import reverse
from django.utils import timezone
from django.views.generic import (
CreateView,
DeleteView,
FormView,
ListView,
2019-06-16 12:32:24 +00:00
TemplateView,
UpdateView,
View,
)
2018-07-02 21:52:52 +00:00
from psycopg2.extras import DateTimeTZRange
from camps.mixins import CampViewMixin
2019-06-16 12:32:24 +00:00
from ..models import Team, TeamMember, TeamShift
2018-07-02 21:52:52 +00:00
class ShiftListView(LoginRequiredMixin, CampViewMixin, ListView):
model = TeamShift
2018-08-05 10:18:10 +00:00
template_name = "team_shift_list.html"
2018-07-02 21:52:52 +00:00
context_object_name = "shifts"
active_menu = "shifts"
2018-07-02 21:52:52 +00:00
def get_queryset(self):
queryset = super().get_queryset()
2019-06-16 12:32:24 +00:00
return queryset.filter(team__slug=self.kwargs["team_slug"])
2018-07-02 21:52:52 +00:00
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
2019-06-16 12:32:24 +00:00
context["team"] = Team.objects.get(
camp=self.camp, slug=self.kwargs["team_slug"]
2018-07-02 21:52:52 +00:00
)
return context
def date_choices(camp):
2018-07-02 21:52:52 +00:00
index = 0
minute_choices = []
# To begin with we assume a shift can not be shorter than an hour
SHIFT_MINIMUM_LENGTH = 60
2018-07-02 21:52:52 +00:00
while index * SHIFT_MINIMUM_LENGTH < 60:
minutes = int(index * SHIFT_MINIMUM_LENGTH)
minute_choices.append(minutes)
index += 1
def get_time_choices(date):
time_choices = []
for hour in range(0, 24):
for minute in minute_choices:
time_label = "{hour:02d}:{minutes:02d}".format(
2019-06-16 12:32:24 +00:00
hour=hour, minutes=minute
)
choice_value = "{} {}".format(date, time_label)
time_choices.append((choice_value, choice_value))
return time_choices
choices = []
current_date = camp.buildup.lower.date()
while current_date != camp.teardown.upper.date():
choices.append(
2019-06-16 12:32:24 +00:00
(current_date, get_time_choices(current_date.strftime("%Y-%m-%d")))
)
current_date += timezone.timedelta(days=1)
return choices
2018-07-02 21:52:52 +00:00
class ShiftForm(forms.ModelForm):
class Meta:
model = TeamShift
2019-06-16 12:32:24 +00:00
fields = ["from_datetime", "to_datetime", "people_required"]
2018-07-02 21:52:52 +00:00
def __init__(self, instance=None, **kwargs):
2019-06-16 12:32:24 +00:00
camp = kwargs.pop("camp")
super().__init__(instance=instance, **kwargs)
2019-06-16 12:32:24 +00:00
self.fields["from_datetime"].widget = forms.Select(choices=date_choices(camp))
self.fields["to_datetime"].widget = forms.Select(choices=date_choices(camp))
if instance:
current_tz = timezone.get_current_timezone()
2019-06-16 12:32:24 +00:00
lower = instance.shift_range.lower.astimezone(current_tz).strftime(
"%Y-%m-%d %H:%M"
)
upper = instance.shift_range.upper.astimezone(current_tz).strftime(
"%Y-%m-%d %H:%M"
)
self.fields["from_datetime"].initial = lower
self.fields["to_datetime"].initial = upper
from_datetime = forms.DateTimeField()
to_datetime = forms.DateTimeField()
2018-07-02 21:52:52 +00:00
def _get_from_datetime(self):
current_timezone = timezone.get_current_timezone()
2019-06-16 12:32:24 +00:00
return self.cleaned_data["from_datetime"].astimezone(current_timezone)
def _get_to_datetime(self):
current_timezone = timezone.get_current_timezone()
2019-06-16 12:32:24 +00:00
return self.cleaned_data["to_datetime"].astimezone(current_timezone)
2018-07-02 21:52:52 +00:00
def clean(self):
self.lower = self._get_from_datetime()
self.upper = self._get_to_datetime()
if self.lower > self.upper:
2019-06-16 12:32:24 +00:00
raise forms.ValidationError("Start can not be after end.")
def save(self, commit=True):
# self has .lower and .upper from .clean()
self.instance.shift_range = DateTimeTZRange(self.lower, self.upper)
return super().save(commit=commit)
2018-07-02 21:52:52 +00:00
2018-07-02 21:52:52 +00:00
class ShiftCreateView(LoginRequiredMixin, CampViewMixin, CreateView):
model = TeamShift
2018-08-05 10:18:10 +00:00
template_name = "team_shift_form.html"
2018-07-02 21:52:52 +00:00
form_class = ShiftForm
active_menu = "shifts"
2018-07-02 21:52:52 +00:00
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
2019-06-16 12:32:24 +00:00
kwargs["camp"] = self.camp
return kwargs
2018-07-02 21:52:52 +00:00
def form_valid(self, form):
shift = form.save(commit=False)
2019-06-16 12:32:24 +00:00
shift.team = Team.objects.get(camp=self.camp, slug=self.kwargs["team_slug"])
2018-07-02 21:52:52 +00:00
return super().form_valid(form)
def get_success_url(self):
2019-06-16 12:32:24 +00:00
return reverse("teams:shifts", kwargs=self.kwargs)
2018-07-02 21:52:52 +00:00
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
2019-06-16 12:32:24 +00:00
context["team"] = Team.objects.get(
camp=self.camp, slug=self.kwargs["team_slug"]
)
return context
2018-07-02 21:52:52 +00:00
class ShiftUpdateView(LoginRequiredMixin, CampViewMixin, UpdateView):
model = TeamShift
2018-08-05 10:18:10 +00:00
template_name = "team_shift_form.html"
form_class = ShiftForm
active_menu = "shifts"
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
2019-06-16 12:32:24 +00:00
kwargs["camp"] = self.camp
return kwargs
def get_success_url(self):
2019-06-16 12:32:24 +00:00
self.kwargs.pop("pk")
return reverse("teams:shifts", kwargs=self.kwargs)
2018-07-02 21:52:52 +00:00
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
2019-06-16 12:32:24 +00:00
context["team"] = self.object.team
return context
class ShiftDeleteView(LoginRequiredMixin, CampViewMixin, DeleteView):
model = TeamShift
2018-08-05 10:18:10 +00:00
template_name = "team_shift_confirm_delete.html"
active_menu = "shifts"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
2019-06-16 12:32:24 +00:00
context["team"] = Team.objects.get(
camp=self.camp, slug=self.kwargs["team_slug"]
)
return context
def get_success_url(self):
2019-06-16 12:32:24 +00:00
self.kwargs.pop("pk")
return reverse("teams:shifts", kwargs=self.kwargs)
class MultipleShiftForm(forms.Form):
def __init__(self, instance=None, **kwargs):
2019-06-16 12:32:24 +00:00
camp = kwargs.pop("camp")
super().__init__(**kwargs)
2019-06-16 12:32:24 +00:00
self.fields["from_datetime"].widget = forms.Select(choices=date_choices(camp))
from_datetime = forms.DateTimeField()
2019-06-16 12:32:24 +00:00
number_of_shifts = forms.IntegerField(help_text="How many shifts?")
shift_length = forms.IntegerField(
help_text="How long should a shift be in minutes?"
)
people_required = forms.IntegerField()
class ShiftCreateMultipleView(LoginRequiredMixin, CampViewMixin, FormView):
2018-08-05 10:18:10 +00:00
template_name = "team_shift_form.html"
form_class = MultipleShiftForm
active_menu = "shifts"
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
2019-06-16 12:32:24 +00:00
kwargs["camp"] = self.camp
return kwargs
def form_valid(self, form):
2019-06-16 12:32:24 +00:00
team = Team.objects.get(camp=self.camp, slug=self.kwargs["team_slug"])
current_timezone = timezone.get_current_timezone()
2019-06-16 12:32:24 +00:00
start_datetime = form.cleaned_data["from_datetime"].astimezone(current_timezone)
number_of_shifts = form.cleaned_data["number_of_shifts"]
shift_length = form.cleaned_data["shift_length"]
people_required = form.cleaned_data["people_required"]
shifts = []
for index in range(number_of_shifts):
shift_range = DateTimeTZRange(
start_datetime,
start_datetime + timezone.timedelta(minutes=shift_length),
)
2019-06-16 12:32:24 +00:00
shifts.append(
TeamShift(
team=team, people_required=people_required, shift_range=shift_range
)
)
start_datetime += timezone.timedelta(minutes=shift_length)
TeamShift.objects.bulk_create(shifts)
return super().form_valid(form)
def get_success_url(self):
2019-06-16 12:32:24 +00:00
return reverse("teams:shifts", kwargs=self.kwargs)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
2019-06-16 12:32:24 +00:00
context["team"] = Team.objects.get(
camp=self.camp, slug=self.kwargs["team_slug"]
)
return context
2018-08-08 12:36:31 +00:00
class MemberTakesShift(LoginRequiredMixin, CampViewMixin, View):
2019-06-16 12:32:24 +00:00
http_methods = ["get"]
def get(self, request, **kwargs):
2019-06-16 12:32:24 +00:00
shift = TeamShift.objects.get(id=kwargs["pk"])
team = Team.objects.get(camp=self.camp, slug=kwargs["team_slug"])
team_member = TeamMember.objects.get(team=team, user=request.user)
overlapping_shifts = TeamShift.objects.filter(
team__camp=self.camp,
team_members__user=request.user,
2019-06-16 12:32:24 +00:00
shift_range__overlap=shift.shift_range,
)
if overlapping_shifts.exists():
2019-06-16 12:32:24 +00:00
template = Template(
"""You have shifts overlapping with the one you are trying to assign:<br/> <ul>
{% for shift in shifts %}
<li>{{ shift }}</li>
{% endfor %}
</ul>
2019-06-16 12:32:24 +00:00
"""
)
messages.error(
2019-06-16 12:32:24 +00:00
request, template.render(Context({"shifts": overlapping_shifts}))
)
else:
shift.team_members.add(team_member)
2019-06-16 12:32:24 +00:00
kwargs.pop("pk")
2019-06-16 12:32:24 +00:00
return HttpResponseRedirect(reverse("teams:shifts", kwargs=kwargs))
2018-08-08 12:36:31 +00:00
class MemberDropsShift(LoginRequiredMixin, CampViewMixin, View):
2019-06-16 12:32:24 +00:00
http_methods = ["get"]
2018-08-08 12:36:31 +00:00
def get(self, request, **kwargs):
2019-06-16 12:32:24 +00:00
shift = TeamShift.objects.get(id=kwargs["pk"])
team = Team.objects.get(camp=self.camp, slug=kwargs["team_slug"])
2018-08-08 12:36:31 +00:00
team_member = TeamMember.objects.get(team=team, user=request.user)
shift.team_members.remove(team_member)
2019-06-16 12:32:24 +00:00
kwargs.pop("pk")
2018-08-08 12:36:31 +00:00
2019-06-16 12:32:24 +00:00
return HttpResponseRedirect(reverse("teams:shifts", kwargs=kwargs))
class UserShifts(CampViewMixin, TemplateView):
2019-06-16 12:32:24 +00:00
template_name = "team_user_shifts.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
2019-06-16 12:32:24 +00:00
context["user_teams"] = self.request.user.teammember_set.filter(
team__camp=self.camp
)
context["user_shifts"] = TeamShift.objects.filter(
team__camp=self.camp, team_members__user=self.request.user
)
2019-06-16 12:32:24 +00:00
return context