workshop attendee: subscription

This commit is contained in:
Élie Bouttier 2016-11-08 21:05:56 +01:00
parent 71103d5f6b
commit 483a794d23
9 changed files with 171 additions and 16 deletions

View File

@ -29,9 +29,13 @@
</li>
</ul>
</li>
{% endif %}
{% if conference.subscriptions_open %}
<li{% block subscriptiontab %}{% endblock %}><a href="{% url 'subscriptions-list' %}"><span class="glyphicon glyphicon-check"></span>&nbsp;{% trans "Subscribe to a workshop" %}</a></li>
{% endif %}
{% if request.user.is_authenticated %}
{% if not request|staff %}
<li{% block topictab %}{% endblock %}><a href="{% url 'list-topics' %}">{% trans "Topics" %}</a></li>
{% if request|staff %}
<li{% block tracktab %}{% endblock %}><a href="{% url 'list-tracks' %}">{% trans "Tracks" %}</a></li>
{% endif %}
{% endif %}
{% block navbar-left %}{% endblock %}
@ -51,6 +55,12 @@
<li role="presentation">
<a role="menuitem" tabindex="-1" href="{% url 'list-volunteers' %}"><span class="glyphicon glyphicon-thumbs-up"></span>&nbsp;{% trans "Volunteers" %}</a>
</li>
<li role="presentation">
<a role="menuitem" tabindex="-1" href="{% url 'list-topics' %}"><span class="glyphicon glyphicon-tag"></span>&nbsp;{% trans "Topics" %}</a></li>
</li>
<li role="presentation">
<a role="menuitem" tabindex="-1" href="{% url 'list-tracks' %}"><span class="glyphicon glyphicon-screenshot"></span>&nbsp;{% trans "Tracks" %}</a></li>
</li>
</ul>
</li>
<li class="dropdown{% block planningtab %}{% endblock %}">

View File

@ -1,7 +1,7 @@
from django.contrib import admin
from django.contrib.sites.shortcuts import get_current_site
from proposals.models import Conference, Talk, Topic, Track, Event
from proposals.models import Conference, Talk, Topic, Track, Event, Attendee
from planning.models import Room
from ponyconf.admin import SiteAdminMixin
@ -35,8 +35,13 @@ class EventAdmin(SiteAdminMixin, admin.ModelAdmin):
pass
class AttendeeAdmin(admin.ModelAdmin):
list_display = ('get_name', 'get_email')
admin.site.register(Conference)
admin.site.register(Topic, TopicAdmin)
admin.site.register(Track, TrackAdmin)
admin.site.register(Talk, TalkAdmin)
admin.site.register(Event, EventAdmin)
admin.site.register(Attendee, AttendeeAdmin)

View File

@ -179,6 +179,18 @@ class TrackForm(forms.ModelForm):
return name
class SubscribeForm(forms.Form):
email = forms.EmailField()
name = forms.CharField(max_length=128, label=_('Name or nickname'))
captcha = forms.IntegerField(label=_('How much is 3+4?'), help_text=_('Anti-bot'))
def clean_captcha(self):
value = self.cleaned_data['captcha']
if value != 7:
raise forms.ValidationError(_("Please re-do the maths."))
return value
ConferenceForm = modelform_factory(Conference,
fields=['cfp_opening_date', 'cfp_closing_date', 'subscriptions_open', 'venue', 'city', 'home'],
widgets={

View File

@ -112,16 +112,21 @@ class Attendee(PonyConfModel):
email = models.EmailField(blank=True, default="")
def get_name(self):
if user:
return str(user.profile)
if self.user:
return str(self.user.profile)
else:
return name
return self.name
get_name.short_description = _('Name')
def get_email(self):
if user:
return user.email
if self.user:
return self.user.email
else:
return self.email
get_email.short_description = _('Email')
def __str__(self):
return self.get_name()
class Talk(PonyConfModel):

View File

@ -0,0 +1,36 @@
{% extends 'base.html' %}
{% load accounts_tags i18n %}
{% block subscriptiontab %} class="active"{% endblock %}
{% block content %}
<h1>{% trans "Subscribe to a workshop" %}</h1>
{% for talk in talks %}
{% if forloop.first %}<div class="list-group">{% endif %}
<div class="list-group-item{% if attendee in talk.attendees.all %} list-group-item-info{% endif %}">
<h4 clas="list-group-item-heading">{{ talk.title }}</h4>
<p class="list-group-item-text">
<p>{{ talk.description }}</p>
{% if talk.attendees_limit %}
<p><em>{% blocktrans count remaining=talk.remaining_attendees %}{{ remaining }} remaining seat{% plural %}{{ remaining }} remaining seats{% endblocktrans %}</em></p>
{% endif %}
{% if talk.remaining_attendees != 0 or attendee in talk.attendees.all %}
<p>
{% if attendee in talk.attendees.all %}
<a class="btn btn-danger" href="{% url 'subscribe-to-talk' talk=talk.slug %}">{% trans "Unregister" %}</a>
{% else %}
<a class="btn btn-primary" href="{% url 'subscribe-to-talk' talk=talk.slug %}">{% trans "Register" %}</a>
{% endif %}
</p>
{% endif %}
</p>
</div>
{% if forloop.last %}</div>{% endif %}
{% empty %}
<em>{% trans "There are no workshops requiring registration for now … come back later!" %}</em>
{% endfor %}
{% endblock %}

View File

@ -48,6 +48,10 @@
{% else %}<em>{% trans "not defined" %}</em>
{% endif %}
</dd>
{% if talk.registration_required %}
<dt>{% trans "Registrations" %}</dt>
<dd>{% if talk.attendees_limit %}{{ talk.attendees.count }} / {{ talk.attendees_limit }}{% else %}{% trans "required but unlimited" %}{% endif %}</dd>
{% endif %}
</dl>
@ -111,6 +115,19 @@
<a href="{% url 'decline-talk' talk.slug %}" class="btn btn-danger">Decline</a>
{% endif %}
{% if talk.registration_required %}
<h3>{% trans "Attendees" %}</h3>
{% for attendee in talk.attendees.all %}
{% if forloop.first %}<ol>{% endif %}
<li><a href="mailto:{{ attendee.get_email }}">{{ attendee.get_name }}</a></li>
{% if forloop.last %}</ol>{% endif %}
{% empty %}
<em>{% trans "No attendees yet." %}</em>
{% endfor %}
{% endif %}
<h3>{% trans "Messages" %}</h3>
{% trans "These messages are for organization team only." %}<br /><br />
{% for message in talk.conversation.messages.all %}

View File

@ -0,0 +1,23 @@
{% extends 'base.html' %}
{% load bootstrap3 i18n %}
{% block subscriptiontab %} class="active"{% endblock %}
{% block css %}
{{ block.super }}
{{ form.media.css }}
{% endblock %}
{% block content %}
<h1>{% trans "Subscribe to a workshop" %}</h1>
{% include "_form.html" %}
{% endblock %}
{% block js_end %}
{{ block.super }}
{{ form.media.js }}
{% endblock %}

View File

@ -23,4 +23,6 @@ urlpatterns = [
url(r'^track/(?P<slug>[-\w]+)/edit/$', views.TrackUpdate.as_view(), name='edit-track'),
url(r'^speakers/$', views.speaker_list, name='list-speakers'),
url(r'^speaker/(?P<username>[\w.@+-]+)$', views.user_details, name='show-speaker'),
url(r'^subscribe/$', views.talk_subscriptions, name='subscriptions-list'),
url(r'^subscribe/(?P<talk>[-\w]+)$', views.talk_subscribe, name='subscribe-to-talk'),
]

View File

@ -12,7 +12,7 @@ from django.shortcuts import get_object_or_404, redirect, render
from django.views.generic import CreateView, DetailView, ListView, UpdateView
from django.utils.translation import ugettext as _
from django.views.decorators.http import require_http_methods
from django.http import HttpResponse
from django.http import HttpResponse, Http404
from ponyconf.mixins import OnSiteFormMixin
@ -25,8 +25,8 @@ from conversations.models import ConversationWithParticipant, ConversationAboutT
from planning.models import Room
from .forms import TalkForm, TopicForm, TrackForm, ConferenceForm, TalkFilterForm, STATUS_VALUES, SpeakerFilterForm, TalkActionForm
from .models import Talk, Track, Topic, Vote, Conference
from .forms import TalkForm, TopicForm, TrackForm, ConferenceForm, TalkFilterForm, STATUS_VALUES, SpeakerFilterForm, TalkActionForm, SubscribeForm
from .models import Talk, Track, Topic, Vote, Conference, Attendee
from .signals import talk_added, talk_edited
from .utils import allowed_talks, markdown_to_html
@ -179,11 +179,11 @@ def talk_edit(request, talk=None):
if talk: # edit existing talk
talk = get_object_or_404(Talk, slug=talk, site=site)
if not talk.is_editable_by(request.user):
raise PermissionDenied()
raise PermissionDenied
else: # add new talk
conf = Conference.objects.get(site=site)
if not is_orga(request, request.user) and not conf.cfp_is_open():
raise PermissionDenied()
raise PermissionDenied
form = TalkForm(request.POST or None, instance=talk, site=site)
if talk:
form.fields['topics'].disabled = True
@ -225,7 +225,7 @@ def talk_edit(request, talk=None):
def talk_assign_to_track(request, talk, track):
talk = get_object_or_404(Talk, slug=talk, site=get_current_site(request))
if not talk.is_moderable_by(request.user):
raise PermissionDenied()
raise PermissionDenied
track = get_object_or_404(Track, slug=track, site=get_current_site(request))
talk.track = track
talk.save()
@ -294,7 +294,7 @@ class TrackUpdate(OrgaRequiredMixin, TrackMixin, TrackFormMixin, UpdateView):
def vote(request, talk, score):
talk = get_object_or_404(Talk, site=get_current_site(request), slug=talk)
if not talk.is_moderable_by(request.user):
raise PermissionDenied()
raise PermissionDenied
vote, created = Vote.objects.get_or_create(talk=talk, user=request.user)
vote.vote = int(score)
vote.save()
@ -307,7 +307,7 @@ def talk_decide(request, talk, accepted):
site = get_current_site(request)
talk = get_object_or_404(Talk, site=site, slug=talk)
if not talk.is_moderable_by(request.user):
raise PermissionDenied()
raise PermissionDenied
if request.method == 'POST':
# Does we need to send a notification to the proposer?
m = request.POST.get('message', '').strip()
@ -401,3 +401,48 @@ def user_details(request, username):
'participation': participation,
'talk_list': allowed_talks(Talk.objects.filter(site=get_current_site(request), speakers=user), request),
})
def talk_subscriptions(request):
site = get_current_site(request)
if not Conference.objects.get(site=site).subscriptions_open:
raise Http404
talks = Talk.objects.filter(site=site, registration_required=True)
if request.user.is_authenticated():
attendee = Attendee.objects.filter(user=request.user).first() # None if it does not exists
else:
attendee = None
return render(request, 'proposals/subscriptions_list.html', {
'talks': talks,
'attendee': attendee,
})
def talk_subscribe(request, talk):
talk = get_object_or_404(Talk, site=get_current_site(request), registration_required=True, slug=talk)
form = SubscribeForm(request.POST or None)
if request.user.is_authenticated() or (request.method == 'POST' and form.is_valid()):
if request.user.is_authenticated():
attendee, created = Attendee.objects.get_or_create(user=request.user)
else:
attendee, created = Attendee.objects.get_or_create(email=form.cleaned_data['email'], name=form.cleaned_data['name'])
if attendee in talk.attendees.all():
if request.user.is_authenticated():
talk.attendees.remove(attendee)
messages.success(request, _("Unregistered :-("))
else:
messages.error(request, _("Already registered!"))
elif talk.remaining_attendees == 0:
raise PermissionDenied
else:
talk.attendees.add(attendee)
messages.success(request, _("Registered!"))
talk.save()
return redirect('subscriptions-list')
return render(request, 'proposals/talk_subscribe.html', {
'talk': talk,
'form': form,
})