Skip to content

Commit

Permalink
group creators can add/remove organizers, delete events and group
Browse files Browse the repository at this point in the history
  • Loading branch information
karambir committed Jun 25, 2014
1 parent 7ebebf8 commit 03c42ed
Show file tree
Hide file tree
Showing 8 changed files with 318 additions and 11 deletions.
38 changes: 37 additions & 1 deletion tavern/forms.py
@@ -1,6 +1,7 @@
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from django.forms.widgets import HiddenInput

from .models import TavernGroup, Event, Membership
from bootstrap3_datetime.widgets import DateTimePicker
Expand All @@ -21,7 +22,7 @@ class Meta:
exclude = ['creator', 'slug', 'show']

def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user', None)
self.user = kwargs.pop('current_user', None)
super(CreateEventForm, self).__init__(*args, **kwargs)
self.fields['group'].queryset = self.user.tavern_groups.all()
self.fields['starts_at'].widget = DateTimePicker(options={"format": "YYYY-MM-DD HH:mm", })
Expand Down Expand Up @@ -63,3 +64,38 @@ def save(self, commit=True):
if commit:
user.save()
return user


class AddOrganizerForm(forms.Form):
usernames = forms.CharField()

def clean(self):
cleaned_data = super(AddOrganizerForm, self).clean()
usernames = cleaned_data.get('usernames')
cleaned_data['users'] = []
for username in usernames.split(','):
try:
user = User.objects.get(username=username.strip())
cleaned_data['users'].append(user)
except User.DoesNotExist:
raise forms.ValidationError("%s is not a user" % username.strip())
return cleaned_data


class RemoveOrganizerForm(AddOrganizerForm):
group = forms.CharField(max_length=5)

def __init__(self, *args, **kwargs):
super(RemoveOrganizerForm, self).__init__(*args, **kwargs)
self.fields['group'].widget = HiddenInput()

def clean(self):
cleaned_data = super(RemoveOrganizerForm, self).clean()
users = cleaned_data.get('users')
group = TavernGroup.objects.get(pk=cleaned_data['group'])
for user in users:
try:
group.organizers.get(username=user.username)
except User.DoesNotExist:
raise forms.ValidationError("%s is not an organizer of %s group" % (user.username, group.name))
return cleaned_data
135 changes: 135 additions & 0 deletions tavern/multiform.py
@@ -0,0 +1,135 @@
# Class-based Views for handling multiple forms
# https://gist.github.com/jamesbrobb/748c47f46b9bd224b07f

from django.views.generic.base import TemplateResponseMixin, ContextMixin
from django.views.generic.edit import ProcessFormView
from django.http import HttpResponseRedirect, HttpResponseForbidden


class MultiFormMixin(ContextMixin):

form_classes = {}
prefixes = {}
success_urls = {}
grouped_forms = {}

initial = {}
prefix = None
success_url = None

def get_form_classes(self):
return self.form_classes

def get_forms(self, form_classes, form_names=None, bind_all=False):
return dict([(key, self._create_form(key, klass,
(form_names and key in form_names) or bind_all)) for key, klass in form_classes.items()])

def get_form_kwargs(self, form_name, bind_form=False):
kwargs = {}
kwargs.update({'initial': self.get_initial(form_name)})
kwargs.update({'prefix': self.get_prefix(form_name)})

if bind_form:
kwargs.update(self._bind_form_data())

return kwargs

def forms_valid(self, forms, form_name):
form_valid_method = '%s_form_valid' % form_name
if hasattr(self, form_valid_method):
return getattr(self, form_valid_method)(forms[form_name])
else:
return HttpResponseRedirect(self.get_success_url(form_name))

def forms_invalid(self, forms):
return self.render_to_response(self.get_context_data(forms=forms))

def get_initial(self, form_name):
initial_method = 'get_%s_initial' % form_name
if hasattr(self, initial_method):
return getattr(self, initial_method)()
else:
return self.initial.copy()

def get_prefix(self, form_name):
return self.prefixes.get(form_name, self.prefix)

def get_success_url(self, form_name=None):
return self.success_urls.get(form_name, self.success_url)

def _create_form(self, form_name, klass, bind_form):
form_kwargs = self.get_form_kwargs(form_name, bind_form)
form_create_method = 'create_%s_form' % form_name
if hasattr(self, form_create_method):
form = getattr(self, form_create_method)(**form_kwargs)
else:
form = klass(**form_kwargs)
return form

def _bind_form_data(self):
if self.request.method in ('POST', 'PUT'):
return{'data': self.request.POST,
'files': self.request.FILES,
}
return {}


class ProcessMultipleFormsView(ProcessFormView):

def get(self, request, *args, **kwargs):
form_classes = self.get_form_classes()
forms = self.get_forms(form_classes)
return self.render_to_response(self.get_context_data(forms=forms))

def post(self, request, *args, **kwargs):
form_classes = self.get_form_classes()
form_name = request.POST.get('action')
if self._individual_exists(form_name):
return self._process_individual_form(form_name, form_classes)
elif self._group_exists(form_name):
return self._process_grouped_forms(form_name, form_classes)
else:
return self._process_all_forms(form_classes)

def _individual_exists(self, form_name):
return form_name in self.form_classes

def _group_exists(self, group_name):
return group_name in self.grouped_forms

def _process_individual_form(self, form_name, form_classes):
forms = self.get_forms(form_classes, (form_name,))
form = forms.get(form_name)
if not form:
return HttpResponseForbidden()
elif form.is_valid():
return self.forms_valid(forms, form_name)
else:
return self.forms_invalid(forms)

def _process_grouped_forms(self, group_name, form_classes):
form_names = self.grouped_forms[group_name]
forms = self.get_forms(form_classes, form_names)
if all([forms.get(form_name).is_valid() for form_name in form_names.values()]):
return self.forms_valid(forms)
else:
return self.forms_invalid(forms)

def _process_all_forms(self, form_classes):
forms = self.get_forms(form_classes, None, True)
if all([form.is_valid() for form in forms.values()]):
return self.forms_valid(forms)
else:
return self.forms_invalid(forms)


class BaseMultipleFormsView(MultiFormMixin, ProcessMultipleFormsView):
"""
A base view for displaying several forms.
"""


class MultiFormsView(TemplateResponseMixin, BaseMultipleFormsView):
"""
A view for displaying several forms, and rendering a template response.
"""
12 changes: 9 additions & 3 deletions tavern/signals.py
Expand Up @@ -6,11 +6,19 @@
from .models import TavernGroup, Event


def create_group_permission(sender, instance, **kwargs):
remove_perm('change_taverngroup', instance.creator, instance)
remove_perm('delete_taverngroup', instance.creator, instance)
assign_perm('change_taverngroup', instance.creator, instance)
assign_perm('delete_taverngroup', instance.creator, instance)


def create_event_permission(sender, instance, created, **kwargs):
remove_perm('change_event', instance.creator, instance)
remove_perm('delete_event', instance.creator, instance)
remove_perm('change_event', instance.group.creator, instance)
remove_perm('delete_event', instance.group.creator, instance)

assign_perm('change_event', instance.creator, instance)
assign_perm('delete_event', instance.creator, instance)
assign_perm('change_event', instance.group.creator, instance)
Expand All @@ -30,20 +38,17 @@ def create_group_permission_for_organizers(sender, instance, action, reverse, pk
for pk in instance._old_m2m:
user = User.objects.get(pk=pk)
remove_perm('change_taverngroup', user, instance)
remove_perm('delete_taverngroup', user, instance)
if action == 'post_add' and not reverse:
for pk in pk_set:
user = User.objects.get(pk=pk)
assign_perm('change_taverngroup', user, instance)
assign_perm('delete_taverngroup', user, instance)


def delete_group_permissions(sender, instance, **kwargs):
remove_perm('change_taverngroup', instance.creator, instance)
remove_perm('delete_taverngroup', instance.creator, instance)
for user in instance.organizers.all():
remove_perm('change_taverngroup', user, instance)
remove_perm('delete_taverngroup', user, instance)


def delete_event_permissions(sender, instance, **kwargs):
Expand All @@ -54,6 +59,7 @@ def delete_event_permissions(sender, instance, **kwargs):


post_save.connect(create_event_permission, sender=Event)
post_save.connect(create_group_permission, sender=TavernGroup)
pre_save.connect(group_pre_save, sender=TavernGroup)
m2m_changed.connect(create_group_permission_for_organizers, sender=TavernGroup.organizers.through)
pre_delete.connect(delete_group_permissions, sender=TavernGroup)
Expand Down
17 changes: 17 additions & 0 deletions tavern/templates/edit_organizers.html
@@ -0,0 +1,17 @@
{% extends "base.html" %}

{% block content %}
<h3>Add organizers</h3>
<form action="{% url 'edit_organizers' object.slug %}" method="post">
{% csrf_token %}
{{ forms.add.as_p }}
<button name="action" value="add" class="btn btn-default" type="submit">Add</button>
</form>
<hr />
<h3>Remove organizers</h3>
<form action="{% url 'edit_organizers' object.slug %}" method="post">
{% csrf_token %}
{{ forms.remove.as_p }}
<button name="action" value="remove" class="btn btn-danger" type="submit">Remove</button>
</form>
{% endblock content %}
24 changes: 23 additions & 1 deletion tavern/templates/event_details.html
Expand Up @@ -72,7 +72,29 @@ <h1> Event Attendees </h1>
{% if editable %}
{% get_obj_perms request.user for event as "event_perms" %}
{% if "change_event" in event_perms %}
<h3><a href="{% url 'tavern_event_update' event.slug %}">Edit Event</a></h3>
<a class="btn btn-default" href="{% url 'tavern_event_update' event.slug %}">Edit Event</a>
{% endif %}

{% if "delete_event" in event_perms %}
<div id="deleteEventModal" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">Are you sure?</h4>
</div>
<div class="modal-body">
<form action="{% url 'delete_event' event.slug %}" method="POST">
{% csrf_token %}
<button class="btn btn-default" type="submit">Yes</button>
<button class="btn btn-default" type="button" class="close" data-dismiss="modal">No</button>
</form>
</div>
<div class="modal-footer"></div>
</div>
</div>
</div>
<button class="btn btn-danger" data-toggle="modal" data-target="#deleteEventModal">Delete</button>
{% endif %}
{% endif %}
{% endblock content %}
Expand Down
25 changes: 24 additions & 1 deletion tavern/templates/group_details.html
Expand Up @@ -20,7 +20,30 @@ <h1> Recently Joined: {{ user.name }} </h1>
</ul>
{% get_obj_perms request.user for group as "group_perms" %}
{% if "change_taverngroup" in group_perms %}
<h3><a href="{% url 'tavern_group_update' group.slug %}">Edit Group</a></h3>
<a class="btn btn-default" href="{% url 'tavern_group_update' group.slug %}">Edit Group</a>
{% endif %}

{% if "delete_taverngroup" in group_perms %}
<a class="btn btn-default" href="{% url 'edit_organizers' group.slug %}">Add/Remove Organizers</a>
<div id="deleteGroupModal" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">Are you sure?</h4>
</div>
<div class="modal-body">
<form action="{% url 'delete_group' group.slug %}" method="POST">
{% csrf_token %}
<button class="btn btn-default" type="submit">Yes</button>
<button class="btn btn-default" type="button" class="close" data-dismiss="modal">No</button>
</form>
</div>
<div class="modal-footer"></div>
</div>
</div>
</div>
<button class="btn btn-danger" data-toggle="modal" data-target="#deleteGroupModal">Delete</button>
{% endif %}
{% include 'past_events.html' %}

Expand Down
13 changes: 11 additions & 2 deletions tavern/urls.py
Expand Up @@ -6,18 +6,27 @@
url(r'^$', views.index, name='index'),
url(r'^groups/(?P<slug>[\w-]+)/$',
views.group_details, name='tavern_group_details'),
url(r'^events/(?P<slug>[\w-]+)/$',
views.event_details, name='tavern_event_details'),
url(r'^create_group/',
views.create_group, name='tavern_create_group'),
url(r'^groups/(?P<slug>[\w-]+)/update',
views.tavern_group_update,
name='tavern_group_update'),
url(r'^groups/(?P<slug>[\w-]+)/delete',
views.group_delete,
name='delete_group'),
url(r'^groups/(?P<slug>[\w-]+)/edit_organizer',
views.edit_organizers,
name='edit_organizers'),
url(r'^events/(?P<slug>[\w-]+)/$',
views.event_details, name='tavern_event_details'),
url(r'^create_event/',
views.create_event, name='tavern_create_event'),
url(r'^events/(?P<slug>[\w-]+)/update',
views.tavern_event_update,
name='tavern_event_update'),
url(r'^events/(?P<slug>[\w-]+)/delete',
views.event_delete,
name='delete_event'),
url(r'^tavern_toggle_member', views.tavern_toggle_member,
name='tavern_toggle_member'),
url(r'^rsvp/(?P<event_id>\d+)/(?P<rsvp_status>\w+)/',
Expand Down

0 comments on commit 03c42ed

Please sign in to comment.