link participation to user account
This commit is contained in:
parent
bac3953763
commit
0565a9f217
|
@ -11,9 +11,12 @@ from cfp.models import Participant
|
|||
def speaker_required(view_func):
|
||||
def wrapped_view(request, **kwargs):
|
||||
speaker_token = kwargs.pop('speaker_token')
|
||||
# TODO v3: if no speaker token is provided, we should check for a logged user, and if so,
|
||||
# we should check if his/her participating at current conference
|
||||
if speaker_token:
|
||||
speaker = get_object_or_404(Participant, site=request.conference.site, token=speaker_token)
|
||||
elif request.user.is_authenticated():
|
||||
speaker = get_object_or_404(Participant, site=request.conference.site, email=request.user.email)
|
||||
else:
|
||||
raise PermissionDenied
|
||||
kwargs['speaker'] = speaker
|
||||
return view_func(request, **kwargs)
|
||||
return wraps(view_func)(wrapped_view)
|
||||
|
|
21
cfp/forms.py
21
cfp/forms.py
|
@ -195,22 +195,12 @@ class TalkActionForm(forms.Form):
|
|||
self.fields['room'].choices = [(None, "---------")] + list(rooms.values_list('slug', 'name'))
|
||||
|
||||
|
||||
class ParticipantForm(OnSiteNamedModelForm):
|
||||
class NotifyForm(forms.Form):
|
||||
notify = forms.BooleanField(initial=True, required=False, label=_('Notify by mail?'))
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
social = kwargs.pop('social', True)
|
||||
ask_notify = kwargs.pop('ask_notify', False)
|
||||
super().__init__(*args, **kwargs)
|
||||
if not social:
|
||||
for field in ['twitter', 'linkedin', 'github', 'website', 'facebook', 'mastodon']:
|
||||
self.fields.pop(field)
|
||||
if not ask_notify:
|
||||
self.fields.pop('notify')
|
||||
|
||||
class Meta:
|
||||
model = Participant
|
||||
fields = ['name', 'email', 'biography', 'twitter', 'linkedin', 'github', 'website', 'facebook', 'mastodon']
|
||||
class ParticipantForm(OnSiteNamedModelForm):
|
||||
SOCIAL_FIELDS = ['twitter', 'linkedin', 'github', 'website', 'facebook', 'mastodon']
|
||||
|
||||
def clean_email(self):
|
||||
email = self.cleaned_data['email']
|
||||
|
@ -220,11 +210,6 @@ class ParticipantForm(OnSiteNamedModelForm):
|
|||
return email
|
||||
|
||||
|
||||
class ParticipantStaffForm(ParticipantForm):
|
||||
class Meta(ParticipantForm.Meta):
|
||||
fields = ['name', 'vip', 'email', 'phone_number', 'notes'] + ParticipantForm.Meta.fields[3:]
|
||||
|
||||
|
||||
class ParticipantFilterForm(forms.Form):
|
||||
category = forms.MultipleChoiceField(
|
||||
label=_('Category'),
|
||||
|
|
|
@ -115,6 +115,10 @@ class Participant(PonyConfModel):
|
|||
|
||||
objects = ParticipantManager()
|
||||
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('participant-details', kwargs=dict(participant_id=self.token))
|
||||
|
||||
def get_secret_url(self, full=False):
|
||||
url = reverse('proposal-dashboard', kwargs={'speaker_token': self.token})
|
||||
if full:
|
||||
|
|
|
@ -15,11 +15,13 @@
|
|||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{% if not request.user.is_authenticated %}
|
||||
<div class="col-md-8 col-md-offset-2 alert alert-info">
|
||||
<span class="glyphicon glyphicon-exclamation-sign"></span>
|
||||
{% url 'proposal-mail-token' as mail_token_url %}
|
||||
{% blocktrans %}If you already have submitted a talk and you want to edit it or submit another one, please click <a href="{{ mail_token_url }}">here</a>.{% endblocktrans %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<form method="POST" class="form-horizontal col-md-8 col-md-offset-2">
|
||||
{% csrf_token %}
|
||||
{{ speaker_form|crispy }}
|
||||
|
|
|
@ -42,7 +42,8 @@
|
|||
{% endif %}
|
||||
<form method="POST" class="form-horizontal col-md-8 col-md-offset-2">
|
||||
{% csrf_token %}
|
||||
{{ form|crispy }}
|
||||
{{ speaker_form|crispy }}
|
||||
{% if notify_form %}{{ notify_form|crispy }}{% endif %}
|
||||
<div class="col-md-12 text-center">
|
||||
<button type="submit" class="btn btn-primary text-center">{% trans "Save" %} <i class="fa fa-check"></i></button>
|
||||
</div>
|
||||
|
|
25
cfp/urls.py
25
cfp/urls.py
|
@ -7,18 +7,19 @@ urlpatterns = [
|
|||
# v1.1
|
||||
url(r'^cfp/$', views.proposal_home, name='proposal-home'),
|
||||
url(r'^cfp/token/$', views.proposal_mail_token, name='proposal-mail-token'),
|
||||
url(r'^cfp/(?P<speaker_token>[\w\-]+)/$', views.proposal_dashboard, name='proposal-dashboard'),
|
||||
url(r'^cfp/(?P<speaker_token>[\w\-]+)/profile/$', views.proposal_speaker_edit, name='proposal-profile-edit'),
|
||||
url(r'^cfp/(?P<speaker_token>[\w\-]+)/talk/add/$', views.proposal_talk_edit, name='proposal-talk-add'),
|
||||
url(r'^cfp/(?P<speaker_token>[\w\-]+)/talk/(?P<talk_id>[0-9]+)/$', views.proposal_talk_details, name='proposal-talk-details'),
|
||||
url(r'^cfp/(?P<speaker_token>[\w\-]+)/talk/(?P<talk_id>[0-9]+)/edit/$', views.proposal_talk_edit, name='proposal-talk-edit'),
|
||||
url(r'^cfp/(?P<speaker_token>[\w\-]+)/talk/(?P<talk_id>[0-9]+)/speaker/add/$', views.proposal_speaker_edit, name='proposal-speaker-add'),
|
||||
url(r'^cfp/(?P<speaker_token>[\w\-]+)/talk/(?P<talk_id>[0-9]+)/speaker/add/(?P<speaker_id>[0-9]+)/$', views.proposal_speaker_add, name='proposal-speaker-add-existing'),
|
||||
#url(r'^cfp/(?P<speaker_token>[\w\-]+)/talk/(?P<talk_id>[0-9]+)/speaker/(?P<co_speaker_id>[0-9]+)/$', views.proposal_speaker_details, name='proposal-speaker-details'),
|
||||
url(r'^cfp/(?P<speaker_token>[\w\-]+)/talk/(?P<talk_id>[0-9]+)/speaker/(?P<co_speaker_id>[0-9]+)/edit/$', views.proposal_speaker_edit, name='proposal-speaker-edit'),
|
||||
url(r'^cfp/(?P<speaker_token>[\w\-]+)/talk/(?P<talk_id>[0-9]+)/speaker/(?P<co_speaker_id>[0-9]+)/remove/$', views.proposal_speaker_remove, name='proposal-speaker-remove'),
|
||||
url(r'^cfp/(?P<speaker_token>[\w\-]+)/talk/(?P<talk_id>[0-9]+)/confirm/$', views.proposal_talk_acknowledgment, {'confirm': True}, name='proposal-talk-confirm'),
|
||||
url(r'^cfp/(?P<speaker_token>[\w\-]+)/talk/(?P<talk_id>[0-9]+)/desist/$', views.proposal_talk_acknowledgment, {'confirm': False}, name='proposal-talk-desist'),
|
||||
url(r'^cfp/(?P<speaker_token>[\w\-]+)/$', views.proposal_dashboard), # backward compatibility
|
||||
url(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?dashboard/$', views.proposal_dashboard, name='proposal-dashboard'),
|
||||
url(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?profile/$', views.proposal_speaker_edit, name='proposal-profile-edit'),
|
||||
url(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?talk/add/$', views.proposal_talk_edit, name='proposal-talk-add'),
|
||||
url(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?talk/(?P<talk_id>[0-9]+)/$', views.proposal_talk_details, name='proposal-talk-details'),
|
||||
url(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?talk/(?P<talk_id>[0-9]+)/edit/$', views.proposal_talk_edit, name='proposal-talk-edit'),
|
||||
url(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?talk/(?P<talk_id>[0-9]+)/speaker/add/$', views.proposal_speaker_edit, name='proposal-speaker-add'),
|
||||
url(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?talk/(?P<talk_id>[0-9]+)/speaker/add/(?P<speaker_id>[0-9]+)/$', views.proposal_speaker_add, name='proposal-speaker-add-existing'),
|
||||
#url(r'^cfp(?:/(?P<speaker_token>[\w\-]+))?/talk/(?P<talk_id>[0-9]+)/speaker/(?P<co_speaker_id>[0-9]+)/$', views.proposal_speaker_details, name='proposal-speaker-details'),
|
||||
url(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?talk/(?P<talk_id>[0-9]+)/speaker/(?P<co_speaker_id>[0-9]+)/edit/$', views.proposal_speaker_edit, name='proposal-speaker-edit'),
|
||||
url(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?talk/(?P<talk_id>[0-9]+)/speaker/(?P<co_speaker_id>[0-9]+)/remove/$', views.proposal_speaker_remove, name='proposal-speaker-remove'),
|
||||
url(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?talk/(?P<talk_id>[0-9]+)/confirm/$', views.proposal_talk_acknowledgment, {'confirm': True}, name='proposal-talk-confirm'),
|
||||
url(r'^cfp/(?:(?P<speaker_token>[\w\-]+)/)?talk/(?P<talk_id>[0-9]+)/desist/$', views.proposal_talk_acknowledgment, {'confirm': False}, name='proposal-talk-desist'),
|
||||
# Backward compatibility
|
||||
url(r'^cfp/(?P<talk_id>[\w\-]+)/speaker/add/$', views.talk_proposal_speaker_edit, name='talk-proposal-speaker-add'),
|
||||
url(r'^cfp/(?P<talk_id>[\w\-]+)/speaker/(?P<participant_id>[\w\-]+)/$', views.talk_proposal_speaker_edit, name='talk-proposal-speaker-edit'),
|
||||
|
|
51
cfp/views.py
51
cfp/views.py
|
@ -12,6 +12,7 @@ from django.http import HttpResponse, Http404
|
|||
from django.utils import timezone
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.core.mail import send_mail
|
||||
from django.forms import modelform_factory
|
||||
|
||||
from django_select2.views import AutoResponseView
|
||||
|
||||
|
@ -25,7 +26,7 @@ from .mixins import StaffRequiredMixin, OnSiteMixin, OnSiteFormMixin
|
|||
from .utils import is_staff
|
||||
from .models import Participant, Talk, TalkCategory, Vote, Track, Tag, Room, Volunteer, Activity
|
||||
from .forms import TalkForm, TalkStaffForm, TalkFilterForm, TalkActionForm, \
|
||||
ParticipantForm, ParticipantStaffForm, ParticipantFilterForm, \
|
||||
ParticipantForm, ParticipantFilterForm, NotifyForm, \
|
||||
ConferenceForm, CreateUserForm, TrackForm, RoomForm, \
|
||||
VolunteerForm, VolunteerFilterForm, MailForm, \
|
||||
ACCEPTATION_VALUES, CONFIRMATION_VALUES
|
||||
|
@ -139,17 +140,29 @@ def volunteer_details(request, volunteer_id):
|
|||
|
||||
|
||||
def proposal_home(request):
|
||||
if is_staff(request, request.user):
|
||||
categories = TalkCategory.objects.filter(site=request.conference.site)
|
||||
else:
|
||||
categories = request.conference.opened_categories
|
||||
if not categories.exists():
|
||||
return render(request, 'cfp/closed.html')
|
||||
speaker_form = ParticipantForm(request.POST or None, conference=request.conference, social=False)
|
||||
if request.user.is_authenticated():
|
||||
if Participant.objects.filter(site=request.conference.site, email=request.user.email).exists():
|
||||
return redirect(reverse('proposal-dashboard'))
|
||||
else:
|
||||
NewSpeakerForm = modelform_factory(Participant, form=ParticipantForm, fields=['name', 'biography'])
|
||||
if request.POST:
|
||||
data = request.POST
|
||||
else:
|
||||
# TODO: import biography from User profile
|
||||
data = dict(name=request.user.get_full_name())
|
||||
else:
|
||||
NewSpeakerForm = modelform_factory(Participant, form=ParticipantForm, fields=['name', 'email', 'biography'])
|
||||
data = request.POST or None
|
||||
speaker_form = NewSpeakerForm(data, conference=request.conference)
|
||||
talk_form = TalkForm(request.POST or None, categories=categories)
|
||||
if request.method == 'POST' and all(map(lambda f: f.is_valid(), [speaker_form, talk_form])):
|
||||
speaker = speaker_form.save(commit=False)
|
||||
speaker.site = request.conference.site
|
||||
if request.user.is_authenticated():
|
||||
speaker.email = request.user.email
|
||||
speaker.save()
|
||||
talk = talk_form.save(commit=False)
|
||||
talk.site = request.conference.site
|
||||
|
@ -328,16 +341,20 @@ def proposal_speaker_edit(request, speaker, talk_id=None, co_speaker_id=None):
|
|||
co_speaker = get_object_or_404(Participant, site=request.conference.site, talk__pk=talk.pk, pk=co_speaker_id)
|
||||
else:
|
||||
co_speaker_candidates = speaker.co_speaker_set.exclude(pk__in=talk.speakers.values_list('pk'))
|
||||
form = ParticipantForm(request.POST or None, conference=request.conference,
|
||||
instance=co_speaker if talk else speaker, ask_notify=talk and not co_speaker)
|
||||
if request.method == 'POST' and form.is_valid():
|
||||
edited_speaker = form.save()
|
||||
EditSpeakerForm = modelform_factory(Participant, form=ParticipantForm, fields=['name', 'email', 'biography'] + ParticipantForm.SOCIAL_FIELDS)
|
||||
speaker_form = EditSpeakerForm(request.POST or None, conference=request.conference, instance=co_speaker if talk else speaker)
|
||||
if talk and not co_speaker_id:
|
||||
notify_form = NotifyForm(request.POST or None)
|
||||
else:
|
||||
notify_form = None
|
||||
if request.method == 'POST' and all(map(lambda f: f.is_valid(), [speaker_form, notify_form])):
|
||||
edited_speaker = speaker_form.save()
|
||||
if talk:
|
||||
talk.speakers.add(edited_speaker)
|
||||
if co_speaker_id:
|
||||
messages.success(request, _('Changes saved.'))
|
||||
else:
|
||||
if form.cleaned_data['notify']:
|
||||
if notify_form.cleaned_data['notify']:
|
||||
base_url = ('https' if request.is_secure() else 'http') + '://' + request.conference.site.domain
|
||||
url_dashboard = base_url + reverse('proposal-dashboard', kwargs=dict(speaker_token=edited_speaker.token))
|
||||
url_talk_details = base_url + reverse('proposal-talk-details', kwargs=dict(speaker_token=edited_speaker.token, talk_id=talk.pk))
|
||||
|
@ -383,7 +400,8 @@ Thanks!
|
|||
'talk': talk,
|
||||
'co_speaker': co_speaker,
|
||||
'co_speaker_candidates': co_speaker_candidates,
|
||||
'form': form,
|
||||
'speaker_form': speaker_form,
|
||||
'notify_form': notify_form,
|
||||
})
|
||||
|
||||
|
||||
|
@ -697,13 +715,20 @@ def participant_details(request, participant_id):
|
|||
})
|
||||
|
||||
|
||||
class ParticipantUpdate(StaffRequiredMixin, OnSiteMixin, UpdateView):
|
||||
class ParticipantUpdate(StaffRequiredMixin, OnSiteFormMixin, UpdateView):
|
||||
model = Participant
|
||||
slug_field = 'token'
|
||||
slug_url_kwarg = 'participant_id'
|
||||
form_class = ParticipantStaffForm
|
||||
#form_class = ParticipantStaffForm
|
||||
template_name = 'cfp/staff/participant_form.html'
|
||||
|
||||
def get_form_class(self):
|
||||
return modelform_factory(
|
||||
self.model,
|
||||
form=ParticipantForm,
|
||||
fields=['name', 'vip', 'email', 'phone_number', 'notes'] + ParticipantForm.SOCIAL_FIELDS,
|
||||
)
|
||||
|
||||
|
||||
@staff_required
|
||||
def conference_edit(request):
|
||||
|
|
Loading…
Reference in New Issue
Block a user