Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add event creation view #15

Merged
merged 4 commits into from
Aug 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion event_management/admin.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from django.contrib import admin
from guardian.admin import GuardedModelAdmin

from event_management.models import Event, EventType, LocalParticipation, Shift

admin.site.register(Shift)
admin.site.register(Event)
admin.site.register(Event, GuardedModelAdmin)
admin.site.register(EventType)
admin.site.register(LocalParticipation)
83 changes: 83 additions & 0 deletions event_management/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
from datetime import datetime, timedelta

from django.contrib.auth.models import Group
from django.core.exceptions import ValidationError
from django.forms import (
ModelForm,
ModelMultipleChoiceField,
modelformset_factory,
Select,
DateField,
TimeField,
)
from guardian.shortcuts import assign_perm

from event_management.models import Event, Shift
from event_management.signup import register_signup_methods
from jep.widgets import CustomDateInput, CustomTimeInput
from user_management.models import UserProfile


class EventForm(ModelForm):
visible_for = ModelMultipleChoiceField(queryset=Group.objects.none())
responsible_persons = ModelMultipleChoiceField(
queryset=UserProfile.objects.all(), required=False
)
responsible_groups = ModelMultipleChoiceField(queryset=Group.objects.all(), required=False)

class Meta:
model = Event
fields = ["title", "description", "location", "type"]

def save(self, commit=True):
event = super(EventForm, self).save(commit)
for group in self.cleaned_data["visible_for"]:
assign_perm("view_event", group, event)
for group in self.cleaned_data["responsible_groups"]:
assign_perm("change_event", group, event)
for user in self.cleaned_data["responsible_persons"]:
assign_perm("change_event", user, event)
return event


class ShiftForm(ModelForm):
date = DateField(widget=CustomDateInput)
meeting_time = TimeField(widget=CustomTimeInput)
start_time = TimeField(widget=CustomTimeInput)
end_time = TimeField(widget=CustomTimeInput)

class Meta:
model = Shift
fields = ["signup_method_slug"]
widgets = {
"signup_method_slug": Select(
choices=(
(method.slug, method.verbose_name)
for receiver, method in register_signup_methods.send(None)
)
)
}

def clean(self):
cleaned_data = super(ShiftForm, self).clean()
if not cleaned_data["meeting_time"] <= cleaned_data["start_time"]:
raise ValidationError("Meeting time must not be after start time!")
return cleaned_data

def save(self, commit=True):
shift = super().save(commit)
shift.meeting_time = datetime.combine(
self.cleaned_data["date"], self.cleaned_data["meeting_time"]
)
shift.start_time = datetime.combine(
self.cleaned_data["date"], self.cleaned_data["start_time"]
)
if self.cleaned_data["end_time"] <= self.cleaned_data["start_time"]:
end_date = self.cleaned_data["date"] + timedelta(days=1)
else:
end_date = self.cleaned_data["date"]
shift.end_time = datetime.combine(end_date, self.cleaned_data["end_time"])
return shift.save() if commit else shift


ShiftFormSet = modelformset_factory(Shift, form=ShiftForm,)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<input type="date" name="{{ widget.name }}"{% if widget.value != None %} value="{{ widget.value|stringformat:'s' }}"{% endif %}{% include "django/forms/widgets/attrs.html" %}>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<input type="time" name="{{ widget.name }}"{% if widget.value != None %} value="{{ widget.value|stringformat:'s' }}"{% endif %}{% include "django/forms/widgets/attrs.html" %}>
30 changes: 30 additions & 0 deletions event_management/templates/event_management/event_form.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{% extends "base.html" %}
{% load bootstrap4 %}
{% load static %}

{% block title %}
Create new event
{% endblock %}

{% block content %}
<div class="page-header">
<h1>Create new event</h1>
</div>
<form method="post" class="form">
{% csrf_token %}
{% bootstrap_form event_form %}
{{ shift_formset.management_form }}
{% for shift_form in shift_formset %}
<div class="card mb-2">
<div class="card-body">
<h5 class="card-title">Shift</h5>
{% bootstrap_form shift_form %}
</div>
</div>

{% endfor %}
{% buttons %}
<button type="submit" class="btn btn-primary">Save</button>
{% endbuttons %}
</form>
{% endblock %}
17 changes: 12 additions & 5 deletions event_management/templates/event_management/event_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
<div class="page-header">
<h1>Events</h1>
</div>
{% if perms.event_management.add_event %}
<a class="btn btn-secondary" href="{% url "event_management:event_create" %}"><span
class="fa fa-plus"></span> Add event</a>
{% endif %}
<table id="event_table" class="table table-striped display">
<thead>
<tr>
Expand All @@ -32,11 +36,14 @@ <h1>Events</h1>
</thead>
<tbody>
{% for event in event_list %}
<td>{{ event.title }}</td>
<td>{{ event.location }}</td>
<td>{{ event.start_time | date:"d.m.Y" }}</td>
<td>{{ event.end_time | date:"d.m.Y" }}</td>
<td><a class="btn btn-primary" href="{% url "event_management:event_detail" event.id %}"><span class="fa fa-eye"></span>Show</a></td>
<tr>
<td>{{ event.title }}</td>
<td>{{ event.location }}</td>
<td>{{ event.start_time | date:"d.m.Y" }}</td>
<td>{{ event.end_time | date:"d.m.Y" }}</td>
<td><a class="btn btn-primary" href="{% url "event_management:event_detail" event.id %}"><span
class="fa fa-eye"></span> Show</a></td>
</tr>
{% endfor %}
</tbody>
</table>
Expand Down
2 changes: 1 addition & 1 deletion event_management/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@
# path("<int:pk>/edit", views.UpdateView.as_view(), name="event_change"),
# path("<int:pk>/delete", views.DeleteView.as_view(), name="event_delete"),
path("events/<int:pk>/", views.EventDetailView.as_view(), name="event_detail"),
# path("add/", views.CreateView.as_view(), name="event_add"),
path("events/create/", views.EventCreateView.as_view(), name="event_create"),
path("shifts/<int:pk>/register", views.ShiftRegisterView.as_view(), name="shift_register",),
]
57 changes: 52 additions & 5 deletions event_management/views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import get_object_or_404
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.contrib.auth.models import Group
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render, redirect
from django.views.generic import (
DeleteView,
DetailView,
Expand All @@ -8,7 +10,9 @@
UpdateView,
View,
)
from guardian.shortcuts import get_objects_for_user

from event_management.forms import EventForm, ShiftFormSet
from event_management.models import (
Event,
Shift,
Expand All @@ -22,17 +26,60 @@ class HomeView(LoginRequiredMixin, TemplateView):
class EventListView(LoginRequiredMixin, ListView):
model = Event

def get_queryset(self):
return get_objects_for_user(self.request.user, "event_management.view_event")

class EventDetailView(LoginRequiredMixin, DetailView):

class EventDetailView(PermissionRequiredMixin, DetailView):
model = Event
permission_required = "event_management.view_event"


class EventUpdateView(LoginRequiredMixin, UpdateView):
class EventUpdateView(PermissionRequiredMixin, UpdateView):
model = Event
permission_required = "event_management.change_event"


class EventCreateView(PermissionRequiredMixin, TemplateView):
template_name = "event_management/event_form.html"
permission_required = "event_management.add_event"

def get_event_form(self):
event_form = EventForm(
self.request.POST or None, initial={"responsible_persons": self.request.user}
)
event_form.fields["visible_for"].queryset = get_objects_for_user(
self.request.user, "publish_event_for_group", klass=Group
)
return event_form

def get_shift_formset(self):
return ShiftFormSet(self.request.POST or None, queryset=Shift.objects.none())

def get_context_data(self, **kwargs):
kwargs.setdefault("event_form", self.get_event_form())
kwargs.setdefault("shift_formset", self.get_shift_formset())
return super().get_context_data(**kwargs)

def post(self, request, *args, **kwargs):
event_form = self.get_event_form()
shift_formset = self.get_shift_formset()
if event_form.is_valid() and shift_formset.is_valid():
event = event_form.save()
shifts = shift_formset.save(commit=False)
for shift in shifts:
shift.event = event
shift.signup_configuration = ""
shift.save()
return redirect(event.get_absolute_url())
return self.render_to_response(
self.get_context_data(event_form=event_form, shift_formset=shift_formset)
)


class EventDeleteView(LoginRequiredMixin, DeleteView):
class EventDeleteView(PermissionRequiredMixin, DeleteView):
model = Event
permission_required = "event_management.delete_event"


# TODO rename to signup
Expand Down
12 changes: 12 additions & 0 deletions jep/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"django.contrib.messages",
"django.contrib.staticfiles",
"bootstrap4",
"guardian",
"user_management",
"event_management",
]
Expand Down Expand Up @@ -93,6 +94,11 @@
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",},
]

AUTHENTICATION_BACKENDS = (
"django.contrib.auth.backends.ModelBackend",
"guardian.backends.ObjectPermissionBackend",
)

AUTH_USER_MODEL = "user_management.UserProfile"
LOGIN_REDIRECT_URL = "/"

Expand All @@ -116,3 +122,9 @@

STATIC_URL = env.str("STATIC_URL")
STATIC_ROOT = env.str("STATIC_ROOT")
STATICFILES_DIRS = (os.path.join(BASE_DIR, "static"),)


# Guardian configuration
ANONYMOUS_USER_NAME = None
GUARDIAN_MONKEY_PATCH = False
9 changes: 9 additions & 0 deletions jep/widgets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from django.forms import DateInput, TimeInput


class CustomDateInput(DateInput):
template_name = "event_management/custom_date_input.html"


class CustomTimeInput(TimeInput):
template_name = "event_management/custom_time_input.html"
17 changes: 16 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ django-environ = "^0.4.5"
mysqlclient = "^1.4.6"
django-jsonfallback = "^2.1.2"
psycopg2 = "^2.8.5"
django-guardian = "^2.3.0"

[tool.poetry.dev-dependencies]
black = "^19.10b0"
Expand Down
Loading