run pre-commit --all-files, it's been a while since last time
This commit is contained in:
parent
a21bc1097c
commit
01687ea11a
|
@ -1,4 +1,5 @@
|
|||
from django import forms
|
||||
|
||||
from program.models import Event, Speaker
|
||||
|
||||
|
||||
|
@ -46,7 +47,7 @@ class AutoScheduleApplyForm(forms.Form):
|
|||
|
||||
|
||||
class EventScheduleForm(forms.Form):
|
||||
""" The EventSlots are added in the view and help_text is not visible, just define the field """
|
||||
"""The EventSlots are added in the view and help_text is not visible, just define the field"""
|
||||
|
||||
slot = forms.ChoiceField()
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
from camps.mixins import CampViewMixin
|
||||
from django.contrib.auth.mixins import UserPassesTestMixin
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.shortcuts import get_object_or_404
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
from economy.models import Pos
|
||||
from utils.mixins import RaisePermissionRequiredMixin
|
||||
|
||||
|
|
|
@ -395,7 +395,9 @@ urlpatterns = [
|
|||
include(
|
||||
[
|
||||
path(
|
||||
"", SpeakerDetailView.as_view(), name="speaker_detail",
|
||||
"",
|
||||
SpeakerDetailView.as_view(),
|
||||
name="speaker_detail",
|
||||
),
|
||||
path(
|
||||
"update/",
|
||||
|
@ -473,7 +475,11 @@ urlpatterns = [
|
|||
"<slug:slug>/",
|
||||
include(
|
||||
[
|
||||
path("", EventDetailView.as_view(), name="event_detail",),
|
||||
path(
|
||||
"",
|
||||
EventDetailView.as_view(),
|
||||
name="event_detail",
|
||||
),
|
||||
path(
|
||||
"update/",
|
||||
EventUpdateView.as_view(),
|
||||
|
@ -500,7 +506,11 @@ urlpatterns = [
|
|||
"autoscheduler/",
|
||||
include(
|
||||
[
|
||||
path("", AutoScheduleManageView.as_view(), name="autoschedule_manage",),
|
||||
path(
|
||||
"",
|
||||
AutoScheduleManageView.as_view(),
|
||||
name="autoschedule_manage",
|
||||
),
|
||||
path(
|
||||
"crashcourse/",
|
||||
AutoScheduleCrashCourseView.as_view(),
|
||||
|
@ -512,7 +522,9 @@ urlpatterns = [
|
|||
name="autoschedule_validate",
|
||||
),
|
||||
path(
|
||||
"diff/", AutoScheduleDiffView.as_view(), name="autoschedule_diff",
|
||||
"diff/",
|
||||
AutoScheduleDiffView.as_view(),
|
||||
name="autoschedule_diff",
|
||||
),
|
||||
path(
|
||||
"apply/",
|
||||
|
@ -539,7 +551,11 @@ urlpatterns = [
|
|||
name="approve_event_feedback",
|
||||
),
|
||||
# add recording url objects
|
||||
path("add_recording", AddRecordingView.as_view(), name="add_eventrecording",),
|
||||
path(
|
||||
"add_recording",
|
||||
AddRecordingView.as_view(),
|
||||
name="add_eventrecording",
|
||||
),
|
||||
# economy
|
||||
path(
|
||||
"economy/",
|
||||
|
@ -658,18 +674,34 @@ urlpatterns = [
|
|||
"pos/",
|
||||
include(
|
||||
[
|
||||
path("", PosListView.as_view(), name="pos_list",),
|
||||
path("create/", PosCreateView.as_view(), name="pos_create",),
|
||||
path(
|
||||
"",
|
||||
PosListView.as_view(),
|
||||
name="pos_list",
|
||||
),
|
||||
path(
|
||||
"create/",
|
||||
PosCreateView.as_view(),
|
||||
name="pos_create",
|
||||
),
|
||||
path(
|
||||
"<slug:pos_slug>/",
|
||||
include(
|
||||
[
|
||||
path("", PosDetailView.as_view(), name="pos_detail",),
|
||||
path(
|
||||
"update/", PosUpdateView.as_view(), name="pos_update",
|
||||
"",
|
||||
PosDetailView.as_view(),
|
||||
name="pos_detail",
|
||||
),
|
||||
path(
|
||||
"delete/", PosDeleteView.as_view(), name="pos_delete",
|
||||
"update/",
|
||||
PosUpdateView.as_view(),
|
||||
name="pos_update",
|
||||
),
|
||||
path(
|
||||
"delete/",
|
||||
PosDeleteView.as_view(),
|
||||
name="pos_delete",
|
||||
),
|
||||
path(
|
||||
"reports/",
|
||||
|
@ -731,14 +763,30 @@ urlpatterns = [
|
|||
"tokens/",
|
||||
include(
|
||||
[
|
||||
path("", TokenListView.as_view(), name="token_list",),
|
||||
path("create/", TokenCreateView.as_view(), name="token_create",),
|
||||
path("stats/", TokenStatsView.as_view(), name="token_stats",),
|
||||
path(
|
||||
"",
|
||||
TokenListView.as_view(),
|
||||
name="token_list",
|
||||
),
|
||||
path(
|
||||
"create/",
|
||||
TokenCreateView.as_view(),
|
||||
name="token_create",
|
||||
),
|
||||
path(
|
||||
"stats/",
|
||||
TokenStatsView.as_view(),
|
||||
name="token_stats",
|
||||
),
|
||||
path(
|
||||
"<int:pk>/",
|
||||
include(
|
||||
[
|
||||
path("", TokenDetailView.as_view(), name="token_detail",),
|
||||
path(
|
||||
"",
|
||||
TokenDetailView.as_view(),
|
||||
name="token_detail",
|
||||
),
|
||||
path(
|
||||
"update/",
|
||||
TokenUpdateView.as_view(),
|
||||
|
|
|
@ -1,22 +1,20 @@
|
|||
import logging
|
||||
|
||||
import requests
|
||||
from camps.mixins import CampViewMixin
|
||||
from django.conf import settings
|
||||
from django.http import Http404, HttpResponse
|
||||
from django.views.generic import TemplateView
|
||||
from facilities.models import (
|
||||
FacilityFeedback,
|
||||
)
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
from facilities.models import FacilityFeedback
|
||||
from teams.models import Team
|
||||
from utils.models import OutgoingEmail
|
||||
|
||||
from ..mixins import (
|
||||
RaisePermissionRequiredMixin,
|
||||
)
|
||||
from ..mixins import RaisePermissionRequiredMixin
|
||||
|
||||
logger = logging.getLogger("bornhack.%s" % __name__)
|
||||
|
||||
|
||||
class BackofficeIndexView(CampViewMixin, RaisePermissionRequiredMixin, TemplateView):
|
||||
"""
|
||||
The Backoffice index view only requires camps.backoffice_permission so we use RaisePermissionRequiredMixin directly
|
||||
|
@ -37,7 +35,14 @@ class BackofficeIndexView(CampViewMixin, RaisePermissionRequiredMixin, TemplateV
|
|||
)
|
||||
)
|
||||
)
|
||||
context["held_email_count"] = OutgoingEmail.objects.filter(hold=True, responsible_team__isnull=True).count() + OutgoingEmail.objects.filter(hold=True, responsible_team__camp=self.camp).count()
|
||||
context["held_email_count"] = (
|
||||
OutgoingEmail.objects.filter(
|
||||
hold=True, responsible_team__isnull=True
|
||||
).count()
|
||||
+ OutgoingEmail.objects.filter(
|
||||
hold=True, responsible_team__camp=self.camp
|
||||
).count()
|
||||
)
|
||||
return context
|
||||
|
||||
|
||||
|
@ -51,7 +56,7 @@ class BackofficeProxyView(CampViewMixin, RaisePermissionRequiredMixin, TemplateV
|
|||
template_name = "backoffice_proxy.html"
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
""" Perform the request and return the response if we have a slug """
|
||||
"""Perform the request and return the response if we have a slug"""
|
||||
# list available stuff if we have no slug
|
||||
if "proxy_slug" not in kwargs:
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
|
|
@ -1,24 +1,16 @@
|
|||
import logging
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
from django.contrib import messages
|
||||
from django.forms import modelformset_factory
|
||||
from django.shortcuts import redirect
|
||||
from django.urls import reverse
|
||||
from django.views.generic.edit import FormView
|
||||
from program.models import (
|
||||
Event,
|
||||
EventFeedback,
|
||||
Url,
|
||||
UrlType,
|
||||
)
|
||||
|
||||
from ..forms import (
|
||||
AddRecordingForm,
|
||||
)
|
||||
from ..mixins import (
|
||||
ContentTeamPermissionMixin,
|
||||
)
|
||||
from camps.mixins import CampViewMixin
|
||||
from program.models import Event, EventFeedback, Url, UrlType
|
||||
|
||||
from ..forms import AddRecordingForm
|
||||
from ..mixins import ContentTeamPermissionMixin
|
||||
|
||||
logger = logging.getLogger("bornhack.%s" % __name__)
|
||||
|
||||
|
@ -84,9 +76,7 @@ class AddRecordingView(CampViewMixin, ContentTeamPermissionMixin, FormView):
|
|||
super().setup(*args, **kwargs)
|
||||
self.queryset = Event.objects.filter(
|
||||
track__camp=self.camp, video_recording=True
|
||||
).exclude(
|
||||
urls__url_type__name="Recording"
|
||||
)
|
||||
).exclude(urls__url_type__name="Recording")
|
||||
|
||||
self.form_class = modelformset_factory(
|
||||
Event,
|
||||
|
@ -113,19 +103,17 @@ class AddRecordingView(CampViewMixin, ContentTeamPermissionMixin, FormView):
|
|||
form.save()
|
||||
|
||||
for event_data in form.cleaned_data:
|
||||
if event_data['recording_url']:
|
||||
url = event_data['recording_url']
|
||||
if not event_data['id'].urls.filter(url=url).exists():
|
||||
if event_data["recording_url"]:
|
||||
url = event_data["recording_url"]
|
||||
if not event_data["id"].urls.filter(url=url).exists():
|
||||
recording_url = Url()
|
||||
recording_url.event = event_data['id']
|
||||
recording_url.event = event_data["id"]
|
||||
recording_url.url = url
|
||||
recording_url.url_type = UrlType.objects.get(name="Recording")
|
||||
recording_url.save()
|
||||
|
||||
if form.changed_objects:
|
||||
messages.success(
|
||||
self.request, f"Updated {len(form.changed_objects)} Event"
|
||||
)
|
||||
messages.success(self.request, f"Updated {len(form.changed_objects)} Event")
|
||||
return redirect(self.get_success_url())
|
||||
|
||||
def get_success_url(self, *args, **kwargs):
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import logging
|
||||
import os
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.models import User
|
||||
|
@ -12,18 +11,12 @@ from django.urls import reverse
|
|||
from django.utils import timezone
|
||||
from django.views.generic import DetailView, ListView
|
||||
from django.views.generic.edit import CreateView, DeleteView, UpdateView
|
||||
from economy.models import (
|
||||
Chain,
|
||||
Credebtor,
|
||||
Expense,
|
||||
Reimbursement,
|
||||
Revenue,
|
||||
)
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
from economy.models import Chain, Credebtor, Expense, Reimbursement, Revenue
|
||||
from teams.models import Team
|
||||
|
||||
from ..mixins import (
|
||||
EconomyTeamPermissionMixin,
|
||||
)
|
||||
from ..mixins import EconomyTeamPermissionMixin
|
||||
|
||||
logger = logging.getLogger("bornhack.%s" % __name__)
|
||||
|
||||
|
@ -245,7 +238,7 @@ class ReimbursementCreateView(CampViewMixin, EconomyTeamPermissionMixin, CreateV
|
|||
fields = ["notes", "paid"]
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
""" Get the user from kwargs """
|
||||
"""Get the user from kwargs"""
|
||||
self.reimbursement_user = get_object_or_404(User, pk=kwargs["user_id"])
|
||||
|
||||
# get response now so we have self.camp available below
|
||||
|
@ -448,5 +441,3 @@ class RevenueDetailView(CampViewMixin, EconomyTeamPermissionMixin, UpdateView):
|
|||
return redirect(
|
||||
reverse("backoffice:revenue_list", kwargs={"camp_slug": self.camp.slug})
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import logging
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.core.exceptions import PermissionDenied
|
||||
|
@ -9,19 +8,18 @@ from django.shortcuts import get_object_or_404, redirect
|
|||
from django.urls import reverse
|
||||
from django.views.generic import DetailView, ListView
|
||||
from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView
|
||||
from leaflet.forms.widgets import LeafletWidget
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
from facilities.models import (
|
||||
Facility,
|
||||
FacilityFeedback,
|
||||
FacilityOpeningHours,
|
||||
FacilityType,
|
||||
)
|
||||
from leaflet.forms.widgets import LeafletWidget
|
||||
from teams.models import Team
|
||||
|
||||
from ..mixins import (
|
||||
OrgaTeamPermissionMixin,
|
||||
RaisePermissionRequiredMixin,
|
||||
)
|
||||
from ..mixins import OrgaTeamPermissionMixin, RaisePermissionRequiredMixin
|
||||
|
||||
logger = logging.getLogger("bornhack.%s" % __name__)
|
||||
|
||||
|
@ -320,5 +318,3 @@ class FacilityOpeningHoursDeleteView(
|
|||
"backoffice:facility_detail",
|
||||
kwargs={"camp_slug": self.camp.slug, "facility_uuid": self.facility.pk},
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import logging
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.models import User
|
||||
from django.db.models import Count, Q
|
||||
|
@ -8,11 +7,11 @@ from django.shortcuts import redirect
|
|||
from django.urls import reverse
|
||||
from django.views.generic import DetailView, ListView
|
||||
from django.views.generic.edit import CreateView, DeleteView, UpdateView
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
from tokens.models import Token, TokenFind
|
||||
|
||||
from ..mixins import (
|
||||
RaisePermissionRequiredMixin,
|
||||
)
|
||||
from ..mixins import RaisePermissionRequiredMixin
|
||||
|
||||
logger = logging.getLogger("bornhack.%s" % __name__)
|
||||
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
import logging
|
||||
from itertools import chain
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.views.generic import ListView, TemplateView
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
from shop.models import Order, OrderProductRelation
|
||||
from tickets.models import DiscountTicket, ShopTicket, SponsorTicket, TicketType
|
||||
|
||||
from ..mixins import (
|
||||
InfoTeamPermissionMixin,
|
||||
)
|
||||
from ..mixins import InfoTeamPermissionMixin
|
||||
|
||||
logger = logging.getLogger("bornhack.%s" % __name__)
|
||||
|
||||
|
@ -140,7 +139,9 @@ class ScanTicketsView(
|
|||
messages.success(request, "Order #{} has been marked as paid!".format(order.id))
|
||||
|
||||
|
||||
class ShopTicketOverview(LoginRequiredMixin, InfoTeamPermissionMixin, CampViewMixin, ListView):
|
||||
class ShopTicketOverview(
|
||||
LoginRequiredMixin, InfoTeamPermissionMixin, CampViewMixin, ListView
|
||||
):
|
||||
model = ShopTicket
|
||||
template_name = "shop_ticket_overview.html"
|
||||
context_object_name = "shop_tickets"
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import logging
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
from django.contrib import messages
|
||||
from django.forms import modelformset_factory
|
||||
from django.shortcuts import redirect
|
||||
|
@ -8,13 +7,13 @@ from django.urls import reverse
|
|||
from django.utils import timezone
|
||||
from django.views.generic import ListView, TemplateView
|
||||
from django.views.generic.edit import FormView
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
from profiles.models import Profile
|
||||
from shop.models import OrderProductRelation
|
||||
from utils.models import OutgoingEmail
|
||||
|
||||
from ..mixins import (
|
||||
OrgaTeamPermissionMixin,
|
||||
)
|
||||
from ..mixins import OrgaTeamPermissionMixin
|
||||
|
||||
logger = logging.getLogger("bornhack.%s" % __name__)
|
||||
|
||||
|
@ -28,6 +27,7 @@ class ApproveNamesView(CampViewMixin, OrgaTeamPermissionMixin, ListView):
|
|||
public_credit_name=""
|
||||
)
|
||||
|
||||
|
||||
################################
|
||||
# MERCHANDISE VIEWS
|
||||
|
||||
|
|
|
@ -1,23 +1,17 @@
|
|||
import logging
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
from django.contrib import messages
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.shortcuts import redirect
|
||||
from django.urls import reverse
|
||||
from django.views.generic import DetailView, ListView
|
||||
from django.views.generic.edit import CreateView, DeleteView, UpdateView
|
||||
from economy.models import (
|
||||
Pos,
|
||||
PosReport,
|
||||
)
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
from economy.models import Pos, PosReport
|
||||
from teams.models import Team
|
||||
|
||||
from ..mixins import (
|
||||
OrgaTeamPermissionMixin,
|
||||
PosViewMixin,
|
||||
RaisePermissionRequiredMixin,
|
||||
)
|
||||
from ..mixins import OrgaTeamPermissionMixin, PosViewMixin, RaisePermissionRequiredMixin
|
||||
|
||||
logger = logging.getLogger("bornhack.%s" % __name__)
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import logging
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
|
@ -10,6 +9,8 @@ from django.urls import reverse
|
|||
from django.utils.safestring import mark_safe
|
||||
from django.views.generic import DetailView, ListView, TemplateView
|
||||
from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
from program.autoscheduler import AutoScheduler
|
||||
from program.mixins import AvailabilityMatrixViewMixin
|
||||
from program.models import (
|
||||
|
@ -30,9 +31,7 @@ from ..forms import (
|
|||
EventScheduleForm,
|
||||
SpeakerForm,
|
||||
)
|
||||
from ..mixins import (
|
||||
ContentTeamPermissionMixin,
|
||||
)
|
||||
from ..mixins import ContentTeamPermissionMixin
|
||||
|
||||
logger = logging.getLogger("bornhack.%s" % __name__)
|
||||
|
||||
|
@ -42,7 +41,7 @@ logger = logging.getLogger("bornhack.%s" % __name__)
|
|||
|
||||
|
||||
class PendingProposalsView(CampViewMixin, ContentTeamPermissionMixin, ListView):
|
||||
""" This convenience view shows a list of pending proposals """
|
||||
"""This convenience view shows a list of pending proposals"""
|
||||
|
||||
model = SpeakerProposal
|
||||
template_name = "pending_proposals.html"
|
||||
|
@ -88,7 +87,7 @@ class ProposalApproveBaseView(CampViewMixin, ContentTeamPermissionMixin, UpdateV
|
|||
|
||||
|
||||
class SpeakerProposalListView(CampViewMixin, ContentTeamPermissionMixin, ListView):
|
||||
""" This view permits Content Team members to list SpeakerProposals """
|
||||
"""This view permits Content Team members to list SpeakerProposals"""
|
||||
|
||||
model = SpeakerProposal
|
||||
template_name = "speaker_proposal_list.html"
|
||||
|
@ -105,7 +104,7 @@ class SpeakerProposalDetailView(
|
|||
ContentTeamPermissionMixin,
|
||||
DetailView,
|
||||
):
|
||||
""" This view permits Content Team members to see SpeakerProposal details """
|
||||
"""This view permits Content Team members to see SpeakerProposal details"""
|
||||
|
||||
model = SpeakerProposal
|
||||
template_name = "speaker_proposal_detail_backoffice.html"
|
||||
|
@ -118,7 +117,7 @@ class SpeakerProposalDetailView(
|
|||
|
||||
|
||||
class SpeakerProposalApproveRejectView(ProposalApproveBaseView):
|
||||
""" This view allows ContentTeam members to approve/reject SpeakerProposals """
|
||||
"""This view allows ContentTeam members to approve/reject SpeakerProposals"""
|
||||
|
||||
model = SpeakerProposal
|
||||
template_name = "speaker_proposal_approve_reject.html"
|
||||
|
@ -126,7 +125,7 @@ class SpeakerProposalApproveRejectView(ProposalApproveBaseView):
|
|||
|
||||
|
||||
class EventProposalListView(CampViewMixin, ContentTeamPermissionMixin, ListView):
|
||||
""" This view permits Content Team members to list EventProposals """
|
||||
"""This view permits Content Team members to list EventProposals"""
|
||||
|
||||
model = EventProposal
|
||||
template_name = "event_proposal_list.html"
|
||||
|
@ -147,7 +146,7 @@ class EventProposalListView(CampViewMixin, ContentTeamPermissionMixin, ListView)
|
|||
|
||||
|
||||
class EventProposalDetailView(CampViewMixin, ContentTeamPermissionMixin, DetailView):
|
||||
""" This view permits Content Team members to see EventProposal details """
|
||||
"""This view permits Content Team members to see EventProposal details"""
|
||||
|
||||
model = EventProposal
|
||||
template_name = "event_proposal_detail_backoffice.html"
|
||||
|
@ -155,7 +154,7 @@ class EventProposalDetailView(CampViewMixin, ContentTeamPermissionMixin, DetailV
|
|||
|
||||
|
||||
class EventProposalApproveRejectView(ProposalApproveBaseView):
|
||||
""" This view allows ContentTeam members to approve/reject EventProposals """
|
||||
"""This view allows ContentTeam members to approve/reject EventProposals"""
|
||||
|
||||
model = EventProposal
|
||||
template_name = "event_proposal_approve_reject.html"
|
||||
|
@ -167,7 +166,7 @@ class EventProposalApproveRejectView(ProposalApproveBaseView):
|
|||
|
||||
|
||||
class SpeakerListView(CampViewMixin, ContentTeamPermissionMixin, ListView):
|
||||
""" This view is used by the Content Team to see Speaker objects. """
|
||||
"""This view is used by the Content Team to see Speaker objects."""
|
||||
|
||||
model = Speaker
|
||||
template_name = "speaker_list_backoffice.html"
|
||||
|
@ -186,7 +185,7 @@ class SpeakerListView(CampViewMixin, ContentTeamPermissionMixin, ListView):
|
|||
class SpeakerDetailView(
|
||||
AvailabilityMatrixViewMixin, ContentTeamPermissionMixin, DetailView
|
||||
):
|
||||
""" This view is used by the Content Team to see details for Speaker objects """
|
||||
"""This view is used by the Content Team to see details for Speaker objects"""
|
||||
|
||||
model = Speaker
|
||||
template_name = "speaker_detail_backoffice.html"
|
||||
|
@ -202,20 +201,20 @@ class SpeakerDetailView(
|
|||
class SpeakerUpdateView(
|
||||
AvailabilityMatrixViewMixin, ContentTeamPermissionMixin, UpdateView
|
||||
):
|
||||
""" This view is used by the Content Team to update Speaker objects """
|
||||
"""This view is used by the Content Team to update Speaker objects"""
|
||||
|
||||
model = Speaker
|
||||
template_name = "speaker_update.html"
|
||||
form_class = SpeakerForm
|
||||
|
||||
def get_form_kwargs(self):
|
||||
""" Set camp for the form """
|
||||
"""Set camp for the form"""
|
||||
kwargs = super().get_form_kwargs()
|
||||
kwargs.update({"camp": self.camp})
|
||||
return kwargs
|
||||
|
||||
def form_valid(self, form):
|
||||
""" Save object and availability """
|
||||
"""Save object and availability"""
|
||||
speaker = form.save()
|
||||
save_speaker_availability(form, obj=speaker)
|
||||
messages.success(self.request, "Speaker has been updated")
|
||||
|
@ -228,7 +227,7 @@ class SpeakerUpdateView(
|
|||
|
||||
|
||||
class SpeakerDeleteView(CampViewMixin, ContentTeamPermissionMixin, DeleteView):
|
||||
""" This view is used by the Content Team to delete Speaker objects """
|
||||
"""This view is used by the Content Team to delete Speaker objects"""
|
||||
|
||||
model = Speaker
|
||||
template_name = "speaker_delete.html"
|
||||
|
@ -252,7 +251,7 @@ class SpeakerDeleteView(CampViewMixin, ContentTeamPermissionMixin, DeleteView):
|
|||
|
||||
|
||||
class EventTypeListView(CampViewMixin, ContentTeamPermissionMixin, ListView):
|
||||
""" This view is used by the Content Team to list EventTypes """
|
||||
"""This view is used by the Content Team to list EventTypes"""
|
||||
|
||||
model = EventType
|
||||
template_name = "event_type_list.html"
|
||||
|
@ -282,7 +281,7 @@ class EventTypeListView(CampViewMixin, ContentTeamPermissionMixin, ListView):
|
|||
|
||||
|
||||
class EventTypeDetailView(CampViewMixin, ContentTeamPermissionMixin, DetailView):
|
||||
""" This view is used by the Content Team to see details for EventTypes """
|
||||
"""This view is used by the Content Team to see details for EventTypes"""
|
||||
|
||||
model = EventType
|
||||
template_name = "event_type_detail.html"
|
||||
|
@ -306,7 +305,7 @@ class EventTypeDetailView(CampViewMixin, ContentTeamPermissionMixin, DetailView)
|
|||
|
||||
|
||||
class EventLocationListView(CampViewMixin, ContentTeamPermissionMixin, ListView):
|
||||
""" This view is used by the Content Team to list EventLocation objects. """
|
||||
"""This view is used by the Content Team to list EventLocation objects."""
|
||||
|
||||
model = EventLocation
|
||||
template_name = "event_location_list.html"
|
||||
|
@ -319,7 +318,7 @@ class EventLocationListView(CampViewMixin, ContentTeamPermissionMixin, ListView)
|
|||
|
||||
|
||||
class EventLocationDetailView(CampViewMixin, ContentTeamPermissionMixin, DetailView):
|
||||
""" This view is used by the Content Team to see details for EventLocation objects """
|
||||
"""This view is used by the Content Team to see details for EventLocation objects"""
|
||||
|
||||
model = EventLocation
|
||||
template_name = "event_location_detail.html"
|
||||
|
@ -334,7 +333,7 @@ class EventLocationDetailView(CampViewMixin, ContentTeamPermissionMixin, DetailV
|
|||
|
||||
|
||||
class EventLocationCreateView(CampViewMixin, ContentTeamPermissionMixin, CreateView):
|
||||
""" This view is used by the Content Team to create EventLocation objects """
|
||||
"""This view is used by the Content Team to create EventLocation objects"""
|
||||
|
||||
model = EventLocation
|
||||
fields = ["name", "icon", "capacity", "conflicts"]
|
||||
|
@ -362,7 +361,7 @@ class EventLocationCreateView(CampViewMixin, ContentTeamPermissionMixin, CreateV
|
|||
|
||||
|
||||
class EventLocationUpdateView(CampViewMixin, ContentTeamPermissionMixin, UpdateView):
|
||||
""" This view is used by the Content Team to update EventLocation objects """
|
||||
"""This view is used by the Content Team to update EventLocation objects"""
|
||||
|
||||
model = EventLocation
|
||||
fields = ["name", "icon", "capacity", "conflicts"]
|
||||
|
@ -386,7 +385,7 @@ class EventLocationUpdateView(CampViewMixin, ContentTeamPermissionMixin, UpdateV
|
|||
|
||||
|
||||
class EventLocationDeleteView(CampViewMixin, ContentTeamPermissionMixin, DeleteView):
|
||||
""" This view is used by the Content Team to delete EventLocation objects """
|
||||
"""This view is used by the Content Team to delete EventLocation objects"""
|
||||
|
||||
model = EventLocation
|
||||
template_name = "event_location_delete.html"
|
||||
|
@ -414,7 +413,7 @@ class EventLocationDeleteView(CampViewMixin, ContentTeamPermissionMixin, DeleteV
|
|||
|
||||
|
||||
class EventListView(CampViewMixin, ContentTeamPermissionMixin, ListView):
|
||||
""" This view is used by the Content Team to see Event objects. """
|
||||
"""This view is used by the Content Team to see Event objects."""
|
||||
|
||||
model = Event
|
||||
template_name = "event_list_backoffice.html"
|
||||
|
@ -431,14 +430,14 @@ class EventListView(CampViewMixin, ContentTeamPermissionMixin, ListView):
|
|||
|
||||
|
||||
class EventDetailView(CampViewMixin, ContentTeamPermissionMixin, DetailView):
|
||||
""" This view is used by the Content Team to see details for Event objects """
|
||||
"""This view is used by the Content Team to see details for Event objects"""
|
||||
|
||||
model = Event
|
||||
template_name = "event_detail_backoffice.html"
|
||||
|
||||
|
||||
class EventUpdateView(CampViewMixin, ContentTeamPermissionMixin, UpdateView):
|
||||
""" This view is used by the Content Team to update Event objects """
|
||||
"""This view is used by the Content Team to update Event objects"""
|
||||
|
||||
model = Event
|
||||
fields = [
|
||||
|
@ -460,7 +459,7 @@ class EventUpdateView(CampViewMixin, ContentTeamPermissionMixin, UpdateView):
|
|||
|
||||
|
||||
class EventDeleteView(CampViewMixin, ContentTeamPermissionMixin, DeleteView):
|
||||
""" This view is used by the Content Team to delete Event objects """
|
||||
"""This view is used by the Content Team to delete Event objects"""
|
||||
|
||||
model = Event
|
||||
template_name = "event_delete.html"
|
||||
|
@ -721,7 +720,7 @@ class EventSessionDeleteView(CampViewMixin, ContentTeamPermissionMixin, DeleteVi
|
|||
context_object_name = "session"
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
""" Show a warning if we have something scheduled in this EventSession """
|
||||
"""Show a warning if we have something scheduled in this EventSession"""
|
||||
if self.get_object().event_slots.filter(event__isnull=False).exists():
|
||||
messages.warning(
|
||||
self.request,
|
||||
|
@ -749,7 +748,7 @@ class EventSessionDeleteView(CampViewMixin, ContentTeamPermissionMixin, DeleteVi
|
|||
|
||||
|
||||
class EventSlotListView(CampViewMixin, ContentTeamPermissionMixin, ListView):
|
||||
""" This view is used by the Content Team to see EventSlot objects. """
|
||||
"""This view is used by the Content Team to see EventSlot objects."""
|
||||
|
||||
model = EventSlot
|
||||
template_name = "event_slot_list.html"
|
||||
|
@ -766,7 +765,7 @@ class EventSlotListView(CampViewMixin, ContentTeamPermissionMixin, ListView):
|
|||
|
||||
|
||||
class EventSlotDetailView(CampViewMixin, ContentTeamPermissionMixin, DetailView):
|
||||
""" This view is used by the Content Team to see details for EventSlot objects """
|
||||
"""This view is used by the Content Team to see details for EventSlot objects"""
|
||||
|
||||
model = EventSlot
|
||||
template_name = "event_slot_detail.html"
|
||||
|
@ -774,7 +773,7 @@ class EventSlotDetailView(CampViewMixin, ContentTeamPermissionMixin, DetailView)
|
|||
|
||||
|
||||
class EventSlotUnscheduleView(CampViewMixin, ContentTeamPermissionMixin, UpdateView):
|
||||
""" This view is used by the Content Team to remove an Event from the schedule/EventSlot """
|
||||
"""This view is used by the Content Team to remove an Event from the schedule/EventSlot"""
|
||||
|
||||
model = EventSlot
|
||||
template_name = "event_slot_unschedule.html"
|
||||
|
@ -802,7 +801,7 @@ class EventSlotUnscheduleView(CampViewMixin, ContentTeamPermissionMixin, UpdateV
|
|||
|
||||
|
||||
class AutoScheduleManageView(CampViewMixin, ContentTeamPermissionMixin, TemplateView):
|
||||
""" Just an index type view with links to the various actions """
|
||||
"""Just an index type view with links to the various actions"""
|
||||
|
||||
template_name = "autoschedule_index.html"
|
||||
|
||||
|
@ -810,7 +809,7 @@ class AutoScheduleManageView(CampViewMixin, ContentTeamPermissionMixin, Template
|
|||
class AutoScheduleCrashCourseView(
|
||||
CampViewMixin, ContentTeamPermissionMixin, TemplateView
|
||||
):
|
||||
""" A short crash course on the autoscheduler """
|
||||
"""A short crash course on the autoscheduler"""
|
||||
|
||||
template_name = "autoschedule_crash_course.html"
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from django.db import models
|
||||
|
||||
from utils.models import CampRelatedModel
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from camps.mixins import CampViewMixin
|
||||
from django.views.generic import ListView
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
|
||||
from .models import ProductCategory
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from channels.auth import AuthMiddlewareStack
|
||||
from channels.routing import ProtocolTypeRouter, URLRouter
|
||||
from django.conf.urls import url
|
||||
|
||||
from program.consumers import ScheduleConsumer
|
||||
|
||||
application = ProtocolTypeRouter(
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
from camps.models import Camp
|
||||
from graphene import ObjectType, Schema, relay
|
||||
from graphene_django import DjangoObjectType
|
||||
from graphene_django.filter import DjangoFilterConnectionField
|
||||
|
||||
from camps.models import Camp
|
||||
from program.schema import ProgramQuery
|
||||
|
||||
|
||||
|
|
|
@ -203,4 +203,4 @@ DATA_UPLOAD_MAX_NUMBER_FIELDS = 5000
|
|||
ACCOUNT_SIGNUP_FORM_CLASS = "bornhack.forms.AllAuthSignupCaptchaForm"
|
||||
|
||||
# django 3.2 https://docs.djangoproject.com/en/3.2/releases/3.2/#customizing-type-of-auto-created-primary-keys
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
from allauth.account.views import LoginView, LogoutView
|
||||
from bar.views import MenuView
|
||||
from camps.views import CampDetailView, CampListView, CampRedirectView
|
||||
from django.conf import settings
|
||||
from django.conf.urls import include
|
||||
from django.contrib import admin
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.urls import path
|
||||
from django.views.generic import TemplateView
|
||||
|
||||
from bar.views import MenuView
|
||||
from camps.views import CampDetailView, CampListView, CampRedirectView
|
||||
from feedback.views import FeedbackCreate
|
||||
from info.views import CampInfoView
|
||||
from people.views import PeopleView
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from camps.models import Camp
|
||||
from django.shortcuts import get_object_or_404
|
||||
|
||||
from camps.models import Camp
|
||||
|
||||
|
||||
class CampViewMixin:
|
||||
"""
|
||||
|
|
|
@ -8,6 +8,7 @@ from django.db import models
|
|||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from psycopg2.extras import DateTimeTZRange
|
||||
|
||||
from utils.models import CreatedUpdatedModel, UUIDModel
|
||||
|
||||
logger = logging.getLogger("bornhack.%s" % __name__)
|
||||
|
@ -135,7 +136,7 @@ class Camp(CreatedUpdatedModel, UUIDModel):
|
|||
return reverse("camp_detail", kwargs={"camp_slug": self.slug})
|
||||
|
||||
def clean(self):
|
||||
""" Make sure the dates make sense - meaning no overlaps and buildup before camp before teardown """
|
||||
"""Make sure the dates make sense - meaning no overlaps and buildup before camp before teardown"""
|
||||
errors = []
|
||||
# check for overlaps buildup vs. camp
|
||||
if self.buildup.upper > self.camp.lower:
|
||||
|
@ -258,7 +259,7 @@ class Camp(CreatedUpdatedModel, UUIDModel):
|
|||
|
||||
@property
|
||||
def event_types(self):
|
||||
""" Return all event types with at least one event in this camp """
|
||||
"""Return all event types with at least one event in this camp"""
|
||||
EventType = apps.get_model("program", "EventType")
|
||||
return EventType.objects.filter(
|
||||
events__isnull=False, event__track__camp=self
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
from camps.models import Camp
|
||||
from django.contrib import admin
|
||||
from django.utils import timezone
|
||||
|
||||
from camps.models import Camp
|
||||
|
||||
|
||||
def get_current_camp():
|
||||
try:
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import os
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from teams.models import Team
|
||||
from utils.email import add_outgoing_email
|
||||
|
||||
|
|
|
@ -53,7 +53,9 @@ class Migration(migrations.Migration):
|
|||
),
|
||||
),
|
||||
],
|
||||
options={"ordering": ["name"],},
|
||||
options={
|
||||
"ordering": ["name"],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="PosReport",
|
||||
|
@ -279,6 +281,8 @@ class Migration(migrations.Migration):
|
|||
),
|
||||
),
|
||||
],
|
||||
options={"abstract": False,},
|
||||
options={
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
]
|
||||
|
|
|
@ -11,6 +11,7 @@ class Migration(migrations.Migration):
|
|||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name="posreport", options={"ordering": ["date", "pos"]},
|
||||
name="posreport",
|
||||
options={"ordering": ["date", "pos"]},
|
||||
),
|
||||
]
|
||||
|
|
|
@ -4,6 +4,7 @@ from django.contrib import messages
|
|||
from django.core.exceptions import ValidationError
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
|
||||
from utils.models import CampRelatedModel, CreatedUpdatedModel, UUIDModel
|
||||
from utils.slugs import unique_slugify
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import os
|
||||
|
||||
import magic
|
||||
from camps.mixins import CampViewMixin
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
|
@ -16,6 +15,8 @@ from django.views.generic import (
|
|||
TemplateView,
|
||||
UpdateView,
|
||||
)
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
from teams.models import Team
|
||||
from utils.email import add_outgoing_email
|
||||
from utils.mixins import RaisePermissionRequiredMixin
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from django.db import models
|
||||
|
||||
from teams.models import Team
|
||||
from utils.models import CreatedUpdatedModel
|
||||
|
||||
|
|
|
@ -42,7 +42,9 @@ class Migration(migrations.Migration):
|
|||
models.TextField(help_text="Description of this facility"),
|
||||
),
|
||||
],
|
||||
options={"abstract": False,},
|
||||
options={
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="FacilityQuickFeedback",
|
||||
|
@ -124,7 +126,9 @@ class Migration(migrations.Migration):
|
|||
),
|
||||
),
|
||||
],
|
||||
options={"unique_together": {("slug", "responsible_team")},},
|
||||
options={
|
||||
"unique_together": {("slug", "responsible_team")},
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="FacilityFeedback",
|
||||
|
@ -202,7 +206,9 @@ class Migration(migrations.Migration):
|
|||
),
|
||||
),
|
||||
],
|
||||
options={"abstract": False,},
|
||||
options={
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="facility",
|
||||
|
|
|
@ -50,6 +50,8 @@ class Migration(migrations.Migration):
|
|||
),
|
||||
),
|
||||
],
|
||||
options={"abstract": False,},
|
||||
options={
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
]
|
||||
|
|
|
@ -14,7 +14,8 @@ class Migration(migrations.Migration):
|
|||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name="facilityopeninghours", options={"ordering": ["when"]},
|
||||
name="facilityopeninghours",
|
||||
options={"ordering": ["when"]},
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="facility",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from camps.mixins import CampViewMixin
|
||||
from django.shortcuts import get_object_or_404
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
|
||||
from .models import Facility, FacilityType
|
||||
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ from django.contrib.postgres.constraints import ExclusionConstraint
|
|||
from django.contrib.postgres.fields import DateTimeRangeField, RangeOperators
|
||||
from django.db import models
|
||||
from django.shortcuts import reverse
|
||||
|
||||
from maps.utils import LeafletMarkerChoices
|
||||
from utils.models import CampRelatedModel, UUIDModel
|
||||
from utils.slugs import unique_slugify
|
||||
|
@ -111,7 +112,8 @@ class Facility(CampRelatedModel, UUIDModel):
|
|||
)
|
||||
|
||||
name = models.CharField(
|
||||
max_length=100, help_text="Name or description of this facility",
|
||||
max_length=100,
|
||||
help_text="Name or description of this facility",
|
||||
)
|
||||
|
||||
description = models.TextField(help_text="Description of this facility")
|
||||
|
@ -250,7 +252,8 @@ class FacilityOpeningHours(CampRelatedModel):
|
|||
)
|
||||
|
||||
when = DateTimeRangeField(
|
||||
db_index=True, help_text="The period when this facility is open.",
|
||||
db_index=True,
|
||||
help_text="The period when this facility is open.",
|
||||
)
|
||||
|
||||
notes = models.TextField(
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
from camps.mixins import CampViewMixin
|
||||
from django import forms
|
||||
from django.contrib import messages
|
||||
from django.shortcuts import redirect
|
||||
|
@ -6,6 +5,8 @@ from django.urls import reverse
|
|||
from django.views.generic import DetailView, ListView
|
||||
from django.views.generic.edit import CreateView
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
|
||||
from .mixins import FacilityTypeViewMixin, FacilityViewMixin
|
||||
from .models import Facility, FacilityFeedback, FacilityType
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from django.db import models
|
||||
|
||||
from utils.models import CampRelatedModel, UUIDModel
|
||||
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
from camps.mixins import CampViewMixin
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.urls import reverse
|
||||
from django.views.generic import CreateView
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
from tokens.models import Token
|
||||
|
||||
from .models import Feedback
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import reversion
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models
|
||||
|
||||
from utils.models import CampRelatedModel
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from camps.mixins import CampViewMixin
|
||||
from django.views.generic import ListView
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
|
||||
from .models import InfoCategory
|
||||
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import irc3
|
|||
from asgiref.sync import sync_to_async
|
||||
from django.conf import settings
|
||||
from django.utils import timezone
|
||||
|
||||
from ircbot.models import OutgoingIrcMessage
|
||||
from teams.models import Team, TeamMember
|
||||
from teams.utils import get_team_from_irc_channel
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from django.core.exceptions import ValidationError
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
|
||||
from utils.models import CreatedUpdatedModel
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.utils.text import slugify
|
||||
|
||||
from utils.models import CreatedUpdatedModel
|
||||
from utils.slugs import unique_slugify
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from camps.models import Camp
|
||||
from django.views.generic import ListView
|
||||
|
||||
from camps.models import Camp
|
||||
|
||||
|
||||
class PeopleView(ListView):
|
||||
template_name = "people.html"
|
||||
|
|
|
@ -82,6 +82,8 @@ class Migration(migrations.Migration):
|
|||
),
|
||||
),
|
||||
],
|
||||
options={"unique_together": {("camp", "number")},},
|
||||
options={
|
||||
"unique_together": {("camp", "number")},
|
||||
},
|
||||
),
|
||||
]
|
||||
|
|
|
@ -3,6 +3,7 @@ import logging
|
|||
from django.contrib.auth.models import User
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models
|
||||
|
||||
from utils.models import CampRelatedModel
|
||||
|
||||
from .dectutils import DectUtils
|
||||
|
@ -20,7 +21,9 @@ class DectRegistration(CampRelatedModel):
|
|||
unique_together = [("camp", "number")]
|
||||
|
||||
camp = models.ForeignKey(
|
||||
"camps.Camp", related_name="dect_registrations", on_delete=models.PROTECT,
|
||||
"camps.Camp",
|
||||
related_name="dect_registrations",
|
||||
on_delete=models.PROTECT,
|
||||
)
|
||||
|
||||
user = models.ForeignKey(
|
||||
|
@ -47,11 +50,14 @@ class DectRegistration(CampRelatedModel):
|
|||
)
|
||||
|
||||
activation_code = models.CharField(
|
||||
max_length=10, blank=True, help_text="The 10 digit numeric activation code",
|
||||
max_length=10,
|
||||
blank=True,
|
||||
help_text="The 10 digit numeric activation code",
|
||||
)
|
||||
|
||||
publish_in_phonebook = models.BooleanField(
|
||||
default=True, help_text="Check to list this registration in the phonebook",
|
||||
default=True,
|
||||
help_text="Check to list this registration in the phonebook",
|
||||
)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
|
|
|
@ -3,7 +3,6 @@ import logging
|
|||
import secrets
|
||||
import string
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.core.exceptions import ValidationError
|
||||
|
@ -13,6 +12,8 @@ from django.urls import reverse
|
|||
from django.utils import timezone
|
||||
from django.views.generic import CreateView, DeleteView, ListView, UpdateView
|
||||
from oauth2_provider.views.generic import ProtectedResourceView
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
from utils.mixins import RaisePermissionRequiredMixin, UserIsObjectOwnerMixin
|
||||
|
||||
from .mixins import DectRegistrationViewMixin
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from django.contrib.auth.models import User
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from utils.models import CreatedUpdatedModel, UUIDModel
|
||||
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ class ProgramConfig(AppConfig):
|
|||
name = "program"
|
||||
|
||||
def ready(self):
|
||||
from .models import Speaker, EventSession
|
||||
from .models import EventSession, Speaker
|
||||
from .signal_handlers import (
|
||||
check_speaker_event_camp_consistency,
|
||||
event_session_post_save,
|
||||
|
|
|
@ -25,7 +25,7 @@ class AutoScheduler:
|
|||
"""
|
||||
|
||||
def __init__(self, camp):
|
||||
""" Get EventTypes, EventSessions and Events, build autoslot and autoevent objects """
|
||||
"""Get EventTypes, EventSessions and Events, build autoslot and autoevent objects"""
|
||||
self.camp = camp
|
||||
|
||||
# Get all EventTypes which support autoscheduling
|
||||
|
@ -62,17 +62,17 @@ class AutoScheduler:
|
|||
self.autoevents, self.autoeventindex = self.get_autoevents(self.events)
|
||||
|
||||
def get_event_types(self):
|
||||
""" Return all EventTypes which support autoscheduling """
|
||||
"""Return all EventTypes which support autoscheduling"""
|
||||
return EventType.objects.filter(support_autoscheduling=True)
|
||||
|
||||
def get_event_sessions(self, event_types):
|
||||
""" Return all EventSessions for these EventTypes """
|
||||
"""Return all EventSessions for these EventTypes"""
|
||||
return self.camp.event_sessions.filter(
|
||||
event_type__in=event_types,
|
||||
).prefetch_related("event_type", "event_location")
|
||||
|
||||
def get_events(self, event_types):
|
||||
""" Return all Events that need scheduling """
|
||||
"""Return all Events that need scheduling"""
|
||||
# return all events for these event_types, but..
|
||||
return self.camp.events.filter(event_type__in=event_types).exclude(
|
||||
# exclude Events that have been sceduled already...
|
||||
|
@ -82,7 +82,7 @@ class AutoScheduler:
|
|||
)
|
||||
|
||||
def get_autoslots(self, event_sessions):
|
||||
""" Return a list of autoslots for all slots in all EventSessions """
|
||||
"""Return a list of autoslots for all slots in all EventSessions"""
|
||||
autoslots = []
|
||||
# loop over the sessions
|
||||
for session in event_sessions:
|
||||
|
@ -92,7 +92,7 @@ class AutoScheduler:
|
|||
return autoslots
|
||||
|
||||
def get_autoevents(self, events):
|
||||
""" Return a list of resources.Event objects, one for each Event """
|
||||
"""Return a list of resources.Event objects, one for each Event"""
|
||||
autoevents = []
|
||||
autoeventindex = {}
|
||||
eventindex = {}
|
||||
|
@ -197,10 +197,10 @@ class AutoScheduler:
|
|||
return autoevents, autoeventindex
|
||||
|
||||
def build_current_autoschedule(self):
|
||||
""" Build an autoschedule object based on the existing published schedule.
|
||||
"""Build an autoschedule object based on the existing published schedule.
|
||||
Returns an autoschedule, which is a list of conference_scheduler.resources.ScheduledItem
|
||||
objects, one for each scheduled Event. This function is useful for creating an "original
|
||||
schedule" to base a new similar schedule off of. """
|
||||
schedule" to base a new similar schedule off of."""
|
||||
|
||||
# loop over scheduled events and create a ScheduledItem object for each
|
||||
autoschedule = []
|
||||
|
@ -244,8 +244,8 @@ class AutoScheduler:
|
|||
return autoschedule
|
||||
|
||||
def calculate_autoschedule(self, original_schedule=None):
|
||||
""" Calculate autoschedule based on self.autoevents and self.autoslots,
|
||||
optionally using original_schedule to minimise changes """
|
||||
"""Calculate autoschedule based on self.autoevents and self.autoslots,
|
||||
optionally using original_schedule to minimise changes"""
|
||||
kwargs = {}
|
||||
kwargs["events"] = self.autoevents
|
||||
kwargs["slots"] = self.autoslots
|
||||
|
@ -264,8 +264,8 @@ class AutoScheduler:
|
|||
return autoschedule
|
||||
|
||||
def calculate_similar_autoschedule(self, original_schedule=None):
|
||||
""" Convenience method for creating similar schedules. If original_schedule
|
||||
is omitted the new schedule is based on the current schedule instead """
|
||||
"""Convenience method for creating similar schedules. If original_schedule
|
||||
is omitted the new schedule is based on the current schedule instead"""
|
||||
|
||||
if not original_schedule:
|
||||
# we do not have an original_schedule, use current EventInstances
|
||||
|
@ -277,7 +277,7 @@ class AutoScheduler:
|
|||
return autoschedule, diff
|
||||
|
||||
def apply(self, autoschedule):
|
||||
""" Apply an autoschedule by creating EventInstance objects to match it """
|
||||
"""Apply an autoschedule by creating EventInstance objects to match it"""
|
||||
|
||||
# "The Clean Slate protocol sir?" - delete any existing autoscheduled Events
|
||||
# TODO: investigate how this affects the FRAB XML export (for which we added a UUID on
|
||||
|
@ -320,7 +320,10 @@ class AutoScheduler:
|
|||
This method returns a dict of Event differences and Slot differences between
|
||||
the two schedules.
|
||||
"""
|
||||
slot_diff = scheduler.slot_schedule_difference(original_schedule, new_schedule,)
|
||||
slot_diff = scheduler.slot_schedule_difference(
|
||||
original_schedule,
|
||||
new_schedule,
|
||||
)
|
||||
|
||||
slot_output = []
|
||||
for item in slot_diff:
|
||||
|
@ -347,7 +350,8 @@ class AutoScheduler:
|
|||
|
||||
# then get a list of differences per event
|
||||
event_diff = scheduler.event_schedule_difference(
|
||||
original_schedule, new_schedule,
|
||||
original_schedule,
|
||||
new_schedule,
|
||||
)
|
||||
event_output = []
|
||||
# loop over the differences and build the dict
|
||||
|
@ -357,7 +361,11 @@ class AutoScheduler:
|
|||
except self.camp.events.DoesNotExist:
|
||||
event = item.event.name
|
||||
event_output.append(
|
||||
{"event": event, "old": {}, "new": {},}
|
||||
{
|
||||
"event": event,
|
||||
"old": {},
|
||||
"new": {},
|
||||
}
|
||||
)
|
||||
# do we have an old slot for this event?
|
||||
if item.old_slot:
|
||||
|
@ -376,7 +384,7 @@ class AutoScheduler:
|
|||
return {"event_diffs": event_output, "slot_diffs": slot_output}
|
||||
|
||||
def is_valid(self, autoschedule, return_violations=False):
|
||||
""" Check if a schedule is valid, optionally returning a list of violations if invalid """
|
||||
"""Check if a schedule is valid, optionally returning a list of violations if invalid"""
|
||||
valid = is_valid_schedule(
|
||||
autoschedule, slots=self.autoslots, events=self.autoevents
|
||||
)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from camps.models import Camp
|
||||
from channels.generic.websocket import JsonWebsocketConsumer
|
||||
|
||||
from camps.models import Camp
|
||||
|
||||
from .models import (
|
||||
Event,
|
||||
EventInstance,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import logging
|
||||
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
|
||||
from teams.models import Team
|
||||
from utils.email import add_outgoing_email
|
||||
|
||||
|
|
|
@ -33,7 +33,8 @@ class SpeakerProposalForm(forms.ModelForm):
|
|||
|
||||
# only show events from this camp
|
||||
self.fields["event_conflicts"].queryset = Event.objects.filter(
|
||||
track__camp=camp, event_type__support_speaker_event_conflicts=True,
|
||||
track__camp=camp,
|
||||
event_type__support_speaker_event_conflicts=True,
|
||||
)
|
||||
|
||||
if matrix:
|
||||
|
@ -265,9 +266,9 @@ class EventProposalForm(forms.ModelForm):
|
|||
]
|
||||
|
||||
def clean_duration(self):
|
||||
""" Make sure duration has been specified, and make sure it is not too long """
|
||||
"""Make sure duration has been specified, and make sure it is not too long"""
|
||||
if not self.cleaned_data["duration"]:
|
||||
raise forms.ValidationError(f"Please specify a duration.")
|
||||
raise forms.ValidationError("Please specify a duration.")
|
||||
if (
|
||||
self.event_type.event_duration_minutes
|
||||
and self.cleaned_data["duration"] > self.event_type.event_duration_minutes
|
||||
|
|
|
@ -2,10 +2,11 @@ import logging
|
|||
from datetime import timedelta
|
||||
from time import sleep
|
||||
|
||||
from camps.utils import get_current_camp
|
||||
from django.conf import settings
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.utils import timezone
|
||||
|
||||
from camps.utils import get_current_camp
|
||||
from ircbot.models import OutgoingIrcMessage
|
||||
from program.models import EventInstance
|
||||
|
||||
|
|
|
@ -2,9 +2,10 @@
|
|||
# Generated by Django 1.10.5 on 2017-02-18 11:43
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import program.models
|
||||
from django.db import migrations, models
|
||||
|
||||
import program.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
|
|
|
@ -5,10 +5,11 @@ from __future__ import unicode_literals
|
|||
import uuid
|
||||
|
||||
import django.db.models.deletion
|
||||
import program.models
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
import program.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
|
|
|
@ -5,10 +5,11 @@ from __future__ import unicode_literals
|
|||
import uuid
|
||||
|
||||
import django.db.models.deletion
|
||||
import program.models
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
import program.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
|
|
|
@ -2,9 +2,10 @@
|
|||
# Generated by Django 1.10.5 on 2017-03-14 19:12
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import program.models
|
||||
from django.db import migrations, models
|
||||
|
||||
import program.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
|
|
|
@ -2,9 +2,10 @@
|
|||
# Generated by Django 1.10.5 on 2017-03-15 23:04
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import program.models
|
||||
from django.db import migrations, models
|
||||
|
||||
import program.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ class Migration(migrations.Migration):
|
|||
),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name="eventfeedback", unique_together={("user", "event")},
|
||||
name="eventfeedback",
|
||||
unique_together={("user", "event")},
|
||||
),
|
||||
]
|
||||
|
|
|
@ -11,6 +11,8 @@ class Migration(migrations.Migration):
|
|||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name="eventfeedback", old_name="feedback", new_name="comment",
|
||||
model_name="eventfeedback",
|
||||
old_name="feedback",
|
||||
new_name="comment",
|
||||
),
|
||||
]
|
||||
|
|
|
@ -51,7 +51,9 @@ class Migration(migrations.Migration):
|
|||
),
|
||||
),
|
||||
],
|
||||
options={"ordering": ["when", "event_type", "event_location"],},
|
||||
options={
|
||||
"ordering": ["when", "event_type", "event_location"],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="EventSlot",
|
||||
|
@ -81,7 +83,9 @@ class Migration(migrations.Migration):
|
|||
),
|
||||
),
|
||||
],
|
||||
options={"ordering": ["when"],},
|
||||
options={
|
||||
"ordering": ["when"],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="SpeakerAvailability",
|
||||
|
@ -128,7 +132,9 @@ class Migration(migrations.Migration):
|
|||
("created", models.DateTimeField(auto_now_add=True)),
|
||||
("updated", models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
options={"abstract": False,},
|
||||
options={
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="SpeakerProposalAvailability",
|
||||
|
@ -175,7 +181,9 @@ class Migration(migrations.Migration):
|
|||
("created", models.DateTimeField(auto_now_add=True)),
|
||||
("updated", models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
options={"abstract": False,},
|
||||
options={
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="event",
|
||||
|
|
|
@ -32,13 +32,19 @@ class Migration(migrations.Migration):
|
|||
new_name="speaker_proposal",
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name="url", old_name="eventproposal", new_name="event_proposal",
|
||||
model_name="url",
|
||||
old_name="eventproposal",
|
||||
new_name="event_proposal",
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name="url", old_name="speakerproposal", new_name="speaker_proposal",
|
||||
model_name="url",
|
||||
old_name="speakerproposal",
|
||||
new_name="speaker_proposal",
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name="url", old_name="urltype", new_name="url_type",
|
||||
model_name="url",
|
||||
old_name="urltype",
|
||||
new_name="url_type",
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="event",
|
||||
|
|
|
@ -2,9 +2,10 @@
|
|||
|
||||
import django.contrib.postgres.constraints
|
||||
import django.db.models.deletion
|
||||
import utils.database
|
||||
from django.db import migrations, models
|
||||
|
||||
import utils.database
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
|
@ -13,13 +14,21 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(model_name="speakereventconflict", name="events",),
|
||||
migrations.RemoveField(model_name="speakereventconflict", name="speaker",),
|
||||
migrations.RemoveField(
|
||||
model_name="speakerproposaleventconflict", name="events",
|
||||
model_name="speakereventconflict",
|
||||
name="events",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="speakerproposaleventconflict", name="speaker_proposal",
|
||||
model_name="speakereventconflict",
|
||||
name="speaker",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="speakerproposaleventconflict",
|
||||
name="events",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="speakerproposaleventconflict",
|
||||
name="speaker_proposal",
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="eventtype",
|
||||
|
@ -110,6 +119,10 @@ class Migration(migrations.Migration):
|
|||
name="prevent_speaker_proposal_availability_adjacent_mergeable",
|
||||
),
|
||||
),
|
||||
migrations.DeleteModel(name="SpeakerEventConflict",),
|
||||
migrations.DeleteModel(name="SpeakerProposalEventConflict",),
|
||||
migrations.DeleteModel(
|
||||
name="SpeakerEventConflict",
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name="SpeakerProposalEventConflict",
|
||||
),
|
||||
]
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
from camps.mixins import CampViewMixin
|
||||
from django.contrib import messages
|
||||
from django.http import Http404
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.urls import reverse
|
||||
from django.views.generic.detail import SingleObjectMixin
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
from program.utils import (
|
||||
add_existing_availability_to_matrix,
|
||||
get_speaker_availability_form_matrix,
|
||||
|
@ -141,7 +142,9 @@ class EventFeedbackViewMixin(EventViewMixin):
|
|||
def setup(self, *args, **kwargs):
|
||||
super().setup(*args, **kwargs)
|
||||
self.event_feedback = get_object_or_404(
|
||||
models.EventFeedback, event=self.event, user=self.request.user,
|
||||
models.EventFeedback,
|
||||
event=self.event,
|
||||
user=self.request.user,
|
||||
)
|
||||
|
||||
def get_object(self):
|
||||
|
@ -157,7 +160,7 @@ class AvailabilityMatrixViewMixin(CampViewMixin):
|
|||
"""
|
||||
|
||||
def setup(self, *args, **kwargs):
|
||||
""" Get the availability matrix"""
|
||||
"""Get the availability matrix"""
|
||||
super().setup(*args, **kwargs)
|
||||
# do we have an Event or an EventProposal?
|
||||
if hasattr(self.get_object(), "events"):
|
||||
|
@ -177,13 +180,13 @@ class AvailabilityMatrixViewMixin(CampViewMixin):
|
|||
add_existing_availability_to_matrix(self.matrix, self.get_object())
|
||||
|
||||
def get_form_kwargs(self):
|
||||
""" Add the matrix to form kwargs, only used if the view has a form """
|
||||
"""Add the matrix to form kwargs, only used if the view has a form"""
|
||||
kwargs = super().get_form_kwargs()
|
||||
kwargs["matrix"] = self.matrix
|
||||
return kwargs
|
||||
|
||||
def get_initial(self, *args, **kwargs):
|
||||
""" Populate the speaker_availability checkboxes, only used if the view has a form """
|
||||
"""Populate the speaker_availability checkboxes, only used if the view has a form"""
|
||||
initial = super().get_initial(*args, **kwargs)
|
||||
|
||||
# add initial checkbox states
|
||||
|
@ -202,7 +205,7 @@ class AvailabilityMatrixViewMixin(CampViewMixin):
|
|||
return initial
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
""" Add the matrix to context """
|
||||
"""Add the matrix to context"""
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["matrix"] = self.matrix
|
||||
return context
|
||||
|
|
|
@ -18,6 +18,7 @@ from django.utils import timezone
|
|||
from django.utils.safestring import mark_safe
|
||||
from psycopg2.extras import DateTimeTZRange
|
||||
from taggit.managers import TaggableManager
|
||||
|
||||
from utils.database import CastToInteger
|
||||
from utils.models import (
|
||||
CampRelatedModel,
|
||||
|
@ -119,7 +120,7 @@ class Url(CampRelatedModel):
|
|||
return self.url
|
||||
|
||||
def clean_fk(self):
|
||||
""" Make sure we have exactly one FK """
|
||||
"""Make sure we have exactly one FK"""
|
||||
fks = 0
|
||||
if self.speaker_proposal:
|
||||
fks += 1
|
||||
|
@ -192,10 +193,10 @@ class Availability(CampRelatedModel, UUIDModel):
|
|||
|
||||
|
||||
class SpeakerProposalAvailability(Availability):
|
||||
""" Availability info for SpeakerProposal objects """
|
||||
"""Availability info for SpeakerProposal objects"""
|
||||
|
||||
class Meta:
|
||||
""" Add ExclusionConstraints preventing overlaps and adjacent ranges with same availability """
|
||||
"""Add ExclusionConstraints preventing overlaps and adjacent ranges with same availability"""
|
||||
|
||||
constraints = [
|
||||
# we do not want overlapping ranges
|
||||
|
@ -247,10 +248,10 @@ class SpeakerProposalAvailability(Availability):
|
|||
|
||||
|
||||
class SpeakerAvailability(Availability):
|
||||
""" Availability info for Speaker objects """
|
||||
"""Availability info for Speaker objects"""
|
||||
|
||||
class Meta:
|
||||
""" Add ExclusionConstraints preventing overlaps and adjacent ranges with same availability """
|
||||
"""Add ExclusionConstraints preventing overlaps and adjacent ranges with same availability"""
|
||||
|
||||
constraints = [
|
||||
# we do not want overlapping ranges
|
||||
|
@ -290,7 +291,9 @@ class SpeakerAvailability(Availability):
|
|||
def clean(self):
|
||||
# this should be an ExclusionConstraint but the boolean condition isn't conditioning :/
|
||||
if SpeakerAvailability.objects.filter(
|
||||
speaker=self.speaker, when__adjacent_to=self.when, available=self.available,
|
||||
speaker=self.speaker,
|
||||
when__adjacent_to=self.when,
|
||||
available=self.available,
|
||||
).exists():
|
||||
raise ValidationError(
|
||||
"An adjacent SpeakerAvailability object for this Speaker already exists with the same value for available, cannot save()"
|
||||
|
@ -359,7 +362,7 @@ class UserSubmittedModel(CampRelatedModel):
|
|||
|
||||
|
||||
class SpeakerProposal(UserSubmittedModel):
|
||||
""" A speaker proposal """
|
||||
"""A speaker proposal"""
|
||||
|
||||
camp = models.ForeignKey(
|
||||
"camps.Camp",
|
||||
|
@ -410,7 +413,7 @@ class SpeakerProposal(UserSubmittedModel):
|
|||
)
|
||||
|
||||
def mark_as_approved(self, request=None):
|
||||
""" Marks a SpeakerProposal as approved, including creating/updating the related Speaker object """
|
||||
"""Marks a SpeakerProposal as approved, including creating/updating the related Speaker object"""
|
||||
speaker_proposalmodel = apps.get_model("program", "SpeakerProposal")
|
||||
# create a Speaker if we don't have one
|
||||
if not hasattr(self, "speaker"):
|
||||
|
@ -470,14 +473,14 @@ class SpeakerProposal(UserSubmittedModel):
|
|||
|
||||
@property
|
||||
def event_types(self):
|
||||
""" Return a queryset of the EventType objects for the EventProposals """
|
||||
"""Return a queryset of the EventType objects for the EventProposals"""
|
||||
return EventType.objects.filter(
|
||||
id__in=self.event_proposals.all().values_list("event_type", flat=True)
|
||||
)
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
""" Convenience method to return the proper host_title """
|
||||
"""Convenience method to return the proper host_title"""
|
||||
if self.event_proposals.values_list("event_type").distinct().count() != 1:
|
||||
# we have no events, or events of different eventtypes, use generic title
|
||||
return "Person"
|
||||
|
@ -486,7 +489,7 @@ class SpeakerProposal(UserSubmittedModel):
|
|||
|
||||
|
||||
class EventProposal(UserSubmittedModel):
|
||||
""" An event proposal """
|
||||
"""An event proposal"""
|
||||
|
||||
track = models.ForeignKey(
|
||||
"program.EventTrack",
|
||||
|
@ -538,7 +541,10 @@ class EventProposal(UserSubmittedModel):
|
|||
help_text="Will you be using the provided speaker laptop?", default=True
|
||||
)
|
||||
|
||||
tags = TaggableManager(through=UUIDTaggedItem, blank=True,)
|
||||
tags = TaggableManager(
|
||||
through=UUIDTaggedItem,
|
||||
blank=True,
|
||||
)
|
||||
|
||||
@property
|
||||
def camp(self):
|
||||
|
@ -618,7 +624,7 @@ class EventProposal(UserSubmittedModel):
|
|||
|
||||
@property
|
||||
def can_be_approved(self):
|
||||
""" We cannot approve an EventProposal until all SpeakerProposals are approved """
|
||||
"""We cannot approve an EventProposal until all SpeakerProposals are approved"""
|
||||
if self.speakers.exclude(proposal_status="approved").exists():
|
||||
return False
|
||||
else:
|
||||
|
@ -629,7 +635,7 @@ class EventProposal(UserSubmittedModel):
|
|||
|
||||
|
||||
class EventTrack(CampRelatedModel):
|
||||
""" All events belong to a track. Administration of a track can be delegated to one or more users. """
|
||||
"""All events belong to a track. Administration of a track can be delegated to one or more users."""
|
||||
|
||||
name = models.CharField(max_length=100, help_text="The name of this Track")
|
||||
|
||||
|
@ -660,7 +666,7 @@ class EventTrack(CampRelatedModel):
|
|||
|
||||
|
||||
class EventLocation(CampRelatedModel):
|
||||
""" The places where stuff happens """
|
||||
"""The places where stuff happens"""
|
||||
|
||||
name = models.CharField(max_length=100)
|
||||
|
||||
|
@ -693,7 +699,7 @@ class EventLocation(CampRelatedModel):
|
|||
unique_together = (("camp", "slug"), ("camp", "name"))
|
||||
|
||||
def save(self, **kwargs):
|
||||
""" Create a slug """
|
||||
"""Create a slug"""
|
||||
if not self.slug:
|
||||
self.slug = unique_slugify(
|
||||
self.name,
|
||||
|
@ -715,11 +721,11 @@ class EventLocation(CampRelatedModel):
|
|||
return self.camp.event_slots.filter(event_session__event_location=self)
|
||||
|
||||
def scheduled_event_slots(self):
|
||||
""" Returns a QuerySet of all EventSlots scheduled in this EventLocation """
|
||||
"""Returns a QuerySet of all EventSlots scheduled in this EventLocation"""
|
||||
return self.event_slots.filter(event__isnull=False)
|
||||
|
||||
def is_available(self, when, ignore_event_slot_ids=[]):
|
||||
""" A location is available if nothing is scheduled in it at that time """
|
||||
"""A location is available if nothing is scheduled in it at that time"""
|
||||
if (
|
||||
self.event_slots.filter(event__isnull=False, when__overlap=when)
|
||||
.exclude(pk__in=ignore_event_slot_ids)
|
||||
|
@ -732,7 +738,7 @@ class EventLocation(CampRelatedModel):
|
|||
|
||||
|
||||
class EventType(CreatedUpdatedModel):
|
||||
""" Every event needs to have a type. """
|
||||
"""Every event needs to have a type."""
|
||||
|
||||
name = models.CharField(
|
||||
max_length=100, unique=True, help_text="The name of this event type"
|
||||
|
@ -785,7 +791,8 @@ class EventType(CreatedUpdatedModel):
|
|||
)
|
||||
|
||||
support_autoscheduling = models.BooleanField(
|
||||
default=False, help_text="Check to enable this EventType in the autoscheduler",
|
||||
default=False,
|
||||
help_text="Check to enable this EventType in the autoscheduler",
|
||||
)
|
||||
|
||||
support_speaker_event_conflicts = models.BooleanField(
|
||||
|
@ -812,7 +819,7 @@ class EventType(CreatedUpdatedModel):
|
|||
|
||||
@property
|
||||
def duration(self):
|
||||
""" Just return a timedelta of the lenght of this Session """
|
||||
"""Just return a timedelta of the lenght of this Session"""
|
||||
return timedelta(minutes=self.event_duration_minutes)
|
||||
|
||||
def icon_html(self):
|
||||
|
@ -891,7 +898,8 @@ class EventSession(CampRelatedModel):
|
|||
)
|
||||
|
||||
description = models.TextField(
|
||||
blank=True, help_text="Description of this session (optional).",
|
||||
blank=True,
|
||||
help_text="Description of this session (optional).",
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
|
@ -904,12 +912,12 @@ class EventSession(CampRelatedModel):
|
|||
|
||||
@property
|
||||
def duration(self):
|
||||
""" Just return a timedelta of the lenght of this Session """
|
||||
"""Just return a timedelta of the lenght of this Session"""
|
||||
return self.when.upper - self.when.lower
|
||||
|
||||
@property
|
||||
def free_time(self):
|
||||
""" Returns a timedelta of the free time in this Session. """
|
||||
"""Returns a timedelta of the free time in this Session."""
|
||||
return self.duration - timedelta(
|
||||
minutes=self.event_duration_minutes * self.get_unavailable_slots().count()
|
||||
)
|
||||
|
@ -954,15 +962,16 @@ class EventSession(CampRelatedModel):
|
|||
return self.event_slots.filter(availablefilter).exclude(excludefilter)
|
||||
|
||||
def get_unavailable_slots(self, count_autoscheduled_as_free=False, bounds="[)"):
|
||||
""" Return a list of slots that are not available for some reason """
|
||||
"""Return a list of slots that are not available for some reason"""
|
||||
return self.event_slots.exclude(
|
||||
id__in=self.get_available_slots(
|
||||
count_autoscheduled_as_free=count_autoscheduled_as_free, bounds=bounds,
|
||||
count_autoscheduled_as_free=count_autoscheduled_as_free,
|
||||
bounds=bounds,
|
||||
).values_list("id", flat=True),
|
||||
)
|
||||
|
||||
def get_slot_times(self, bounds="[)"):
|
||||
""" Return a list of the DateTimeTZRanges we want EventSlots to exists for """
|
||||
"""Return a list of the DateTimeTZRanges we want EventSlots to exists for"""
|
||||
slots = []
|
||||
period = self.when
|
||||
duration = timedelta(minutes=self.event_duration_minutes)
|
||||
|
@ -985,7 +994,7 @@ class EventSession(CampRelatedModel):
|
|||
return slots
|
||||
|
||||
def fixup_event_slots(self):
|
||||
""" This method takes care of creating and deleting EventSlots when the EventSession is created, updated or deleted """
|
||||
"""This method takes care of creating and deleting EventSlots when the EventSession is created, updated or deleted"""
|
||||
# get a set of DateTimeTZRange objects representing the EventSlots we need
|
||||
needed_slot_times = set(self.get_slot_times(bounds="[)"))
|
||||
|
||||
|
@ -1036,7 +1045,9 @@ class EventSlot(CampRelatedModel):
|
|||
help_text="The EventSession this EventSlot belongs to",
|
||||
)
|
||||
|
||||
when = DateTimeRangeField(help_text="Start and end time of this slot",)
|
||||
when = DateTimeRangeField(
|
||||
help_text="Start and end time of this slot",
|
||||
)
|
||||
|
||||
event = models.ForeignKey(
|
||||
"program.Event",
|
||||
|
@ -1064,7 +1075,7 @@ class EventSlot(CampRelatedModel):
|
|||
return f"{self.when} ({self.event_session.event_location.name}, {self.event_session.event_type})"
|
||||
|
||||
def clean(self):
|
||||
""" Validate EventSlot length, time, and autoscheduled status"""
|
||||
"""Validate EventSlot length, time, and autoscheduled status"""
|
||||
if self.when.upper - self.when.lower != timedelta(
|
||||
minutes=self.event_session.event_duration_minutes
|
||||
):
|
||||
|
@ -1087,7 +1098,7 @@ class EventSlot(CampRelatedModel):
|
|||
self.clean_location()
|
||||
|
||||
def get_autoscheduler_slot(self):
|
||||
""" Return a conference_scheduler.resources.Slot object matching this EventSlot """
|
||||
"""Return a conference_scheduler.resources.Slot object matching this EventSlot"""
|
||||
return resources.Slot(
|
||||
venue=self.event_session.event_location.id,
|
||||
starts_at=self.when.lower,
|
||||
|
@ -1105,7 +1116,7 @@ class EventSlot(CampRelatedModel):
|
|||
return self.event_session.event_location
|
||||
|
||||
def clean_speakers(self):
|
||||
""" Check if all speakers are available """
|
||||
"""Check if all speakers are available"""
|
||||
if self.event:
|
||||
for speaker in self.event.speakers.all():
|
||||
if not speaker.is_available(
|
||||
|
@ -1116,7 +1127,7 @@ class EventSlot(CampRelatedModel):
|
|||
)
|
||||
|
||||
def clean_location(self):
|
||||
""" Make sure the location is available """
|
||||
"""Make sure the location is available"""
|
||||
if self.event:
|
||||
if not self.event_location.is_available(
|
||||
when=self.when, ignore_event_slot_ids=[self.pk]
|
||||
|
@ -1126,14 +1137,14 @@ class EventSlot(CampRelatedModel):
|
|||
)
|
||||
|
||||
def unschedule(self):
|
||||
""" Clear the Event FK and autoscheduled status, removing the Event from the schedule """
|
||||
"""Clear the Event FK and autoscheduled status, removing the Event from the schedule"""
|
||||
self.event = None
|
||||
self.autoscheduled = None
|
||||
self.save()
|
||||
|
||||
@property
|
||||
def overflow(self):
|
||||
""" If we have more demand than capacity return the overflow """
|
||||
"""If we have more demand than capacity return the overflow"""
|
||||
if self.event and self.event.demand > self.event_location.capacity:
|
||||
return (self.event_location.capacity - self.event.demand) * -1
|
||||
else:
|
||||
|
@ -1207,7 +1218,7 @@ class EventSlot(CampRelatedModel):
|
|||
|
||||
|
||||
class Event(CampRelatedModel):
|
||||
""" Something that is on the program one or more times. """
|
||||
"""Something that is on the program one or more times."""
|
||||
|
||||
uuid = models.UUIDField(
|
||||
default=uuid.uuid4,
|
||||
|
@ -1278,7 +1289,7 @@ class Event(CampRelatedModel):
|
|||
return self.title
|
||||
|
||||
def save(self, **kwargs):
|
||||
""" Create a slug and get duration """
|
||||
"""Create a slug and get duration"""
|
||||
if not self.slug:
|
||||
self.slug = unique_slugify(
|
||||
self.title,
|
||||
|
@ -1336,7 +1347,7 @@ class Event(CampRelatedModel):
|
|||
|
||||
|
||||
class EventInstance(CampRelatedModel):
|
||||
""" The old way of scheduling events. Model to be deleted after prod data migration """
|
||||
"""The old way of scheduling events. Model to be deleted after prod data migration"""
|
||||
|
||||
uuid = models.UUIDField(
|
||||
default=uuid.uuid4,
|
||||
|
@ -1362,7 +1373,8 @@ class EventInstance(CampRelatedModel):
|
|||
)
|
||||
|
||||
autoscheduled = models.BooleanField(
|
||||
default=False, help_text="True if this was created by the autoscheduler.",
|
||||
default=False,
|
||||
help_text="True if this was created by the autoscheduler.",
|
||||
)
|
||||
|
||||
class Meta:
|
||||
|
@ -1382,7 +1394,7 @@ class EventInstance(CampRelatedModel):
|
|||
return "%s (%s)" % (self.event, self.when)
|
||||
|
||||
def clean_speakers(self):
|
||||
""" Check if all speakers are available """
|
||||
"""Check if all speakers are available"""
|
||||
for speaker in self.event.speakers.all():
|
||||
if not speaker.is_available(
|
||||
when=self.event_slot.when, ignore_eventinstances=[self.pk]
|
||||
|
@ -1392,7 +1404,7 @@ class EventInstance(CampRelatedModel):
|
|||
)
|
||||
|
||||
def save(self, *args, clean_speakers=True, **kwargs):
|
||||
""" Validate speakers (unless we are asked not to) """
|
||||
"""Validate speakers (unless we are asked not to)"""
|
||||
if "commit" not in kwargs or kwargs["commit"]:
|
||||
# we are saving for real
|
||||
if clean_speakers:
|
||||
|
@ -1420,7 +1432,7 @@ class EventInstance(CampRelatedModel):
|
|||
|
||||
@property
|
||||
def timeslots(self):
|
||||
""" Find the number of timeslots this eventinstance takes up """
|
||||
"""Find the number of timeslots this eventinstance takes up"""
|
||||
seconds = (self.when.upper - self.when.lower).seconds
|
||||
minutes = seconds / 60
|
||||
return minutes / settings.SCHEDULE_TIMESLOT_LENGTH_MINUTES
|
||||
|
@ -1470,7 +1482,7 @@ class EventInstance(CampRelatedModel):
|
|||
|
||||
@property
|
||||
def duration(self):
|
||||
""" Return a timedelta of the lenght of this EventInstance """
|
||||
"""Return a timedelta of the lenght of this EventInstance"""
|
||||
return self.when.upper - self.when.lower
|
||||
|
||||
@property
|
||||
|
@ -1482,7 +1494,7 @@ class EventInstance(CampRelatedModel):
|
|||
|
||||
|
||||
class Speaker(CampRelatedModel):
|
||||
""" A Person (co)anchoring one or more events on a camp. """
|
||||
"""A Person (co)anchoring one or more events on a camp."""
|
||||
|
||||
name = models.CharField(max_length=150, help_text="Name or alias of the speaker")
|
||||
|
||||
|
@ -1559,9 +1571,9 @@ class Speaker(CampRelatedModel):
|
|||
return data
|
||||
|
||||
def is_available(self, when, ignore_event_slot_ids=[]):
|
||||
""" A speaker is available if the person has positive availability for the period and
|
||||
"""A speaker is available if the person has positive availability for the period and
|
||||
if the speaker is not in another event at the time, or if the person has not submitted
|
||||
any availability at all """
|
||||
any availability at all"""
|
||||
if not self.availabilities.exists():
|
||||
# we have no availability at all for this speaker, assume they are available
|
||||
return True
|
||||
|
@ -1585,12 +1597,12 @@ class Speaker(CampRelatedModel):
|
|||
return True
|
||||
|
||||
def scheduled_event_slots(self):
|
||||
""" Returns a QuerySet of all EventSlots scheduled for this speaker """
|
||||
"""Returns a QuerySet of all EventSlots scheduled for this speaker"""
|
||||
return self.camp.event_slots.filter(event__speakers=self)
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
""" Convenience method to return the proper host_title """
|
||||
"""Convenience method to return the proper host_title"""
|
||||
if self.events.values_list("event_type").distinct().count() > 1:
|
||||
# we have different eventtypes, use generic title
|
||||
return "Person"
|
||||
|
@ -1638,7 +1650,8 @@ class EventFeedback(CampRelatedModel, UUIDModel):
|
|||
)
|
||||
|
||||
expectations_fulfilled = models.BooleanField(
|
||||
choices=YESNO_CHOICES, help_text="Did the event live up to your expectations?",
|
||||
choices=YESNO_CHOICES,
|
||||
help_text="Did the event live up to your expectations?",
|
||||
)
|
||||
|
||||
attend_speaker_again = models.BooleanField(
|
||||
|
@ -1649,7 +1662,8 @@ class EventFeedback(CampRelatedModel, UUIDModel):
|
|||
RATING_CHOICES = [(n, f"{n}") for n in range(0, 6)]
|
||||
|
||||
rating = models.IntegerField(
|
||||
choices=RATING_CHOICES, help_text="Rating/Score (5 is best)",
|
||||
choices=RATING_CHOICES,
|
||||
help_text="Rating/Score (5 is best)",
|
||||
)
|
||||
|
||||
comment = models.TextField(blank=True, help_text="Any other comments or feedback?")
|
||||
|
@ -1682,15 +1696,12 @@ class CustomUrlStorage(FileSystemStorage):
|
|||
Can be removed when we clean up old migrations at some point
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
def get_speaker_picture_upload_path():
|
||||
"""
|
||||
Must exist because it is mentioned in old migrations.
|
||||
Can be removed when we clean up old migrations at some point
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def get_speakerproposal_picture_upload_path():
|
||||
|
@ -1698,7 +1709,6 @@ def get_speakerproposal_picture_upload_path():
|
|||
Must exist because it is mentioned in old migrations.
|
||||
Can be removed when we clean up old migrations at some point
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def get_speakersubmission_picture_upload_path():
|
||||
|
@ -1706,4 +1716,3 @@ def get_speakersubmission_picture_upload_path():
|
|||
Must exist because it is mentioned in old migrations.
|
||||
Can be removed when we clean up old migrations at some point
|
||||
"""
|
||||
pass
|
||||
|
|
|
@ -50,7 +50,8 @@ class MultiForm(object):
|
|||
# Some things, such as the WizardView expect these to exist.
|
||||
self.data, self.files = data, files
|
||||
kwargs.update(
|
||||
data=data, files=files,
|
||||
data=data,
|
||||
files=files,
|
||||
)
|
||||
|
||||
self.initials = kwargs.pop("initial", None)
|
||||
|
@ -74,7 +75,8 @@ class MultiForm(object):
|
|||
else:
|
||||
prefix = "{0}__{1}".format(key, prefix)
|
||||
fkwargs.update(
|
||||
initial=self.initials.get(key), prefix=prefix,
|
||||
initial=self.initials.get(key),
|
||||
prefix=prefix,
|
||||
)
|
||||
return args, fkwargs
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ logger = logging.getLogger("bornhack.%s" % __name__)
|
|||
|
||||
def check_speaker_event_camp_consistency(sender, instance, **kwargs):
|
||||
if kwargs["action"] == "pre_add":
|
||||
from program.models import Speaker, Event
|
||||
from program.models import Event, Speaker
|
||||
|
||||
if isinstance(instance, Event):
|
||||
# loop over speakers being added to this event
|
||||
|
@ -35,5 +35,5 @@ def check_speaker_event_camp_consistency(sender, instance, **kwargs):
|
|||
|
||||
|
||||
def event_session_post_save(sender, instance, created, **kwargs):
|
||||
""" Make sure we have the number of EventSlots we need to have, adjust if not """
|
||||
"""Make sure we have the number of EventSlots we need to have, adjust if not"""
|
||||
instance.fixup_event_slots()
|
||||
|
|
|
@ -9,13 +9,13 @@ register = template.Library()
|
|||
|
||||
|
||||
def render_datetime(datetime):
|
||||
""" Renders a datetime in the users timezone """
|
||||
"""Renders a datetime in the users timezone"""
|
||||
t = Template("{{ datetime }}")
|
||||
return t.render(Context({"datetime": datetime}))
|
||||
|
||||
|
||||
def render_datetimetzrange(datetimetzrange):
|
||||
""" Renders a datetimetzrange as 14:00-16:00 in the users timezone """
|
||||
"""Renders a datetimetzrange as 14:00-16:00 in the users timezone"""
|
||||
return f"{render_datetime(datetimetzrange.lower.time())}-{render_datetime(datetimetzrange.upper.time())} ({datetimetzrange.lower.tzname()})"
|
||||
|
||||
|
||||
|
@ -32,7 +32,7 @@ def availabilitytable(matrix, form=None):
|
|||
# start bulding the output
|
||||
output = "<div class='form-group'>"
|
||||
output += "<table class='table table-hover table-condensed table-bordered table-responsive' style='margin-bottom: .25em;'><thead>"
|
||||
output += f"<tr><th class='text-nowrap'>Speaker Availability</th>"
|
||||
output += "<tr><th class='text-nowrap'>Speaker Availability</th>"
|
||||
|
||||
# to build the <thead> for this table we need to loop over the days (dates)
|
||||
# in the matrix and create a column for each
|
||||
|
|
|
@ -93,7 +93,11 @@ def get_speaker_availability_form_matrix(sessions):
|
|||
# pass a list of dicts instead of the queryset to avoid one million lookups
|
||||
for et in event_types:
|
||||
matrix[day][daychunk]["event_types"].append(
|
||||
{"name": et.name, "icon": et.icon, "color": et.color,}
|
||||
{
|
||||
"name": et.name,
|
||||
"icon": et.icon,
|
||||
"color": et.color,
|
||||
}
|
||||
)
|
||||
matrix[day][daychunk]["initial"] = None
|
||||
else:
|
||||
|
@ -205,7 +209,9 @@ def save_speaker_availability(form, obj):
|
|||
else:
|
||||
# "available" changed or daychunk is not adjacent to formerchunk
|
||||
AvailabilityModel.objects.create(
|
||||
when=formerchunk, available=formeravailable, **kwargs,
|
||||
when=formerchunk,
|
||||
available=formeravailable,
|
||||
**kwargs,
|
||||
)
|
||||
# and remember the current chunk for next iteration
|
||||
formerchunk = daychunk
|
||||
|
|
|
@ -2,7 +2,6 @@ import logging
|
|||
from collections import OrderedDict
|
||||
|
||||
import icalendar
|
||||
from camps.mixins import CampViewMixin
|
||||
from django import forms
|
||||
from django.contrib import messages
|
||||
from django.contrib.admin.views.decorators import staff_member_required
|
||||
|
@ -15,6 +14,8 @@ from django.utils.decorators import method_decorator
|
|||
from django.views.generic import DetailView, ListView, TemplateView, View
|
||||
from django.views.generic.edit import CreateView, DeleteView, UpdateView
|
||||
from lxml import etree, objectify
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
from utils.middleware import RedirectException
|
||||
from utils.mixins import UserIsObjectOwnerMixin
|
||||
|
||||
|
@ -82,7 +83,8 @@ class ICSView(CampViewMixin, View):
|
|||
query_kwargs["event__video_recording"] = False
|
||||
|
||||
event_slots = models.EventSlot.objects.filter(
|
||||
event__track__camp=self.camp, **query_kwargs,
|
||||
event__track__camp=self.camp,
|
||||
**query_kwargs,
|
||||
).prefetch_related("event", "event_session__event_location")
|
||||
|
||||
cal = icalendar.Calendar()
|
||||
|
@ -109,7 +111,7 @@ class ProposalListView(LoginRequiredMixin, CampViewMixin, ListView):
|
|||
context_object_name = "speaker_proposal_list"
|
||||
|
||||
def get_queryset(self, **kwargs):
|
||||
""" Only show speaker proposals for the current user """
|
||||
"""Only show speaker proposals for the current user"""
|
||||
return (
|
||||
super()
|
||||
.get_queryset()
|
||||
|
@ -123,7 +125,7 @@ class ProposalListView(LoginRequiredMixin, CampViewMixin, ListView):
|
|||
)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
""" Add event_proposals to the context """
|
||||
"""Add event_proposals to the context"""
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["event_proposal_list"] = models.EventProposal.objects.filter(
|
||||
track__camp=self.camp, user=self.request.user
|
||||
|
@ -143,14 +145,14 @@ class SpeakerProposalCreateView(
|
|||
EnsureCFPOpenMixin,
|
||||
CreateView,
|
||||
):
|
||||
""" This view allows a user to create a new SpeakerProposal linked to an existing EventProposal """
|
||||
"""This view allows a user to create a new SpeakerProposal linked to an existing EventProposal"""
|
||||
|
||||
model = models.SpeakerProposal
|
||||
template_name = "speaker_proposal_form.html"
|
||||
form_class = SpeakerProposalForm
|
||||
|
||||
def setup(self, *args, **kwargs):
|
||||
""" Get the event_proposal object and speaker availability matrix"""
|
||||
"""Get the event_proposal object and speaker availability matrix"""
|
||||
super().setup(*args, **kwargs)
|
||||
""" Get the event_proposal and availability matrix """
|
||||
self.event_proposal = get_object_or_404(
|
||||
|
@ -166,7 +168,7 @@ class SpeakerProposalCreateView(
|
|||
return reverse("program:proposal_list", kwargs={"camp_slug": self.camp.slug})
|
||||
|
||||
def get_form_kwargs(self):
|
||||
""" Set camp and event_type for the form """
|
||||
"""Set camp and event_type for the form"""
|
||||
kwargs = super().get_form_kwargs()
|
||||
kwargs.update(
|
||||
{
|
||||
|
@ -178,7 +180,7 @@ class SpeakerProposalCreateView(
|
|||
return kwargs
|
||||
|
||||
def get_initial(self, *args, **kwargs):
|
||||
""" Populate the speaker_availability checkboxes """
|
||||
"""Populate the speaker_availability checkboxes"""
|
||||
initial = super().get_initial(*args, **kwargs)
|
||||
# loop over dates in the matrix
|
||||
for date in self.matrix.keys():
|
||||
|
@ -196,7 +198,7 @@ class SpeakerProposalCreateView(
|
|||
return context
|
||||
|
||||
def form_valid(self, form):
|
||||
""" Set user and camp before saving, then save availability """
|
||||
"""Set user and camp before saving, then save availability"""
|
||||
speaker_proposal = form.save(commit=False)
|
||||
speaker_proposal.user = self.request.user
|
||||
speaker_proposal.camp = self.camp
|
||||
|
@ -234,20 +236,20 @@ class SpeakerProposalUpdateView(
|
|||
EnsureCFPOpenMixin,
|
||||
UpdateView,
|
||||
):
|
||||
""" This view allows a user to update an existing SpeakerProposal. """
|
||||
"""This view allows a user to update an existing SpeakerProposal."""
|
||||
|
||||
model = models.SpeakerProposal
|
||||
template_name = "speaker_proposal_form.html"
|
||||
form_class = SpeakerProposalForm
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
""" Prefetch availabilities for this SpeakerProposal """
|
||||
"""Prefetch availabilities for this SpeakerProposal"""
|
||||
qs = self.model.objects.filter(pk=self.kwargs.get(self.pk_url_kwarg))
|
||||
qs = qs.prefetch_related("availabilities")
|
||||
return qs.get()
|
||||
|
||||
def get_form_kwargs(self):
|
||||
""" Set camp, matrix and event_type for the form """
|
||||
"""Set camp, matrix and event_type for the form"""
|
||||
kwargs = super().get_form_kwargs()
|
||||
|
||||
# get all event types this SpeakerProposal is involved in
|
||||
|
@ -269,7 +271,7 @@ class SpeakerProposalUpdateView(
|
|||
return kwargs
|
||||
|
||||
def form_valid(self, form):
|
||||
""" Change status and save availability """
|
||||
"""Change status and save availability"""
|
||||
speaker_proposal = form.save(commit=False)
|
||||
|
||||
# set proposal status to pending
|
||||
|
@ -295,7 +297,7 @@ class SpeakerProposalUpdateView(
|
|||
# message user and redirect
|
||||
messages.info(
|
||||
self.request,
|
||||
f"Changes to your proposal is now pending approval by the content team.",
|
||||
"Changes to your proposal is now pending approval by the content team.",
|
||||
)
|
||||
return redirect(
|
||||
reverse(
|
||||
|
@ -335,7 +337,7 @@ class SpeakerProposalDeleteView(
|
|||
return super().get(request, *args, **kwargs)
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
""" Delete availabilities before deleting the proposal """
|
||||
"""Delete availabilities before deleting the proposal"""
|
||||
self.get_object().availabilities.all().delete()
|
||||
return super().delete(*args, **kwargs)
|
||||
|
||||
|
@ -377,18 +379,18 @@ class EventProposalTypeSelectView(
|
|||
context_object_name = "event_type_list"
|
||||
|
||||
def setup(self, *args, **kwargs):
|
||||
""" Get the speaker_proposal object """
|
||||
"""Get the speaker_proposal object"""
|
||||
super().setup(*args, **kwargs)
|
||||
self.speaker = get_object_or_404(
|
||||
models.SpeakerProposal, pk=kwargs["speaker_uuid"]
|
||||
)
|
||||
|
||||
def get_queryset(self, **kwargs):
|
||||
""" We only allow submissions of events with EventTypes where public=True """
|
||||
"""We only allow submissions of events with EventTypes where public=True"""
|
||||
return super().get_queryset().filter(public=True)
|
||||
|
||||
def get_context_data(self, *args, **kwargs):
|
||||
""" Make speaker_proposal object available in template """
|
||||
"""Make speaker_proposal object available in template"""
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["speaker"] = self.speaker
|
||||
return context
|
||||
|
@ -410,18 +412,18 @@ class EventProposalSelectPersonView(
|
|||
context_object_name = "speaker_proposal_list"
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
""" Get EventProposal from url kwargs """
|
||||
"""Get EventProposal from url kwargs"""
|
||||
self.event_proposal = get_object_or_404(
|
||||
models.EventProposal, pk=kwargs["event_uuid"], user=request.user
|
||||
)
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_queryset(self, **kwargs):
|
||||
""" Filter out any speaker_proposals already added to this event_proposal """
|
||||
"""Filter out any speaker_proposals already added to this event_proposal"""
|
||||
return self.event_proposal.get_available_speaker_proposals().all()
|
||||
|
||||
def get_context_data(self, *args, **kwargs):
|
||||
""" Make event_proposal object available in template """
|
||||
"""Make event_proposal object available in template"""
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["event_proposal"] = self.event_proposal
|
||||
return context
|
||||
|
@ -445,14 +447,14 @@ class EventProposalAddPersonView(
|
|||
context_object_name = "event_proposal"
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
""" Get the speaker_proposal object """
|
||||
"""Get the speaker_proposal object"""
|
||||
self.speaker_proposal = get_object_or_404(
|
||||
models.SpeakerProposal, pk=kwargs["speaker_uuid"], user=request.user
|
||||
)
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_context_data(self, *args, **kwargs):
|
||||
""" Make speaker_proposal object available in template """
|
||||
"""Make speaker_proposal object available in template"""
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["speaker_proposal"] = self.speaker_proposal
|
||||
return context
|
||||
|
@ -488,7 +490,7 @@ class EventProposalRemovePersonView(
|
|||
pk_url_kwarg = "event_uuid"
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
""" Get the speaker_proposal object and check a few things """
|
||||
"""Get the speaker_proposal object and check a few things"""
|
||||
# get the speaker_proposal object from URL kwargs
|
||||
self.speaker_proposal = get_object_or_404(
|
||||
models.SpeakerProposal, pk=kwargs["speaker_uuid"], user=request.user
|
||||
|
@ -496,13 +498,13 @@ class EventProposalRemovePersonView(
|
|||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_context_data(self, *args, **kwargs):
|
||||
""" Make speaker_proposal object available in template """
|
||||
"""Make speaker_proposal object available in template"""
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["speaker_proposal"] = self.speaker_proposal
|
||||
return context
|
||||
|
||||
def form_valid(self, form):
|
||||
""" Remove the speaker from the event """
|
||||
"""Remove the speaker from the event"""
|
||||
if self.speaker_proposal not in self.get_object().speakers.all():
|
||||
# this speaker is not associated with this event
|
||||
raise Http404
|
||||
|
@ -545,7 +547,7 @@ class EventProposalCreateView(
|
|||
form_class = EventProposalForm
|
||||
|
||||
def setup(self, *args, **kwargs):
|
||||
""" Get the speaker_proposal object """
|
||||
"""Get the speaker_proposal object"""
|
||||
super().setup(*args, **kwargs)
|
||||
self.speaker_proposal = get_object_or_404(
|
||||
models.SpeakerProposal, pk=self.kwargs["speaker_uuid"]
|
||||
|
@ -555,7 +557,7 @@ class EventProposalCreateView(
|
|||
)
|
||||
|
||||
def get_context_data(self, *args, **kwargs):
|
||||
""" Make speaker_proposal object available in template """
|
||||
"""Make speaker_proposal object available in template"""
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["speaker"] = self.speaker_proposal
|
||||
context["event_type"] = self.event_type
|
||||
|
@ -570,7 +572,7 @@ class EventProposalCreateView(
|
|||
return kwargs
|
||||
|
||||
def form_valid(self, form):
|
||||
""" set camp and user for this event_proposal, save slideurl """
|
||||
"""set camp and user for this event_proposal, save slideurl"""
|
||||
event_proposal = form.save(commit=False)
|
||||
event_proposal.user = self.request.user
|
||||
event_proposal.event_type = self.event_type
|
||||
|
@ -630,7 +632,7 @@ class EventProposalUpdateView(
|
|||
return kwargs
|
||||
|
||||
def get_context_data(self, *args, **kwargs):
|
||||
""" Make speaker_proposal and event_type objects available in the template """
|
||||
"""Make speaker_proposal and event_type objects available in the template"""
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["event_type"] = self.get_object().event_type
|
||||
return context
|
||||
|
@ -711,7 +713,7 @@ class CombinedProposalTypeSelectView(LoginRequiredMixin, CampViewMixin, ListView
|
|||
template_name = "event_type_select.html"
|
||||
|
||||
def get_queryset(self, **kwargs):
|
||||
""" We only allow submissions of events with EventTypes where public=True """
|
||||
"""We only allow submissions of events with EventTypes where public=True"""
|
||||
return super().get_queryset().filter(public=True)
|
||||
|
||||
|
||||
|
@ -727,14 +729,14 @@ class CombinedProposalPersonSelectView(LoginRequiredMixin, CampViewMixin, ListVi
|
|||
context_object_name = "speaker_proposal_list"
|
||||
|
||||
def setup(self, *args, **kwargs):
|
||||
""" Check that we have a valid EventType """
|
||||
"""Check that we have a valid EventType"""
|
||||
super().setup(*args, **kwargs)
|
||||
self.event_type = get_object_or_404(
|
||||
models.EventType, slug=self.kwargs["event_type_slug"]
|
||||
)
|
||||
|
||||
def get_queryset(self, **kwargs):
|
||||
""" only show speaker proposals for the current user """
|
||||
"""only show speaker proposals for the current user"""
|
||||
return super().get_queryset().filter(user=self.request.user)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
@ -746,7 +748,7 @@ class CombinedProposalPersonSelectView(LoginRequiredMixin, CampViewMixin, ListVi
|
|||
return context
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
""" If we don't have any existing SpeakerProposals just redirect directly to the combined submit view """
|
||||
"""If we don't have any existing SpeakerProposals just redirect directly to the combined submit view"""
|
||||
if not self.get_queryset().exists():
|
||||
return redirect(
|
||||
reverse_lazy(
|
||||
|
@ -1004,7 +1006,9 @@ class FrabXmlView(CampViewMixin, View):
|
|||
qs = (
|
||||
models.EventSlot.objects.filter(event__track__camp=self.camp)
|
||||
.prefetch_related(
|
||||
"event__urls", "event__speakers", "event_session__event_location",
|
||||
"event__urls",
|
||||
"event__speakers",
|
||||
"event_session__event_location",
|
||||
)
|
||||
.order_by("when", "event_session__event_location")
|
||||
)
|
||||
|
@ -1327,7 +1331,7 @@ class UrlDeleteView(
|
|||
|
||||
|
||||
class FeedbackRedirectView(LoginRequiredMixin, EventViewMixin, DetailView):
|
||||
""" Redirect to the appropriate view """
|
||||
"""Redirect to the appropriate view"""
|
||||
|
||||
model = models.Event
|
||||
slug_url_kwarg = "event_slug"
|
||||
|
|
|
@ -11,6 +11,8 @@ class Migration(migrations.Migration):
|
|||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name="ride", old_name="location", new_name="from_location",
|
||||
model_name="ride",
|
||||
old_name="location",
|
||||
new_name="from_location",
|
||||
),
|
||||
]
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from django.db import models
|
||||
from django.urls import reverse
|
||||
|
||||
from utils.models import CampRelatedModel, UUIDModel
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
from camps.mixins import CampViewMixin
|
||||
from django import forms
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
|
@ -11,6 +10,8 @@ from django.views.generic import (
|
|||
ListView,
|
||||
UpdateView,
|
||||
)
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
from teams.models import Team
|
||||
from utils.email import add_outgoing_email
|
||||
from utils.mixins import UserIsObjectOwnerMixin
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from tickets.admin import ShopTicketInline
|
||||
|
||||
from .models import (
|
||||
|
|
|
@ -3,6 +3,7 @@ import logging
|
|||
|
||||
import requests
|
||||
from django.conf import settings
|
||||
|
||||
from vendor.coinify.coinify_api import CoinifyAPI
|
||||
|
||||
from .models import CoinifyAPICallback, CoinifyAPIInvoice, CoinifyAPIRequest
|
||||
|
|
|
@ -2,6 +2,7 @@ import factory
|
|||
from django.utils import timezone
|
||||
from factory.django import DjangoModelFactory
|
||||
from psycopg2.extras import DateTimeTZRange
|
||||
|
||||
from utils.factories import UserFactory
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from django import forms
|
||||
from django.forms import modelformset_factory
|
||||
|
||||
from shop.models import OrderProductRelation
|
||||
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ import logging
|
|||
from django.conf import settings
|
||||
from django.core.files import File
|
||||
from django.db.models import Q
|
||||
|
||||
from shop.email import add_creditnote_email, add_invoice_email
|
||||
from shop.models import CreditNote, CustomOrder, Invoice, Order
|
||||
from utils.pdf import generate_pdf_letter
|
||||
|
|
|
@ -11,7 +11,9 @@ class Migration(migrations.Migration):
|
|||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="coinifyapicallback", name="headers", field=models.JSONField(),
|
||||
model_name="coinifyapicallback",
|
||||
name="headers",
|
||||
field=models.JSONField(),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="coinifyapicallback",
|
||||
|
@ -24,13 +26,19 @@ class Migration(migrations.Migration):
|
|||
field=models.JSONField(),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="coinifyapirequest", name="payload", field=models.JSONField(),
|
||||
model_name="coinifyapirequest",
|
||||
name="payload",
|
||||
field=models.JSONField(),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="coinifyapirequest", name="response", field=models.JSONField(),
|
||||
model_name="coinifyapirequest",
|
||||
name="response",
|
||||
field=models.JSONField(),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="epaycallback", name="payload", field=models.JSONField(),
|
||||
model_name="epaycallback",
|
||||
name="payload",
|
||||
field=models.JSONField(),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="order",
|
||||
|
|
|
@ -13,6 +13,7 @@ from django.utils import timezone
|
|||
from django.utils.dateparse import parse_datetime
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from unidecode import unidecode
|
||||
|
||||
from utils.models import CreatedUpdatedModel, UUIDModel
|
||||
from utils.slugs import unique_slugify
|
||||
|
||||
|
@ -160,7 +161,7 @@ class Order(CreatedUpdatedModel):
|
|||
return False
|
||||
|
||||
def get_coinify_callback_url(self, request):
|
||||
""" Check settings for an alternative COINIFY_CALLBACK_HOSTNAME otherwise use the one from the request """
|
||||
"""Check settings for an alternative COINIFY_CALLBACK_HOSTNAME otherwise use the one from the request"""
|
||||
if (
|
||||
hasattr(settings, "COINIFY_CALLBACK_HOSTNAME")
|
||||
and settings.COINIFY_CALLBACK_HOSTNAME
|
||||
|
|
|
@ -2,6 +2,7 @@ from django.test import TestCase
|
|||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from psycopg2.extras import DateTimeTZRange
|
||||
|
||||
from shop.forms import OrderProductRelationForm
|
||||
from tickets.factories import TicketTypeFactory
|
||||
from tickets.models import ShopTicket
|
||||
|
@ -11,16 +12,16 @@ from .factories import OrderFactory, OrderProductRelationFactory, ProductFactory
|
|||
|
||||
|
||||
class ProductAvailabilityTest(TestCase):
|
||||
""" Test logic about availability of products. """
|
||||
"""Test logic about availability of products."""
|
||||
|
||||
def test_product_available_by_stock(self):
|
||||
""" If no orders have been made, the product is still available. """
|
||||
"""If no orders have been made, the product is still available."""
|
||||
product = ProductFactory(stock_amount=10)
|
||||
self.assertEqual(product.left_in_stock, 10)
|
||||
self.assertTrue(product.is_available())
|
||||
|
||||
def test_product_not_available_by_stock(self):
|
||||
""" If max orders have been made, the product is NOT available. """
|
||||
"""If max orders have been made, the product is NOT available."""
|
||||
product = ProductFactory(stock_amount=2)
|
||||
|
||||
OrderProductRelationFactory(product=product, order__open=None)
|
||||
|
@ -39,14 +40,14 @@ class ProductAvailabilityTest(TestCase):
|
|||
self.assertTrue(product.is_available())
|
||||
|
||||
def test_product_available_by_time(self):
|
||||
""" The product is available if now is in the right timeframe. """
|
||||
"""The product is available if now is in the right timeframe."""
|
||||
product = ProductFactory()
|
||||
# The factory defines the timeframe as now and 31 days forward.
|
||||
self.assertTrue(product.is_time_available)
|
||||
self.assertTrue(product.is_available())
|
||||
|
||||
def test_product_not_available_by_time(self):
|
||||
""" The product is not available if now is outside the timeframe. """
|
||||
"""The product is not available if now is outside the timeframe."""
|
||||
available_in = DateTimeTZRange(
|
||||
lower=timezone.now() - timezone.timedelta(5),
|
||||
upper=timezone.now() - timezone.timedelta(1),
|
||||
|
@ -57,7 +58,7 @@ class ProductAvailabilityTest(TestCase):
|
|||
self.assertFalse(product.is_available())
|
||||
|
||||
def test_product_is_not_available_yet(self):
|
||||
""" The product is not available because we are before lower bound. """
|
||||
"""The product is not available because we are before lower bound."""
|
||||
available_in = DateTimeTZRange(lower=timezone.now() + timezone.timedelta(5))
|
||||
product = ProductFactory(available_in=available_in)
|
||||
# Make sure there is no upper - just in case.
|
||||
|
@ -67,7 +68,7 @@ class ProductAvailabilityTest(TestCase):
|
|||
self.assertFalse(product.is_available())
|
||||
|
||||
def test_product_is_available_from_now_on(self):
|
||||
""" The product is available because we are after lower bound. """
|
||||
"""The product is available because we are after lower bound."""
|
||||
available_in = DateTimeTZRange(lower=timezone.now() - timezone.timedelta(1))
|
||||
product = ProductFactory(available_in=available_in)
|
||||
# Make sure there is no upper - just in case.
|
||||
|
|
|
@ -19,6 +19,7 @@ from django.views.decorators.csrf import csrf_exempt
|
|||
from django.views.generic import DetailView, FormView, ListView, View
|
||||
from django.views.generic.base import RedirectView
|
||||
from django.views.generic.detail import SingleObjectMixin
|
||||
|
||||
from shop.models import (
|
||||
CreditNote,
|
||||
EpayCallback,
|
||||
|
|
|
@ -2,6 +2,7 @@ import logging
|
|||
import os
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from teams.models import Team
|
||||
from utils.email import add_outgoing_email
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
# coding: utf-8
|
||||
import logging
|
||||
|
||||
from camps.models import Camp
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.utils import timezone
|
||||
|
||||
from camps.models import Camp
|
||||
from sponsors.email import add_sponsorticket_email
|
||||
from sponsors.models import Sponsor
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
# coding: utf-8
|
||||
from camps.models import Camp
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.utils import timezone
|
||||
|
||||
from camps.models import Camp
|
||||
from sponsors.models import Sponsor
|
||||
from tickets.models import SponsorTicket, TicketType
|
||||
|
||||
|
|
|
@ -2,9 +2,10 @@
|
|||
# Generated by Django 1.11 on 2017-07-11 21:35
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import sponsors.models
|
||||
from django.db import migrations, models
|
||||
|
||||
import sponsors.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from django.db import models
|
||||
|
||||
from utils.models import CampRelatedModel
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from camps.mixins import CampViewMixin
|
||||
from django.views.generic import ListView
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
|
||||
from .models import Sponsor
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from camps.utils import CampPropertyListFilter
|
||||
from django.contrib import admin
|
||||
|
||||
from camps.utils import CampPropertyListFilter
|
||||
|
||||
from .email import add_added_membership_email, add_removed_membership_email
|
||||
from .models import Team, TeamMember, TeamShift, TeamTask
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ from django.contrib.postgres.fields import DateTimeRangeField
|
|||
from django.core.exceptions import ValidationError
|
||||
from django.db import models
|
||||
from django.urls import reverse_lazy
|
||||
|
||||
from utils.models import CampRelatedModel, CreatedUpdatedModel, UUIDModel
|
||||
from utils.slugs import unique_slugify
|
||||
|
||||
|
@ -317,7 +318,7 @@ class TeamMember(CampRelatedModel):
|
|||
|
||||
@property
|
||||
def camp(self):
|
||||
""" All CampRelatedModels must have a camp FK or a camp property """
|
||||
"""All CampRelatedModels must have a camp FK or a camp property"""
|
||||
return self.team.camp
|
||||
|
||||
camp_filter = "team__camp"
|
||||
|
@ -362,7 +363,7 @@ class TeamTask(CampRelatedModel):
|
|||
|
||||
@property
|
||||
def camp(self):
|
||||
""" All CampRelatedModels must have a camp FK or a camp property """
|
||||
"""All CampRelatedModels must have a camp FK or a camp property"""
|
||||
return self.team.camp
|
||||
|
||||
camp_filter = "team__camp"
|
||||
|
@ -406,7 +407,7 @@ class TeamShift(CampRelatedModel):
|
|||
|
||||
@property
|
||||
def camp(self):
|
||||
""" All CampRelatedModels must have a camp FK or a camp property """
|
||||
"""All CampRelatedModels must have a camp FK or a camp property"""
|
||||
return self.team.camp
|
||||
|
||||
camp_filter = "team__camp"
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import logging
|
||||
|
||||
|
||||
logger = logging.getLogger("bornhack.%s" % __name__)
|
||||
|
||||
|
||||
|
@ -13,6 +12,7 @@ def teammember_saved(sender, instance, created, **kwargs):
|
|||
# call the mail sending function
|
||||
# late import to please django 3.2 or "django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet."
|
||||
from .email import add_new_membership_email
|
||||
|
||||
if not add_new_membership_email(instance):
|
||||
logger.error("Error adding email to outgoing queue")
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from django import template
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
from teams.models import TeamMember
|
||||
|
||||
register = template.Library()
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from django.urls import include, path
|
||||
|
||||
from teams.views.base import (
|
||||
FixIrcAclView,
|
||||
TeamGeneralView,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import logging
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
|
@ -9,6 +8,8 @@ from django.urls import reverse_lazy
|
|||
from django.views.generic import DetailView, ListView
|
||||
from django.views.generic.edit import UpdateView
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
|
||||
from ..models import Team, TeamMember
|
||||
from .mixins import EnsureTeamResponsibleMixin
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
from camps.mixins import CampViewMixin
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
|
||||
from django.views.generic import DetailView
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
|
||||
from ..models import Team, TeamMember
|
||||
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
from camps.mixins import CampViewMixin
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.views.generic import CreateView, DeleteView, ListView, UpdateView
|
||||
from info.models import InfoCategory, InfoItem
|
||||
from reversion.views import RevisionMixin
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
from info.models import InfoCategory, InfoItem
|
||||
|
||||
from ..models import Team
|
||||
from .mixins import EnsureTeamResponsibleMixin, TeamViewMixin
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import logging
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.shortcuts import redirect
|
||||
from django.views.generic import DetailView, UpdateView
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
from profiles.models import Profile
|
||||
|
||||
from ..email import add_added_membership_email, add_removed_membership_email
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from django.contrib import messages
|
||||
from django.shortcuts import redirect
|
||||
from django.views.generic.detail import SingleObjectMixin
|
||||
|
||||
from teams.models import Team, TeamMember
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
from camps.mixins import CampViewMixin
|
||||
from django import forms
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
|
@ -17,6 +16,8 @@ from django.views.generic import (
|
|||
)
|
||||
from psycopg2.extras import DateTimeTZRange
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
|
||||
from ..models import Team, TeamMember, TeamShift
|
||||
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
from camps.mixins import CampViewMixin
|
||||
from django import forms
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.http import HttpResponseNotAllowed, HttpResponseRedirect
|
||||
from django.views.generic import CreateView, DetailView, UpdateView
|
||||
|
||||
from camps.mixins import CampViewMixin
|
||||
|
||||
from ..models import TaskComment, Team, TeamMember, TeamTask
|
||||
from .mixins import EnsureTeamResponsibleMixin, TeamViewMixin
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from shop.models import OrderProductRelation
|
||||
|
||||
from .models import DiscountTicket, ShopTicket, SponsorTicket, TicketType
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# Generated by Django 2.2.2 on 2019-07-18 18:52
|
||||
from django.conf import settings
|
||||
from django.db import migrations
|
||||
|
||||
from tickets.models import create_ticket_token
|
||||
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue