workshop attendee: subscription
This commit is contained in:
parent
71103d5f6b
commit
483a794d23
|
@ -29,9 +29,13 @@
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if conference.subscriptions_open %}
|
||||||
|
<li{% block subscriptiontab %}{% endblock %}><a href="{% url 'subscriptions-list' %}"><span class="glyphicon glyphicon-check"></span> {% 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>
|
<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 %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% block navbar-left %}{% endblock %}
|
{% block navbar-left %}{% endblock %}
|
||||||
|
@ -51,6 +55,12 @@
|
||||||
<li role="presentation">
|
<li role="presentation">
|
||||||
<a role="menuitem" tabindex="-1" href="{% url 'list-volunteers' %}"><span class="glyphicon glyphicon-thumbs-up"></span> {% trans "Volunteers" %}</a>
|
<a role="menuitem" tabindex="-1" href="{% url 'list-volunteers' %}"><span class="glyphicon glyphicon-thumbs-up"></span> {% trans "Volunteers" %}</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li role="presentation">
|
||||||
|
<a role="menuitem" tabindex="-1" href="{% url 'list-topics' %}"><span class="glyphicon glyphicon-tag"></span> {% trans "Topics" %}</a></li>
|
||||||
|
</li>
|
||||||
|
<li role="presentation">
|
||||||
|
<a role="menuitem" tabindex="-1" href="{% url 'list-tracks' %}"><span class="glyphicon glyphicon-screenshot"></span> {% trans "Tracks" %}</a></li>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li class="dropdown{% block planningtab %}{% endblock %}">
|
<li class="dropdown{% block planningtab %}{% endblock %}">
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.sites.shortcuts import get_current_site
|
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 planning.models import Room
|
||||||
|
|
||||||
from ponyconf.admin import SiteAdminMixin
|
from ponyconf.admin import SiteAdminMixin
|
||||||
|
@ -35,8 +35,13 @@ class EventAdmin(SiteAdminMixin, admin.ModelAdmin):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class AttendeeAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('get_name', 'get_email')
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Conference)
|
admin.site.register(Conference)
|
||||||
admin.site.register(Topic, TopicAdmin)
|
admin.site.register(Topic, TopicAdmin)
|
||||||
admin.site.register(Track, TrackAdmin)
|
admin.site.register(Track, TrackAdmin)
|
||||||
admin.site.register(Talk, TalkAdmin)
|
admin.site.register(Talk, TalkAdmin)
|
||||||
admin.site.register(Event, EventAdmin)
|
admin.site.register(Event, EventAdmin)
|
||||||
|
admin.site.register(Attendee, AttendeeAdmin)
|
||||||
|
|
|
@ -179,6 +179,18 @@ class TrackForm(forms.ModelForm):
|
||||||
return name
|
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,
|
ConferenceForm = modelform_factory(Conference,
|
||||||
fields=['cfp_opening_date', 'cfp_closing_date', 'subscriptions_open', 'venue', 'city', 'home'],
|
fields=['cfp_opening_date', 'cfp_closing_date', 'subscriptions_open', 'venue', 'city', 'home'],
|
||||||
widgets={
|
widgets={
|
||||||
|
|
|
@ -112,16 +112,21 @@ class Attendee(PonyConfModel):
|
||||||
email = models.EmailField(blank=True, default="")
|
email = models.EmailField(blank=True, default="")
|
||||||
|
|
||||||
def get_name(self):
|
def get_name(self):
|
||||||
if user:
|
if self.user:
|
||||||
return str(user.profile)
|
return str(self.user.profile)
|
||||||
else:
|
else:
|
||||||
return name
|
return self.name
|
||||||
|
get_name.short_description = _('Name')
|
||||||
|
|
||||||
def get_email(self):
|
def get_email(self):
|
||||||
if user:
|
if self.user:
|
||||||
return user.email
|
return self.user.email
|
||||||
else:
|
else:
|
||||||
return self.email
|
return self.email
|
||||||
|
get_email.short_description = _('Email')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.get_name()
|
||||||
|
|
||||||
|
|
||||||
class Talk(PonyConfModel):
|
class Talk(PonyConfModel):
|
||||||
|
|
36
proposals/templates/proposals/subscriptions_list.html
Normal file
36
proposals/templates/proposals/subscriptions_list.html
Normal 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 %}
|
|
@ -48,6 +48,10 @@
|
||||||
{% else %}<em>{% trans "not defined" %}</em>
|
{% else %}<em>{% trans "not defined" %}</em>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</dd>
|
</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>
|
</dl>
|
||||||
|
|
||||||
|
@ -111,6 +115,19 @@
|
||||||
<a href="{% url 'decline-talk' talk.slug %}" class="btn btn-danger">Decline</a>
|
<a href="{% url 'decline-talk' talk.slug %}" class="btn btn-danger">Decline</a>
|
||||||
{% endif %}
|
{% 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>
|
<h3>{% trans "Messages" %}</h3>
|
||||||
{% trans "These messages are for organization team only." %}<br /><br />
|
{% trans "These messages are for organization team only." %}<br /><br />
|
||||||
{% for message in talk.conversation.messages.all %}
|
{% for message in talk.conversation.messages.all %}
|
||||||
|
|
23
proposals/templates/proposals/talk_subscribe.html
Normal file
23
proposals/templates/proposals/talk_subscribe.html
Normal 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 %}
|
|
@ -23,4 +23,6 @@ urlpatterns = [
|
||||||
url(r'^track/(?P<slug>[-\w]+)/edit/$', views.TrackUpdate.as_view(), name='edit-track'),
|
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'^speakers/$', views.speaker_list, name='list-speakers'),
|
||||||
url(r'^speaker/(?P<username>[\w.@+-]+)$', views.user_details, name='show-speaker'),
|
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'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -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.views.generic import CreateView, DetailView, ListView, UpdateView
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.views.decorators.http import require_http_methods
|
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
|
from ponyconf.mixins import OnSiteFormMixin
|
||||||
|
|
||||||
|
@ -25,8 +25,8 @@ from conversations.models import ConversationWithParticipant, ConversationAboutT
|
||||||
|
|
||||||
from planning.models import Room
|
from planning.models import Room
|
||||||
|
|
||||||
from .forms import TalkForm, TopicForm, TrackForm, ConferenceForm, TalkFilterForm, STATUS_VALUES, SpeakerFilterForm, TalkActionForm
|
from .forms import TalkForm, TopicForm, TrackForm, ConferenceForm, TalkFilterForm, STATUS_VALUES, SpeakerFilterForm, TalkActionForm, SubscribeForm
|
||||||
from .models import Talk, Track, Topic, Vote, Conference
|
from .models import Talk, Track, Topic, Vote, Conference, Attendee
|
||||||
from .signals import talk_added, talk_edited
|
from .signals import talk_added, talk_edited
|
||||||
from .utils import allowed_talks, markdown_to_html
|
from .utils import allowed_talks, markdown_to_html
|
||||||
|
|
||||||
|
@ -179,11 +179,11 @@ def talk_edit(request, talk=None):
|
||||||
if talk: # edit existing talk
|
if talk: # edit existing talk
|
||||||
talk = get_object_or_404(Talk, slug=talk, site=site)
|
talk = get_object_or_404(Talk, slug=talk, site=site)
|
||||||
if not talk.is_editable_by(request.user):
|
if not talk.is_editable_by(request.user):
|
||||||
raise PermissionDenied()
|
raise PermissionDenied
|
||||||
else: # add new talk
|
else: # add new talk
|
||||||
conf = Conference.objects.get(site=site)
|
conf = Conference.objects.get(site=site)
|
||||||
if not is_orga(request, request.user) and not conf.cfp_is_open():
|
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)
|
form = TalkForm(request.POST or None, instance=talk, site=site)
|
||||||
if talk:
|
if talk:
|
||||||
form.fields['topics'].disabled = True
|
form.fields['topics'].disabled = True
|
||||||
|
@ -225,7 +225,7 @@ def talk_edit(request, talk=None):
|
||||||
def talk_assign_to_track(request, talk, track):
|
def talk_assign_to_track(request, talk, track):
|
||||||
talk = get_object_or_404(Talk, slug=talk, site=get_current_site(request))
|
talk = get_object_or_404(Talk, slug=talk, site=get_current_site(request))
|
||||||
if not talk.is_moderable_by(request.user):
|
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))
|
track = get_object_or_404(Track, slug=track, site=get_current_site(request))
|
||||||
talk.track = track
|
talk.track = track
|
||||||
talk.save()
|
talk.save()
|
||||||
|
@ -294,7 +294,7 @@ class TrackUpdate(OrgaRequiredMixin, TrackMixin, TrackFormMixin, UpdateView):
|
||||||
def vote(request, talk, score):
|
def vote(request, talk, score):
|
||||||
talk = get_object_or_404(Talk, site=get_current_site(request), slug=talk)
|
talk = get_object_or_404(Talk, site=get_current_site(request), slug=talk)
|
||||||
if not talk.is_moderable_by(request.user):
|
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, created = Vote.objects.get_or_create(talk=talk, user=request.user)
|
||||||
vote.vote = int(score)
|
vote.vote = int(score)
|
||||||
vote.save()
|
vote.save()
|
||||||
|
@ -307,7 +307,7 @@ def talk_decide(request, talk, accepted):
|
||||||
site = get_current_site(request)
|
site = get_current_site(request)
|
||||||
talk = get_object_or_404(Talk, site=site, slug=talk)
|
talk = get_object_or_404(Talk, site=site, slug=talk)
|
||||||
if not talk.is_moderable_by(request.user):
|
if not talk.is_moderable_by(request.user):
|
||||||
raise PermissionDenied()
|
raise PermissionDenied
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
# Does we need to send a notification to the proposer?
|
# Does we need to send a notification to the proposer?
|
||||||
m = request.POST.get('message', '').strip()
|
m = request.POST.get('message', '').strip()
|
||||||
|
@ -401,3 +401,48 @@ def user_details(request, username):
|
||||||
'participation': participation,
|
'participation': participation,
|
||||||
'talk_list': allowed_talks(Talk.objects.filter(site=get_current_site(request), speakers=user), request),
|
'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,
|
||||||
|
})
|
||||||
|
|
Loading…
Reference in New Issue
Block a user