From 1f5377f38ddcbdd845c94284c4b1ecebf529d786 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89lie=20Bouttier?= Date: Sat, 4 Nov 2017 15:30:00 +0100 Subject: [PATCH 1/7] major overhaul of proposal process --- cfp/decorators.py | 17 +- cfp/forms.py | 70 +- cfp/migrations/0018_auto_20171104_1227.py | 25 + cfp/models.py | 11 +- cfp/templates/cfp/closed.html | 15 - cfp/templates/cfp/complete.html | 27 - cfp/templates/cfp/proposal_dashboard.html | 77 +++ cfp/templates/cfp/proposal_home.html | 33 + cfp/templates/cfp/proposal_mail_token.html | 30 + cfp/templates/cfp/proposal_speaker_form.html | 42 ++ cfp/templates/cfp/proposal_talk_details.html | 86 +++ .../{propose.html => proposal_talk_form.html} | 12 +- cfp/templates/cfp/speaker.html | 26 - cfp/templatetags/cfp_tags.py | 5 + cfp/urls.py | 19 +- cfp/views.py | 319 ++++++--- locale/fr/LC_MESSAGES/django.mo | Bin 17631 -> 21304 bytes locale/fr/LC_MESSAGES/django.po | 604 ++++++++++++------ ponyconf/templates/base.html | 2 +- 19 files changed, 1022 insertions(+), 398 deletions(-) create mode 100644 cfp/migrations/0018_auto_20171104_1227.py delete mode 100644 cfp/templates/cfp/closed.html delete mode 100644 cfp/templates/cfp/complete.html create mode 100644 cfp/templates/cfp/proposal_dashboard.html create mode 100644 cfp/templates/cfp/proposal_home.html create mode 100644 cfp/templates/cfp/proposal_mail_token.html create mode 100644 cfp/templates/cfp/proposal_speaker_form.html create mode 100644 cfp/templates/cfp/proposal_talk_details.html rename cfp/templates/cfp/{propose.html => proposal_talk_form.html} (61%) delete mode 100644 cfp/templates/cfp/speaker.html diff --git a/cfp/decorators.py b/cfp/decorators.py index a5ca0ac..40964bc 100644 --- a/cfp/decorators.py +++ b/cfp/decorators.py @@ -1,9 +1,22 @@ -from functools import wraps - from django.core.exceptions import PermissionDenied from django.contrib.auth.decorators import login_required +from django.shortcuts import get_object_or_404 + +from functools import wraps from cfp.utils import is_staff +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 + speaker = get_object_or_404(Participant, site=request.conference.site, token=speaker_token) + kwargs['speaker'] = speaker + return view_func(request, **kwargs) + return wraps(view_func)(wrapped_view) def staff_required(view_func): diff --git a/cfp/forms.py b/cfp/forms.py index b0bef9e..a2bc667 100644 --- a/cfp/forms.py +++ b/cfp/forms.py @@ -36,6 +36,27 @@ CONFIRMATION_VALUES = [ ] +class OnSiteNamedModelForm(forms.ModelForm): + def __init__(self, *args, **kwargs): + self.conference = kwargs.pop('conference') + super().__init__(*args, **kwargs) + + # we should manually check (site, name) uniqueness as the site is not part of the form + def clean_name(self): + name = self.cleaned_data['name'] + if (not self.instance or self.instance.name != name) \ + and self._meta.model.objects.filter(site=self.conference.site, name=name).exists(): + raise self.instance.unique_error_message(self._meta.model, ['name']) + return name + + def save(self, commit=True): + obj = super().save(commit=False) + obj.site = self.conference.site + if commit: + obj.save() + return obj + + class VolunteerFilterForm(forms.Form): activity = forms.MultipleChoiceField( label=_('Activity'), @@ -174,15 +195,29 @@ class TalkActionForm(forms.Form): self.fields['room'].choices = [(None, "---------")] + list(rooms.values_list('slug', 'name')) -ParticipantForm = modelform_factory(Participant, fields=('name', 'email', 'biography')) +class ParticipantForm(OnSiteNamedModelForm): + def __init__(self, *args, **kwargs): + social = kwargs.pop('social', True) + super().__init__(*args, **kwargs) + if not social: + for field in ['twitter', 'linkedin', 'github', 'website', 'facebook', 'mastodon']: + self.fields.pop(field) + + class Meta: + model = Participant + fields = ['name', 'email', 'biography', 'twitter', 'linkedin', 'github', 'website', 'facebook', 'mastodon'] + + def clean_email(self): + email = self.cleaned_data['email'] + if (not self.instance or self.instance.email != email) \ + and self._meta.model.objects.filter(site=self.conference.site, email=email).exists(): + raise self.instance.unique_error_message(self._meta.model, ['email']) + return email class ParticipantStaffForm(ParticipantForm): class Meta(ParticipantForm.Meta): - fields = ('name', 'vip', 'email', 'biography') - labels = { - 'name': _('Name'), - } + fields = ['name', 'vip', 'email', 'phone_number', 'notes'] + ParticipantForm.Meta.fields[3:] class ParticipantFilterForm(forms.Form): @@ -220,6 +255,10 @@ class ParticipantFilterForm(forms.Form): self.fields['track'].choices = [('none', _('Not assigned'))] + list(tracks.values_list('slug', 'name')) +class MailForm(forms.Form): + email = forms.EmailField(required=True, label=_('Email')) + + class UsersWidget(ModelSelect2MultipleWidget): model = User search_fields = [ '%s__icontains' % field for field in UserAdmin.search_fields ] @@ -273,27 +312,6 @@ class CreateUserForm(forms.ModelForm): return user -class OnSiteNamedModelForm(forms.ModelForm): - def __init__(self, *args, **kwargs): - self.conference = kwargs.pop('conference') - super().__init__(*args, **kwargs) - - # we should manually check (site, name) uniqueness as the site is not part of the form - def clean_name(self): - name = self.cleaned_data['name'] - if (not self.instance or self.instance.name != name) \ - and self._meta.model.objects.filter(site=self.conference.site, name=name).exists(): - raise self.instance.unique_error_message(self._meta.model, ['name']) - return name - - def save(self, commit=True): - obj = super().save(commit=False) - obj.site = self.conference.site - if commit: - obj.save() - return obj - - class TrackForm(OnSiteNamedModelForm): class Meta: model = Track diff --git a/cfp/migrations/0018_auto_20171104_1227.py b/cfp/migrations/0018_auto_20171104_1227.py new file mode 100644 index 0000000..7e9884b --- /dev/null +++ b/cfp/migrations/0018_auto_20171104_1227.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2017-11-04 12:27 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('cfp', '0017_auto_20171103_1922'), + ] + + operations = [ + migrations.AddField( + model_name='conference', + name='acceptances_disclosure_date', + field=models.DateTimeField(blank=True, default=None, null=True, verbose_name='Acceptances disclosure date'), + ), + migrations.AlterField( + model_name='participant', + name='name', + field=models.CharField(max_length=128, verbose_name='Name'), + ), + ] diff --git a/cfp/models.py b/cfp/models.py index 09090eb..f9c8ff8 100644 --- a/cfp/models.py +++ b/cfp/models.py @@ -34,6 +34,7 @@ class Conference(models.Model): reply_email = models.CharField(max_length=100, blank=True, verbose_name=_('Reply email')) staff = models.ManyToManyField(User, blank=True, verbose_name=_('Staff members')) secure_domain = models.BooleanField(default=True, verbose_name=_('Secure domain (HTTPS)')) + acceptances_disclosure_date = models.DateTimeField(null=True, blank=True, default=None, verbose_name=_('Acceptances disclosure date')) schedule_publishing_date = models.DateTimeField(null=True, blank=True, default=None, verbose_name=_('Schedule publishing date')) schedule_redirection_url = models.URLField(blank=True, default='', verbose_name=_('Schedule redirection URL'), help_text=_('If specified, schedule tab will redirect to this URL.')) @@ -56,6 +57,11 @@ class Conference(models.Model): .filter(Q(opening_date__isnull=True) | Q(opening_date__lte=now))\ .filter(Q(closing_date__isnull=True) | Q(closing_date__gte=now)) + @property + def disclosed_acceptances(self): + # acceptances are automatically disclosed if the schedule is published + return self.acceptances_disclosure_date and self.acceptances_disclosure_date <= timezone.now() or self.schedule_available + @property def schedule_available(self): return self.schedule_publishing_date and self.schedule_publishing_date <= timezone.now() @@ -90,7 +96,7 @@ class ParticipantManager(models.Manager): class Participant(PonyConfModel): site = models.ForeignKey(Site, on_delete=models.CASCADE) - name = models.CharField(max_length=128, verbose_name=_('Your Name')) + name = models.CharField(max_length=128, verbose_name=_('Name')) email = models.EmailField() biography = models.TextField(verbose_name=_('Biography')) token = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) @@ -110,10 +116,11 @@ class Participant(PonyConfModel): objects = ParticipantManager() def get_absolute_url(self): - return reverse('participant-details', kwargs={'participant_id': self.token}) + return reverse('proposal-dashboard', kwargs={'speaker_token': self.token}) class Meta: # A User can participe only once to a Conference (= Site) + unique_together = ('site', 'name') unique_together = ('site', 'email') def __str__(self): diff --git a/cfp/templates/cfp/closed.html b/cfp/templates/cfp/closed.html deleted file mode 100644 index 792703c..0000000 --- a/cfp/templates/cfp/closed.html +++ /dev/null @@ -1,15 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} - -{% block proposetab %} class="active"{% endblock %} - -{% block content %} - - -

{% trans "Sorry, the Call for Participation is closed!" %}

- -{% endblock %} diff --git a/cfp/templates/cfp/complete.html b/cfp/templates/cfp/complete.html deleted file mode 100644 index c25b4a2..0000000 --- a/cfp/templates/cfp/complete.html +++ /dev/null @@ -1,27 +0,0 @@ -{% extends 'base.html' %} - -{% load ponyconf_tags i18n %} - -{% block proposetab %} class="active"{% endblock %} - -{% block content %} - - -
- -
-{% endblock %} diff --git a/cfp/templates/cfp/proposal_dashboard.html b/cfp/templates/cfp/proposal_dashboard.html new file mode 100644 index 0000000..c1d3b28 --- /dev/null +++ b/cfp/templates/cfp/proposal_dashboard.html @@ -0,0 +1,77 @@ +{% extends 'base.html' %} +{% load i18n crispy_forms_tags cfp_tags %} + +{% load ponyconf_tags i18n %} + +{% block proposetab %} class="active"{% endblock %} + +{% block content %} + + +

{% trans "Your informations" %}

+ +

+

+

+ +

{% trans "Biography" %}

+ +

+ {% if speaker.biography %} + {{ speaker.biography|linebreaksbr }} + {% else %} + {% trans "No biography." %} + {% endif %} +

+ +

{% trans "Your proposals" %}

+ +

+ {% for talk in talks %} + {% if forloop.first %} +

+ {% endif %} + {% empty %} + {% trans "No proposals." %} + {% endfor %} +

+

+ {% trans "New proposal" %} +

+{% endblock %} diff --git a/cfp/templates/cfp/proposal_home.html b/cfp/templates/cfp/proposal_home.html new file mode 100644 index 0000000..6622729 --- /dev/null +++ b/cfp/templates/cfp/proposal_home.html @@ -0,0 +1,33 @@ +{% extends 'base.html' %} +{% load crispy_forms_tags %} + +{% load ponyconf_tags i18n %} + +{% block proposetab %} class="active"{% endblock %} + +{% block content %} + + + +
+
+
+ + {% 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 here.{% endblocktrans %} +
+
+ {% csrf_token %} + {{ speaker_form|crispy }} + {{ talk_form|crispy }} +
+ +
+
+
+
+{% endblock %} diff --git a/cfp/templates/cfp/proposal_mail_token.html b/cfp/templates/cfp/proposal_mail_token.html new file mode 100644 index 0000000..9ad8b31 --- /dev/null +++ b/cfp/templates/cfp/proposal_mail_token.html @@ -0,0 +1,30 @@ +{% extends 'base.html' %} +{% load crispy_forms_tags %} + +{% load ponyconf_tags i18n %} + +{% block proposetab %} class="active"{% endblock %} + +{% block content %} + + + +
+
+
+ {% csrf_token %} +
+ {% blocktrans %}To receive a email with a link to access your profile, please enter your email below.{% endblocktrans %} +
+ {{ form|crispy }} +
+ +
+
+
+
+{% endblock %} diff --git a/cfp/templates/cfp/proposal_speaker_form.html b/cfp/templates/cfp/proposal_speaker_form.html new file mode 100644 index 0000000..13e2a82 --- /dev/null +++ b/cfp/templates/cfp/proposal_speaker_form.html @@ -0,0 +1,42 @@ +{% extends 'base.html' %} +{% load crispy_forms_tags %} + +{% load ponyconf_tags i18n %} + +{% block proposetab %} class="active"{% endblock %} + +{% block content %} + + +
+
+
+ {% csrf_token %} + {{ form|crispy }} +
+ +
+
+
+
+{% endblock %} diff --git a/cfp/templates/cfp/proposal_talk_details.html b/cfp/templates/cfp/proposal_talk_details.html new file mode 100644 index 0000000..9c2878a --- /dev/null +++ b/cfp/templates/cfp/proposal_talk_details.html @@ -0,0 +1,86 @@ +{% extends 'base.html' %} +{% load i18n crispy_forms_tags %} + +{% load ponyconf_tags i18n %} + +{% block proposetab %} class="active"{% endblock %} + +{% block content %} + + +

{% trans "Status" %}

+ +{% if not conference.disclosed_acceptances or talk.accepted is None %} +

{% trans "Reviewing in progress, we will keep you informed by mail." %}

+{% elif talk.accepted %} +

{% trans "Accepted!" %}

+{% if talk.confirmed is None %} +

+ {% trans "Please confirm your participation:" %} + {% trans "I will be there!" %} + {% trans "Sorry, couldn't make it :-(" %} +

+{% elif talk.confirmed %} +

+ {% trans "Sorry, I have to cancel." %} +

+{% else %} +

+ {% trans "Good news, I finally could be there!" %} +

+{% endif %} +{% else %} +

{% trans "Sorry, refused :-(" %}

+{% endif %} + +

{% trans "Speakers" %}

+ +

+ {% for spkr in talk.speakers.all %} + {% if forloop.first %}

{% endif %} + {% endfor %} + +  {% trans "Add a co-speaker" %} + +

+ +

{% trans "Description" %}

+ +

+ {% if talk.description %} + {{ talk.description|linebreaksbr }} + {% else %} + {% trans "No description provided." %} + {% endif %} +

+ +

{% trans "Message to organizers" %}

+ +

+ {% if talk.notes %} + {{ talk.notes|linebreaksbr }} + {% else %} + {% trans "No description provided." %} + {% endif %} +

+{% endblock %} diff --git a/cfp/templates/cfp/propose.html b/cfp/templates/cfp/proposal_talk_form.html similarity index 61% rename from cfp/templates/cfp/propose.html rename to cfp/templates/cfp/proposal_talk_form.html index a59db31..b7ba544 100644 --- a/cfp/templates/cfp/propose.html +++ b/cfp/templates/cfp/proposal_talk_form.html @@ -8,7 +8,14 @@ {% block content %} @@ -16,8 +23,7 @@
{% csrf_token %} - {{ participant_form|crispy }} - {{ talk_form|crispy }} + {{ form|crispy }}
diff --git a/cfp/templates/cfp/speaker.html b/cfp/templates/cfp/speaker.html deleted file mode 100644 index 6a98b01..0000000 --- a/cfp/templates/cfp/speaker.html +++ /dev/null @@ -1,26 +0,0 @@ -{% extends 'base.html' %} -{% load crispy_forms_tags %} - -{% load ponyconf_tags i18n %} - -{% block proposetab %} class="active"{% endblock %} - -{% block content %} - - -
-
- - {% csrf_token %} - {{ participant_form|crispy }} -
- -
- -
-
-{% endblock %} diff --git a/cfp/templatetags/cfp_tags.py b/cfp/templatetags/cfp_tags.py index 11ae8a6..7128df5 100644 --- a/cfp/templatetags/cfp_tags.py +++ b/cfp/templatetags/cfp_tags.py @@ -17,3 +17,8 @@ def duration_format(value): hours = int(value/60) minutes = value%60 return '%d h %02d' % (hours, minutes) + + +@register.filter +def exclude(queryset, excluded): + return queryset.exclude(pk=excluded.pk) diff --git a/cfp/urls.py b/cfp/urls.py index 600de38..e15e192 100644 --- a/cfp/urls.py +++ b/cfp/urls.py @@ -4,12 +4,27 @@ from . import views urlpatterns = [ url(r'^$', views.home, name='home'), - url(r'^cfp/$', views.talk_proposal, name='talk-proposal'), +# 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[\w\-]+)/$', views.proposal_dashboard, name='proposal-dashboard'), + url(r'^cfp/(?P[\w\-]+)/profile/$', views.proposal_speaker_edit, name='proposal-profile-edit'), + url(r'^cfp/(?P[\w\-]+)/talk/add/$', views.proposal_talk_edit, name='proposal-talk-add'), + url(r'^cfp/(?P[\w\-]+)/talk/(?P[\w\-]+)/$', views.proposal_talk_details, name='proposal-talk-details'), + url(r'^cfp/(?P[\w\-]+)/talk/(?P[\w\-]+)/edit/$', views.proposal_talk_edit, name='proposal-talk-edit'), + url(r'^cfp/(?P[\w\-]+)/talk/(?P[\w\-]+)/speaker/add/$', views.proposal_speaker_edit, name='proposal-speaker-add'), + url(r'^cfp/(?P[\w\-]+)/talk/(?P[\w\-]+)/confirm/$', views.proposal_talk_acknowledgment, {'confirm': True}, name='proposal-talk-confirm'), + url(r'^cfp/(?P[\w\-]+)/talk/(?P[\w\-]+)/desist/$', views.proposal_talk_acknowledgment, {'confirm': False}, name='proposal-talk-desist'), + #url(r'^cfp/(?P[\w\-]+)/talk/(?P[\w\-]+)/speaker/(?P[\w\-]+)/$', views.proposal_speaker_details, name='proposal-speaker-details'), + url(r'^cfp/(?P[\w\-]+)/talk/(?P[\w\-]+)/speaker/(?P[\w\-]+)/edit/$', views.proposal_speaker_edit, name='proposal-speaker-edit'), + url(r'^cfp/(?P[\w\-]+)/talk/(?P[\w\-]+)/speaker/(?P[\w\-]+)/remove/$', views.proposal_speaker_remove, name='proposal-speaker-remove'), +# Backward compatibility url(r'^cfp/(?P[\w\-]+)/speaker/add/$', views.talk_proposal_speaker_edit, name='talk-proposal-speaker-add'), url(r'^cfp/(?P[\w\-]+)/speaker/(?P[\w\-]+)/$', views.talk_proposal_speaker_edit, name='talk-proposal-speaker-edit'), url(r'^cfp/(?P[\w\-]+)/(?P[\w\-]+)/$', views.talk_proposal, name='talk-proposal-edit'), url(r'^cfp/(?P[\w\-]+)/(?P[\w\-]+)/confirm/$', views.talk_acknowledgment, {'confirm': True}, name='talk-confirm'), url(r'^cfp/(?P[\w\-]+)/(?P[\w\-]+)/desist/$', views.talk_acknowledgment, {'confirm': False}, name='talk-desist'), +# End backward compatibility url(r'^volunteer/$', views.volunteer_enrole, name='volunteer-enrole'), url(r'^volunteer/(?P[\w\-]+)/$', views.volunteer_home, name='volunteer-home'), url(r'^volunteer/(?P[\w\-]+)/join/(?P[\w\-]+)/$', views.volunteer_update_activity, {'join': True}, name='volunteer-join'), @@ -41,7 +56,7 @@ urlpatterns = [ url(r'^staff/schedule/((?P[\w]+)/)?$', views.staff_schedule, name='staff-schedule'), url(r'^staff/select2/$', views.Select2View.as_view(), name='django_select2-json'), url(r'^admin/$', views.admin, name='admin'), - url(r'^admin/conference/$', views.conference, name='conference'), + url(r'^admin/conference/$', views.conference_edit, name='conference'), url(r'^schedule/((?P[\w]+)/)?$', views.public_schedule, name='public-schedule'), #url(r'^markdown/$', views.markdown_preview, name='markdown'), ] diff --git a/cfp/views.py b/cfp/views.py index 9943ef0..b82d475 100644 --- a/cfp/views.py +++ b/cfp/views.py @@ -20,14 +20,14 @@ from functools import reduce from mailing.models import Message from mailing.forms import MessageForm from .planning import Program -from .decorators import staff_required +from .decorators import speaker_required, staff_required 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, \ ConferenceForm, CreateUserForm, TrackForm, RoomForm, \ - VolunteerForm, VolunteerFilterForm, \ + VolunteerForm, VolunteerFilterForm, MailForm, \ ACCEPTATION_VALUES, CONFIRMATION_VALUES @@ -35,7 +35,7 @@ def home(request): if request.conference.home: return render(request, 'cfp/home.html') else: - return redirect(reverse('talk-proposal')) + return redirect(reverse('proposal-home')) def volunteer_enrole(request): @@ -139,43 +139,25 @@ def volunteer_details(request, volunteer_id): }) -def talk_proposal(request, talk_id=None, participant_id=None): - conference = request.conference - site = conference.site +def proposal_home(request): if is_staff(request, request.user): - categories = TalkCategory.objects.filter(site=site) + categories = TalkCategory.objects.filter(site=request.conference.site) else: - categories = conference.opened_categories - talk = None - participant = None - - if talk_id and participant_id: - talk = get_object_or_404(Talk, token=talk_id, site=site) - participant = get_object_or_404(Participant, token=participant_id, site=site) - elif not categories.exists(): - return render(request, 'cfp/closed.html') - - participant_form = ParticipantForm(request.POST or None, instance=participant) - talk_form = TalkForm(request.POST or None, categories=categories, instance=talk) - - if request.method == 'POST' and talk_form.is_valid() and participant_form.is_valid(): + categories = request.conference.opened_categories + speaker_form = ParticipantForm(request.POST or None, conference=request.conference, social=False) + 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 + speaker.save() talk = talk_form.save(commit=False) - talk.site = site - - participant, created = Participant.objects.get_or_create(email=participant_form.cleaned_data['email'], site=site) - participant_form = ParticipantForm(request.POST, instance=participant) - participant = participant_form.save() - participant.language = request.LANGUAGE_CODE - participant.save() - + talk.site = request.conference.site talk.save() - talk.speakers.add(participant) - - protocol = 'https' if request.is_secure() else 'http' - base_url = protocol+'://'+site.domain - url_talk_proposal_edit = base_url + reverse('talk-proposal-edit', args=[talk.token, participant.token]) - url_talk_proposal_speaker_add = base_url + reverse('talk-proposal-speaker-add', args=[talk.token]) - url_talk_proposal_speaker_edit = base_url + reverse('talk-proposal-speaker-edit', args=[talk.token, participant.token]) + talk.speakers.add(speaker) + base_url = ('https' if request.is_secure() else 'http') + '://' + request.conference.site.domain + url_dashboard = base_url + reverse('proposal-dashboard', kwargs=dict(speaker_token=speaker.token)) + url_talk_details = base_url + reverse('proposal-talk-details', kwargs=dict(speaker_token=speaker.token, talk_id=talk.pk)) + url_speaker_add = base_url + reverse('proposal-speaker-add', kwargs=dict(speaker_token=speaker.token, talk_id=talk.pk)) body = _("""Hi {}, Your talk has been submitted for {}. @@ -185,9 +167,9 @@ Title: {} Description: {} You can at anytime: -- edit your talk: {} +- review and edit your profile: {} +- review and edit your talk: {} - add a new co-speaker: {} -- edit your profile: {} If you have any question, your can answer to this email. @@ -195,89 +177,232 @@ Thanks! {} -""").format(participant.name, conference.name, talk.title, talk.description, url_talk_proposal_edit, url_talk_proposal_speaker_add, url_talk_proposal_speaker_edit, conference.name) - +""").format( + speaker.name, request.conference.name,talk.title, talk.description, + url_dashboard, url_talk_details, url_speaker_add, + request.conference.name, + ) Message.objects.create( - thread=participant.conversation, - author=conference, - from_email=conference.contact_email, + thread=speaker.conversation, + author=request.conference, + from_email=request.conference.contact_email, content=body, ) - - return render(request, 'cfp/complete.html', {'talk': talk, 'participant': participant}) - - return render(request, 'cfp/propose.html', { - 'participant_form': participant_form, - 'site': site, + messages.success(request, _('You proposition have been successfully submitted!')) + return redirect(reverse('proposal-talk-details', kwargs=dict(speaker_token=speaker.token, talk_id=talk.pk))) + return render(request, 'cfp/proposal_home.html', { + 'speaker_form': speaker_form, 'talk_form': talk_form, }) -def talk_proposal_speaker_edit(request, talk_id, participant_id=None): +def proposal_mail_token(request): + form = MailForm(request.POST or None) + if request.method == 'POST' and form.is_valid(): + try: + speaker = Participant.objects.get(site=request.conference.site, email=form.cleaned_data['email']) + except Participant.DoesNotExist: + messages.error(request, _('Sorry, we do not know this email.')) + else: - talk = get_object_or_404(Talk, token=talk_id, site=request.conference.site) - participant = None + base_url = ('https' if request.is_secure() else 'http') + '://' + request.conference.site.domain + dashboard_url = base_url + reverse('proposal-dashboard', kwargs=dict(speaker_token=speaker.token)) + body = _("""Hi {}, - if participant_id: - participant = get_object_or_404(Participant, token=participant_id, site=request.conference.site) +Someone, probably you, ask to access your profile. +You can edit your talks or add new ones following this url: - participant_form = ParticipantForm(request.POST or None, instance=participant) + {} - if request.method == 'POST' and participant_form.is_valid(): +If you have any question, your can answer to this email. - participant, created = Participant.objects.get_or_create(email=participant_form.cleaned_data['email'], site=request.conference.site) - participant_form = ParticipantForm(request.POST, instance=participant) - participant = participant_form.save() - participant.save() +Sincerely, - talk.speakers.add(participant) +{} - return render(request,'cfp/complete.html', {'talk': talk, 'participant': participant}) - - return render(request, 'cfp/speaker.html', { - 'participant_form': participant_form, +""").format(speaker.name, dashboard_url, request.conference.name) + Message.objects.create( + thread=speaker.conversation, + author=request.conference, + from_email=request.conference.contact_email, + content=body, + ) + messages.success(request, _('A email have been sent with a link to access to your profil.')) + return redirect(reverse('proposal-mail-token')) + return render(request, 'cfp/proposal_mail_token.html', { + 'form': form, }) -def talk_acknowledgment(request, talk_id, confirm, participant_id=None): - # TODO: handle multiple speakers case - talk = get_object_or_404(Talk, token=talk_id, site=request.conference.site) - if participant_id: - participant = get_object_or_404(Participant, token=participant_id, site=request.conference.site) - elif not is_staff(request, request.user): - raise PermissionDenied +@speaker_required +def proposal_dashboard(request, speaker): + return render(request, 'cfp/proposal_dashboard.html', { + 'speaker': speaker, + 'talks': speaker.talk_set.all(), + }) + + +@speaker_required +def proposal_talk_details(request, speaker, talk_id): + talk = get_object_or_404(Talk, site=request.conference.site, speakers__pk=speaker.pk, pk=talk_id) + return render(request, 'cfp/proposal_talk_details.html', { + 'speaker': speaker, + 'talk': talk, + }) + + +@speaker_required +def proposal_talk_edit(request, speaker, talk_id=None): + if talk_id: + talk = get_object_or_404(Talk, site=request.conference.site, speakers__pk=speaker.pk, pk=talk_id) else: - participant = None - if not talk.accepted: - raise PermissionDenied - if talk.confirmed != confirm: - talk.confirmed = confirm + talk = None + if is_staff(request, request.user): + categories = TalkCategory.objects.filter(site=request.conference.site) + else: + categories = request.conference.opened_categories + form = TalkForm(request.POST or None, categories=categories, instance=talk) + if request.method == 'POST' and form.is_valid(): + talk = form.save(commit=False) + talk.site = request.conference.site talk.save() - if confirm: - confirmation_message= _('Your participation has been taken into account, thank you!') - if participant: - thread_note = _('Speaker %(speaker)s confirmed his/her participation.') - else: - thread_note = _('The talk have been confirmed.') + talk.speakers.add(speaker) + if talk_id: + messages.success(request, _('Changes saved.')) else: - confirmation_message = _('We have noted your unavailability.') - if participant: - thread_note = _('Speaker %(speaker)s CANCELLED his/her participation.') - else: - thread_note = _('The talk have been cancelled.') - if participant_id: - thread_note = thread_note % {'speaker': participant} - Message.objects.create(thread=talk.conversation, author=participant or request.user, content=thread_note) - messages.success(request, confirmation_message) - else: + # TODO: it could be great to receive the proposition by mail + # but this is not crucial as the speaker already have a link in its mailbox + messages.success(request, _('You proposition have been successfully submitted!')) + return redirect(reverse('proposal-talk-details', kwargs=dict(speaker_token=speaker.token, talk_id=talk.pk))) + return render(request, 'cfp/proposal_talk_form.html', { + 'speaker': speaker, + 'talk': talk, + 'form': form, + }) + + +@speaker_required +def proposal_talk_acknowledgment(request, speaker, talk_id, confirm): + # TODO: handle multiple speakers case + talk = get_object_or_404(Talk, site=request.conference.site, speakers__pk=speaker.pk, pk=talk_id) + if not request.conference.disclosed_acceptances or not talk.accepted: + raise PermissionDenied + if talk.confirmed == confirm: if confirm: messages.warning(request, _('You already confirmed your participation to this talk.')) else: messages.warning(request, _('You already cancelled your participation to this talk.')) - if participant: - return redirect(reverse('talk-proposal-edit', kwargs=dict(talk_id=talk_id, participant_id=participant_id))) else: - return redirect(reverse('talk-details', kwargs=dict(talk_id=talk_id))) + talk.confirmed = confirm + talk.save() + if confirm: + confirmation_message= _('Your participation has been taken into account, thank you!') + thread_note = _('Speaker %(speaker)s confirmed his/her participation.' % {'speaker': speaker}) + else: + confirmation_message = _('We have noted your unavailability.') + thread_note = _('Speaker %(speaker)s CANCELLED his/her participation.' % {'speaker': speaker}) + Message.objects.create(thread=talk.conversation, author=speaker, content=thread_note) + messages.success(request, confirmation_message) + return redirect(reverse('proposal-talk-details', kwargs=dict(speaker_token=speaker.token, talk_id=talk.pk))) + + +# FIXME his this view really useful? +#@speaker_required +#def proposal_speaker_details(request, speaker, talk_id, co_speaker_id): +# talk = get_object_or_404(Talk, site=request.conference.site, speakers__pk=speaker.pk, pk=talk_id) +# co_speaker = get_object_or_404(Participant, site=request.conference.site, talk_set__pk=talk.pk, pk=co_speaker_id) +# return render(request, 'cfp/proposal_speaker_details.html', { +# 'speaker': speaker, +# 'talk': talk, +# 'co_speaker': co_speaker, +# }) + + +@speaker_required +def proposal_speaker_edit(request, speaker, talk_id=None, co_speaker_id=None): + if talk_id: + talk = get_object_or_404(Talk, site=request.conference.site, speakers__pk=speaker.pk, pk=talk_id) + if co_speaker_id: + co_speaker = get_object_or_404(Participant, site=request.conference.site, talk__pk=talk.pk, pk=co_speaker_id) + else: + co_speaker = None + else: + talk = None + co_speaker = None + form = ParticipantForm(request.POST or None, conference=request.conference, instance=co_speaker if talk else speaker) + if request.method == 'POST' and form.is_valid(): + # TODO: Allow to add a co-speaker which already exists. + # This should be automatically allowed if the speaker already have a talk in common with the co-speaker. + # Otherwise, we should send an speaker request to the other user OR allow the other user to join the talk with his token. + # This last requirements in planned for v3. + edited_speaker = form.save() + if talk: + talk.speakers.add(edited_speaker) + #return redirect(reverse('proposal-speaker-details', kwargs=dict(speaker_token=speaker.token, talk_id=talk.pk))) + return redirect(reverse('proposal-talk-details', kwargs=dict(speaker_token=speaker.token, talk_id=talk.pk))) + else: + return redirect(reverse('proposal-dashboard', kwargs=dict(speaker_token=speaker.token))) + return render(request, 'cfp/proposal_speaker_form.html', { + 'speaker': speaker, + 'talk': talk, + 'co_speaker': co_speaker, + 'form': form, + }) + + +@speaker_required +def proposal_speaker_remove(request, speaker, talk_id, co_speaker_id): + talk = get_object_or_404(Talk, site=request.conference.site, speakers__pk=speaker.pk, pk=talk_id) + co_speaker = get_object_or_404(Participant, site=request.conference.site, talk_set__pk=talk.pk, pk=co_speaker_id) + return redirect(reverse('proposal-speaker-details', kwargs=dict())) + + +# BACKWARD COMPATIBILITY +def talk_proposal(request, talk_id=None, participant_id=None): + if talk_id and participant_id: + talk = get_object_or_404(Talk, token=talk_id, site=site) + speaker = get_object_or_404(Participant, token=participant_id, site=site) + return render(reverse('proposal-talk-edit', kwargs=dict(speaker_token=speaker.token, talk_id=talk.pk))) + else: + return render(reverse('proposal-home')) + + +# BACKWARD COMPATIBILITY +def talk_proposal_speaker_edit(request, talk_id, participant_id=None): + talk = get_object_or_404(Talk, token=talk_id, site=request.conference.site) + speaker = talk.speakers.first() # no other choice here… + if participant_id: + co_speaker = get_object_or_404(Participant, token=participant_id, site=request.conference.site) + return redirect(reverse('proposal-speaker-edit', kwargs=dict(speaker_token=speaker.token, talk_id=talk.pk, co_speaker_id=co_speaker.pk))) + else: + return redirect(reverse('proposal-speaker-add', kwargs=dict(speaker_token=speaker.token, talk_id=talk.pk))) + + +# TODO: add @staff_required decorator when dropping old links support +def talk_acknowledgment(request, talk_id, confirm, participant_id=None): + talk = get_object_or_404(Talk, token=talk_id, site=request.conference.site) + if participant_id: + speaker = get_object_or_404(Participant, token=participant_id, site=request.conference.site) + if confirm: + return redirect(reverse('proposal-talk-confirm', kwargs=dict(speaker_token=speaker.token, talk_id=talk.pk))) + else: + return redirect(reverse('proposal-talk-desist', kwargs=dict(speaker_token=speaker.token, talk_id=talk.pk))) + elif not is_staff(request, request.user): + raise PermissionDenied + if not talk.accepted or talk.confirmed == confirm: + raise PermissionDenied + # TODO: handle multiple speakers case + talk.confirmed = confirm + talk.save() + if confirm: + confirmation_message= _('The speaker confirmation have been noted.') + thread_note = _('The talk have been confirmed.') + else: + confirmation_message = _('The speaker unavailability have been noted.') + thread_note = _('The talk have been cancelled.') + Message.objects.create(thread=talk.conversation, author=request.user, content=thread_note) + messages.success(request, confirmation_message) + return redirect(reverse('talk-details', kwargs=dict(talk_id=talk_id))) @staff_required @@ -529,7 +654,7 @@ class ParticipantUpdate(StaffRequiredMixin, OnSiteMixin, UpdateView): @staff_required -def conference(request): +def conference_edit(request): form = ConferenceForm(request.POST or None, instance=request.conference) if request.method == 'POST' and form.is_valid(): diff --git a/locale/fr/LC_MESSAGES/django.mo b/locale/fr/LC_MESSAGES/django.mo index f0ac7bad1b12fa9cd84952a4cd33b01ed16ebfab..6e261cdf7e30ae5942d2eb2c7fc6d52ee3870781 100644 GIT binary patch delta 8688 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 diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index 7fe0432..66bfd3d 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-11-03 19:20+0000\n" -"PO-Revision-Date: 2017-11-03 20:22+0100\n" +"POT-Creation-Date: 2017-11-04 14:28+0000\n" +"PO-Revision-Date: 2017-11-04 15:29+0100\n" "Last-Translator: \n" "Language-Team: \n" "Language: fr\n" @@ -22,7 +22,7 @@ msgstr "" msgid "Pending decision" msgstr "Décision en attente" -#: cfp/forms.py:18 cfp/forms.py:103 cfp/forms.py:196 +#: cfp/forms.py:18 cfp/forms.py:124 cfp/forms.py:231 msgid "Accepted" msgstr "Accepté" @@ -34,145 +34,146 @@ msgstr "Décliné" msgid "Waiting" msgstr "En attente" -#: cfp/forms.py:29 cfp/forms.py:109 cfp/forms.py:202 cfp/models.py:343 +#: cfp/forms.py:29 cfp/forms.py:130 cfp/forms.py:237 cfp/models.py:350 msgid "Confirmed" msgstr "Confirmé" -#: cfp/forms.py:30 cfp/models.py:345 +#: cfp/forms.py:30 cfp/models.py:352 msgid "Cancelled" msgstr "Annulé" -#: cfp/forms.py:41 cfp/models.py:438 +#: cfp/forms.py:62 cfp/models.py:445 msgid "Activity" msgstr "Activité" -#: cfp/forms.py:51 +#: cfp/forms.py:72 msgctxt "activity" msgid "None" msgstr "Aucune" -#: cfp/forms.py:77 +#: cfp/forms.py:98 #, python-format msgid "Default duration: %(duration)d min" msgstr "Durée par défaut : %(duration)d min" -#: cfp/forms.py:85 cfp/forms.py:97 cfp/forms.py:190 +#: cfp/forms.py:106 cfp/forms.py:118 cfp/forms.py:225 #: cfp/templates/cfp/staff/talk_details.html:15 msgid "Category" msgstr "Catégorie" -#: cfp/forms.py:86 cfp/templates/cfp/staff/talk_list.html:43 +#: cfp/forms.py:107 cfp/templates/cfp/staff/talk_list.html:43 msgid "Title" msgstr "Titre" -#: cfp/forms.py:87 cfp/models.py:137 cfp/models.py:433 +#: cfp/forms.py:108 cfp/models.py:144 cfp/models.py:440 +#: cfp/templates/cfp/proposal_talk_details.html:67 #: cfp/templates/cfp/staff/talk_details.html:64 msgid "Description" msgstr "Description" -#: cfp/forms.py:88 cfp/models.py:105 cfp/models.py:414 -#: cfp/templates/cfp/staff/participant_details.html:16 +#: cfp/forms.py:109 cfp/models.py:111 cfp/models.py:421 +#: cfp/templates/cfp/staff/participant_details.html:19 #: cfp/templates/cfp/staff/talk_details.html:78 #: cfp/templates/cfp/staff/volunteer_details.html:20 msgid "Notes" msgstr "Notes" -#: cfp/forms.py:91 +#: cfp/forms.py:112 msgid "Visible by speakers" msgstr "Visible par les orateurs" -#: cfp/forms.py:115 cfp/forms.py:208 cfp/models.py:300 +#: cfp/forms.py:136 cfp/forms.py:243 cfp/models.py:307 #: cfp/templates/cfp/staff/talk_details.html:21 #: cfp/templates/cfp/staff/talk_list.html:46 #: cfp/templates/cfp/staff/track_form.html:14 msgid "Track" msgstr "Session" -#: cfp/forms.py:121 +#: cfp/forms.py:142 msgid "Tag" msgstr "Étiquette" -#: cfp/forms.py:127 cfp/templates/cfp/staff/talk_details.html:83 +#: cfp/forms.py:148 cfp/templates/cfp/staff/talk_details.html:83 msgid "Vote" msgstr "Vote" -#: cfp/forms.py:128 +#: cfp/forms.py:149 msgid "Filter talks you already / not yet voted for" msgstr "" "Filtrer les propositions pour lesquelles vous avez déjà voté / pas encore " "voté" -#: cfp/forms.py:131 cfp/templates/cfp/staff/room_form.html:14 +#: cfp/forms.py:152 cfp/templates/cfp/staff/room_form.html:14 #: cfp/templates/cfp/staff/talk_details.html:38 msgid "Room" msgstr "Salle" -#: cfp/forms.py:132 +#: cfp/forms.py:153 msgid "Filter talks already / not yet affected to a room" msgstr "Filtrer les exposés déjà / pas encore affectées à une salle" -#: cfp/forms.py:135 +#: cfp/forms.py:156 msgid "Scheduled" msgstr "Programmé" -#: cfp/forms.py:136 +#: cfp/forms.py:157 msgid "Filter talks already / not yet scheduled" msgstr "Filtrer les exposés déjà / pas encore planifiées" -#: cfp/forms.py:139 cfp/models.py:317 +#: cfp/forms.py:160 cfp/models.py:324 #: cfp/templates/cfp/staff/talk_details.html:54 msgid "Materials" msgstr "Supports" -#: cfp/forms.py:140 +#: cfp/forms.py:161 msgid "Filter talks with / without materials" msgstr "Filtrer les exposés avec / sans supports" -#: cfp/forms.py:143 cfp/templates/cfp/staff/talk_details.html:58 +#: cfp/forms.py:164 cfp/templates/cfp/staff/talk_details.html:58 msgid "Video" msgstr "Vidéo" -#: cfp/forms.py:144 +#: cfp/forms.py:165 msgid "Filter talks with / without video" msgstr "Filtrer les exposés avec / sans vidéo" -#: cfp/forms.py:153 cfp/forms.py:220 +#: cfp/forms.py:174 cfp/forms.py:255 msgid "Not assigned" msgstr "Pas encore assignée" -#: cfp/forms.py:159 +#: cfp/forms.py:180 msgid "Accept talk?" msgstr "Accepter la proposition ?" -#: cfp/forms.py:160 +#: cfp/forms.py:181 msgid "Assign to a track" msgstr "Assigner à une session" -#: cfp/forms.py:161 +#: cfp/forms.py:182 msgid "Add a tag" msgstr "Ajouter une étiquette" -#: cfp/forms.py:162 +#: cfp/forms.py:183 msgid "Put in a room" msgstr "Assigner à une salle" -#: cfp/forms.py:184 cfp/models.py:135 cfp/models.py:187 cfp/models.py:431 -#: cfp/templates/cfp/staff/participant_list.html:35 -#: cfp/templates/cfp/staff/volunteer_list.html:29 -msgid "Name" -msgstr "Nom" +#: cfp/forms.py:259 cfp/models.py:416 +#: cfp/templates/cfp/staff/volunteer_details.html:11 +#: cfp/templates/cfp/staff/volunteer_list.html:30 +msgid "Email" +msgstr "E-mail" -#: cfp/forms.py:239 +#: cfp/forms.py:278 msgid "New staff members will be informed of their new position by e-mail." msgstr "" "Les nouveaux membres du staff seront informés de leur nouveau rôle par " "courrier électronique." -#: cfp/forms.py:259 +#: cfp/forms.py:298 msgid "An user with that firstname and that lastname already exists." msgstr "Un utilisateur avec ce prénom et ce nom existe déjà." -#: cfp/forms.py:264 +#: cfp/forms.py:303 msgid "A user with that email already exists." msgstr "Un utilisateur avec cet email existe déjà." @@ -209,26 +210,30 @@ msgid "Secure domain (HTTPS)" msgstr "Domaine sécurisé (HTTPS)" #: cfp/models.py:37 +msgid "Acceptances disclosure date" +msgstr "Date de divulgation des acceptations" + +#: cfp/models.py:38 msgid "Schedule publishing date" msgstr "Date de publication du programme" -#: cfp/models.py:38 +#: cfp/models.py:39 msgid "Schedule redirection URL" msgstr "URL de redirection du programme" -#: cfp/models.py:39 +#: cfp/models.py:40 msgid "If specified, schedule tab will redirect to this URL." msgstr "Si spécifiée, l’onglet programme redirigera vers cette URL." -#: cfp/models.py:40 +#: cfp/models.py:41 msgid "Volunteers enrollment opening date" msgstr "Date d’ouverture de l’appel à bénévole" -#: cfp/models.py:41 +#: cfp/models.py:42 msgid "Volunteers enrollment closing date" msgstr "Date de fermeture de l’appel à bénévole" -#: cfp/models.py:73 +#: cfp/models.py:79 #, python-brace-format msgid "" "The reply email should be a formatable string accepting a token argument (e." @@ -237,87 +242,91 @@ msgstr "" "L’adresse de réponse doit être une chaine de texte formatable avec un " "argument « token » (e.g. ponyconf+{token}@exemple.com)." -#: cfp/models.py:93 cfp/models.py:408 -msgid "Your Name" -msgstr "Votre Nom" +#: cfp/models.py:99 cfp/models.py:142 cfp/models.py:194 cfp/models.py:438 +#: cfp/templates/cfp/staff/participant_list.html:35 +#: cfp/templates/cfp/staff/volunteer_list.html:29 +msgid "Name" +msgstr "Nom" -#: cfp/models.py:95 cfp/templates/cfp/staff/participant_details.html:12 +#: cfp/models.py:101 cfp/templates/cfp/proposal_dashboard.html:33 +#: cfp/templates/cfp/staff/participant_details.html:15 msgid "Biography" msgstr "Biographie" -#: cfp/models.py:97 +#: cfp/models.py:103 msgid "Twitter" msgstr "Twitter" -#: cfp/models.py:98 +#: cfp/models.py:104 msgid "LinkedIn" msgstr "LinkedIn" -#: cfp/models.py:99 +#: cfp/models.py:105 msgid "Github" msgstr "Github" -#: cfp/models.py:100 +#: cfp/models.py:106 msgid "Website" msgstr "Site web" -#: cfp/models.py:101 +#: cfp/models.py:107 msgid "Facebook" msgstr "Facebook" -#: cfp/models.py:102 +#: cfp/models.py:108 msgid "Mastodon" msgstr "Mastodon" -#: cfp/models.py:103 cfp/models.py:411 +#: cfp/models.py:109 cfp/models.py:418 #: cfp/templates/cfp/staff/volunteer_details.html:14 msgid "Phone number" msgstr "Numéro de téléphone" -#: cfp/models.py:106 cfp/models.py:299 +#: cfp/models.py:112 cfp/models.py:306 msgid "This field is only visible by organizers." msgstr "Ce champs est uniquement visible par les organisateurs." -#: cfp/models.py:107 +#: cfp/models.py:113 cfp/templates/cfp/staff/participant_details.html:25 msgid "Invited speaker" msgstr "Orateur invité" -#: cfp/models.py:189 +#: cfp/models.py:196 msgid "Color" msgstr "Couleur" -#: cfp/models.py:221 +#: cfp/models.py:228 msgid "Default duration (min)" msgstr "Durée par défaut (min)" -#: cfp/models.py:222 +#: cfp/models.py:229 msgid "Color on program" msgstr "Couleur sur le programme" -#: cfp/models.py:223 +#: cfp/models.py:230 msgid "Label on program" msgstr "Label dans le xml du programme" -#: cfp/models.py:294 cfp/templates/cfp/staff/base.html:11 +#: cfp/models.py:301 cfp/templates/cfp/proposal_talk_details.html:51 +#: cfp/templates/cfp/staff/base.html:11 #: cfp/templates/cfp/staff/participant_list.html:8 #: cfp/templates/cfp/staff/talk_details.html:68 #: cfp/templates/cfp/staff/talk_list.html:45 msgid "Speakers" msgstr "Orateurs" -#: cfp/models.py:295 +#: cfp/models.py:302 msgid "Talk Title" msgstr "Titre de la proposition" -#: cfp/models.py:298 +#: cfp/models.py:305 msgid "Description of your talk" msgstr "Description de votre proposition" -#: cfp/models.py:302 +#: cfp/models.py:309 cfp/templates/cfp/proposal_talk_details.html:77 msgid "Message to organizers" msgstr "Message aux organisateurs" -#: cfp/models.py:303 +#: cfp/models.py:310 msgid "" "If you have any constraint or if you have anything that may help you to " "select your talk, like a video or slides of your talk, please write it down " @@ -327,68 +336,67 @@ msgstr "" "votre proposition, comme une vidéo, des slides, n'hésitez pas à les ajouter " "ici." -#: cfp/models.py:306 +#: cfp/models.py:313 msgid "Talk Category" msgstr "Catégorie de proposition" -#: cfp/models.py:307 +#: cfp/models.py:314 msgid "I'm ok to be recorded on video" msgstr "J’accepte d’être enregistré en vidéo" -#: cfp/models.py:309 +#: cfp/models.py:316 msgid "Video licence" msgstr "Licence vidéo" -#: cfp/models.py:310 +#: cfp/models.py:317 msgid "I need sound" msgstr "J’ai besoin de son" -#: cfp/models.py:313 +#: cfp/models.py:320 msgid "Beginning date and time" msgstr "Date et heure de début" -#: cfp/models.py:314 +#: cfp/models.py:321 msgid "Duration (min)" msgstr "Durée (min)" -#: cfp/models.py:318 +#: cfp/models.py:325 msgid "" "You can use this field to share some materials related to your intervention." msgstr "" "Vous pouvez utiliser ce champs pour partager les supports de votre " "intervention." -#: cfp/models.py:347 +#: cfp/models.py:354 msgid "Waiting confirmation" msgstr "En attente de confirmation" -#: cfp/models.py:349 +#: cfp/models.py:356 msgid "Refused" msgstr "Refusé" -#: cfp/models.py:351 +#: cfp/models.py:358 #, python-format msgid "Pending decision, score: %(score).1f" msgstr "En cours, score : %(score).1f" -#: cfp/models.py:409 cfp/templates/cfp/staff/volunteer_details.html:11 -#: cfp/templates/cfp/staff/volunteer_list.html:30 -msgid "Email" -msgstr "E-mail" +#: cfp/models.py:415 +msgid "Your Name" +msgstr "Votre Nom" -#: cfp/models.py:412 +#: cfp/models.py:419 msgid "SMS prefered" msgstr "SMS préférés" -#: cfp/models.py:415 +#: cfp/models.py:422 msgid "If you have some constraints, you can indicate them here." msgstr "Si vous avez des contraintes, vous pouvez les indiquer ici." -#: cfp/models.py:434 cfp/templates/cfp/staff/volunteer_details.html:8 +#: cfp/models.py:441 cfp/templates/cfp/staff/volunteer_details.html:8 msgid "Volunteer" msgstr "Bénévole" -#: cfp/models.py:439 cfp/templates/cfp/staff/volunteer_details.html:25 +#: cfp/models.py:446 cfp/templates/cfp/staff/volunteer_details.html:25 #: cfp/templates/cfp/staff/volunteer_list.html:32 msgid "Activities" msgstr "Activités" @@ -422,14 +430,18 @@ msgstr "Veuillez sélectionner une catégorie." msgid "Add a new user" msgstr "Ajouter un nouvel utilisateur" -#: cfp/templates/cfp/admin/conference.html:14 cfp/templates/cfp/propose.html:22 -#: cfp/templates/cfp/speaker.html:21 +#: cfp/templates/cfp/admin/conference.html:14 +#: cfp/templates/cfp/proposal.html:28 +#: cfp/templates/cfp/proposal_mail_token.html:25 +#: cfp/templates/cfp/proposal_speaker_form.html:38 +#: cfp/templates/cfp/proposal_talk_form.html:28 +#: cfp/templates/cfp/propose.html:22 cfp/templates/cfp/speaker.html:21 #: cfp/templates/cfp/staff/create_user.html:13 msgid "Save" msgstr "Envoyer" -#: cfp/templates/cfp/closed.html:9 cfp/templates/cfp/propose.html:11 -#: cfp/templates/cfp/speaker.html:11 +#: cfp/templates/cfp/closed.html:9 cfp/templates/cfp/proposal.html:12 +#: cfp/templates/cfp/propose.html:11 cfp/templates/cfp/speaker.html:11 msgid "Participate" msgstr "Participer" @@ -465,13 +477,207 @@ msgstr "Éditer votre profil :" msgid "An email has been sent to you with those URLs" msgstr "Un mail vous a été envoyé avec toutes les URLs" +#: cfp/templates/cfp/proposal.html:21 +#, python-format +msgid "" +"If you already have submitted a talk and you want to edit it or submit " +"another one, please click here." +msgstr "" +"Si vous avez déjà soumis une proposition et que vous souhaitez l’éditer ou " +"en soumettre une autre, cliquez ici." + +#: cfp/templates/cfp/proposal_dashboard.html:11 +#, python-format +msgid "Welcome %(name)s!" +msgstr "Bienvenue %(name)s !" + +#: cfp/templates/cfp/proposal_dashboard.html:13 +#: cfp/templates/cfp/proposal_speaker_form.html:21 +msgid "Edit your profile" +msgstr "Éditer votre profil" + +#: cfp/templates/cfp/proposal_dashboard.html:18 +msgid "Your informations" +msgstr "Vos informations" + +#: cfp/templates/cfp/proposal_dashboard.html:22 +#: cfp/templates/cfp/staff/participant_details.html:26 +msgid "E-mail:" +msgstr "E-mail :" + +#: cfp/templates/cfp/proposal_dashboard.html:23 +#: cfp/templates/cfp/staff/participant_details.html:27 +msgid "Twitter:" +msgstr "Twitter :" + +#: cfp/templates/cfp/proposal_dashboard.html:24 +#: cfp/templates/cfp/staff/participant_details.html:28 +msgid "LinkedIn:" +msgstr "LinkedIn :" + +#: cfp/templates/cfp/proposal_dashboard.html:25 +#: cfp/templates/cfp/staff/participant_details.html:29 +msgid "Github:" +msgstr "Github :" + +#: cfp/templates/cfp/proposal_dashboard.html:26 +#: cfp/templates/cfp/staff/participant_details.html:30 +msgid "Website:" +msgstr "Website :" + +#: cfp/templates/cfp/proposal_dashboard.html:27 +#: cfp/templates/cfp/staff/participant_details.html:31 +msgid "Facebook:" +msgstr "Facebook :" + +#: cfp/templates/cfp/proposal_dashboard.html:28 +#: cfp/templates/cfp/staff/participant_details.html:32 +msgid "Mastodon:" +msgstr "Mastodon :" + +#: cfp/templates/cfp/proposal_dashboard.html:29 +#: cfp/templates/cfp/staff/participant_details.html:33 +msgid "Phone number:" +msgstr "Numéro de téléphone :" + +#: cfp/templates/cfp/proposal_dashboard.html:39 +msgid "No biography." +msgstr "Pas de bibliographie." + +#: cfp/templates/cfp/proposal_dashboard.html:43 +msgid "Your proposals" +msgstr "Vos propositions" + +#: cfp/templates/cfp/proposal_dashboard.html:53 +msgid "with" +msgstr "avec" + +#: cfp/templates/cfp/proposal_dashboard.html:55 +#: cfp/templates/cfp/staff/participant_details.html:47 +#: cfp/templates/cfp/staff/room_details.html:21 +#: cfp/templates/cfp/staff/room_details.html:39 +#: cfp/templates/cfp/staff/talk_list.html:62 +msgid "and" +msgstr "et" + +#: cfp/templates/cfp/proposal_dashboard.html:59 +msgid "you must confirm you participation" +msgstr "vous devez confirmer votre participation" + +#: cfp/templates/cfp/proposal_dashboard.html:61 +msgid "accepted" +msgstr "accepté" + +#: cfp/templates/cfp/proposal_dashboard.html:63 +msgid "cancelled" +msgstr "annulé" + +#: cfp/templates/cfp/proposal_dashboard.html:71 +msgid "No proposals." +msgstr "Aucune proposition." + +#: cfp/templates/cfp/proposal_dashboard.html:75 +#: cfp/templates/cfp/proposal_talk_details.html:17 +msgid "New proposal" +msgstr "Nouvelle proposition" + +#: cfp/templates/cfp/proposal_mail_token.html:12 +msgid "Access an existing profile" +msgstr "Accéder à un profil existant" + +#: cfp/templates/cfp/proposal_mail_token.html:21 +msgid "" +"To receive a email with a link to access your profile, please enter your " +"email below." +msgstr "" +"Pour recevoir un e-mail avec un lien pour accéder à votre profil, veuillez " +"entrer votre adresse mail ci-dessous." + +#: cfp/templates/cfp/proposal_speaker_form.html:13 +#: cfp/templates/cfp/staff/participant_form.html:8 +msgid "Edit a speaker" +msgstr "Éditer un orateur" + +#: cfp/templates/cfp/proposal_speaker_form.html:15 +#: cfp/templates/cfp/proposal_talk_details.html:63 +msgid "Add a co-speaker" +msgstr "Ajouter un co-orateur" + +#: cfp/templates/cfp/proposal_speaker_form.html:17 +msgid "Go back to the talk" +msgstr "Retourner à l’exposé" + +#: cfp/templates/cfp/proposal_talk_details.html:14 +msgid "My profile" +msgstr "Mon profil" + +#: cfp/templates/cfp/proposal_talk_details.html:20 +msgid "Edit this proposal" +msgstr "Éditer cette proposition" + +#: cfp/templates/cfp/proposal_talk_details.html:26 +#: cfp/templates/cfp/staff/talk_details.html:18 +#: cfp/templates/cfp/staff/talk_list.html:48 +msgid "Status" +msgstr "Statut" + +#: cfp/templates/cfp/proposal_talk_details.html:29 +msgid "Reviewing in progress, we will keep you informed by mail." +msgstr "Relecture en cours, nous vous tenons informé par e-mail." + +#: cfp/templates/cfp/proposal_talk_details.html:31 +msgid "Accepted!" +msgstr "Accepté !" + +#: cfp/templates/cfp/proposal_talk_details.html:34 +msgid "Please confirm your participation:" +msgstr "Merci de confirmer votre participation :" + +#: cfp/templates/cfp/proposal_talk_details.html:35 +msgid "I will be there!" +msgstr "Je serai là !" + +#: cfp/templates/cfp/proposal_talk_details.html:36 +msgid "Sorry, couldn't make it :-(" +msgstr "Désolé, j’ai un contre temps :-(" + +#: cfp/templates/cfp/proposal_talk_details.html:40 +msgid "Sorry, I have to cancel." +msgstr "Désolé, je dois annuler." + +#: cfp/templates/cfp/proposal_talk_details.html:44 +msgid "Good news, I finally could be there!" +msgstr "Bonne nouvelle, je peux finalement être présent !" + +#: cfp/templates/cfp/proposal_talk_details.html:48 +msgid "Sorry, refused :-(" +msgstr "Désolé, refusé :-(" + +#: cfp/templates/cfp/proposal_talk_details.html:58 +msgid "you!" +msgstr "vous !" + +#: cfp/templates/cfp/proposal_talk_details.html:73 +#: cfp/templates/cfp/proposal_talk_details.html:83 +#: cfp/templates/cfp/staff/talk_details.html:66 +msgid "No description provided." +msgstr "Aucune description fournie." + +#: cfp/templates/cfp/proposal_talk_form.html:14 +msgid "Submit a proposal" +msgstr "Soumettre une proposition" + +#: cfp/templates/cfp/proposal_talk_form.html:16 +msgid "Go back to proposals list" +msgstr "Retourner à la liste des propositions" + #: cfp/templates/cfp/schedule.html:9 cfp/templates/cfp/staff/base.html:15 #: cfp/templates/cfp/staff/schedule.html:9 ponyconf/templates/base.html:27 msgid "Schedule" msgstr "Programme" #: cfp/templates/cfp/staff/base.html:10 -#: cfp/templates/cfp/staff/participant_details.html:33 +#: cfp/templates/cfp/staff/participant_details.html:37 #: cfp/templates/cfp/staff/talk_list.html:8 msgid "Talks" msgstr "Exposés" @@ -498,75 +704,40 @@ msgid "Cancel" msgstr "Annuler" #: cfp/templates/cfp/staff/participant_details.html:10 +msgid "VIP" +msgstr "VIP" + +#: cfp/templates/cfp/staff/participant_details.html:13 #: cfp/templates/cfp/staff/talk_details.html:10 msgid "Edit" msgstr "Éditer" -#: cfp/templates/cfp/staff/participant_details.html:20 +#: cfp/templates/cfp/staff/participant_details.html:23 msgid "Informations" msgstr "Informations" -#: cfp/templates/cfp/staff/participant_details.html:22 -msgid "E-mail:" -msgstr "E-mail :" - -#: cfp/templates/cfp/staff/participant_details.html:23 -msgid "Twitter:" -msgstr "Twitter :" - -#: cfp/templates/cfp/staff/participant_details.html:24 -msgid "LinkedIn:" -msgstr "LinkedIn :" - -#: cfp/templates/cfp/staff/participant_details.html:25 -msgid "Github:" -msgstr "Github :" - -#: cfp/templates/cfp/staff/participant_details.html:26 -msgid "Website:" -msgstr "Website :" - -#: cfp/templates/cfp/staff/participant_details.html:27 -msgid "Facebook:" -msgstr "Facebook :" - -#: cfp/templates/cfp/staff/participant_details.html:28 -msgid "Mastodon:" -msgstr "Mastodon :" - -#: cfp/templates/cfp/staff/participant_details.html:29 -msgid "Phone number:" -msgstr "Numéro de téléphone :" - -#: cfp/templates/cfp/staff/participant_details.html:30 +#: cfp/templates/cfp/staff/participant_details.html:34 msgid "Language:" msgstr "Langue :" -#: cfp/templates/cfp/staff/participant_details.html:40 +#: cfp/templates/cfp/staff/participant_details.html:44 msgid "by" msgstr "par" -#: cfp/templates/cfp/staff/participant_details.html:43 -#: cfp/templates/cfp/staff/room_details.html:21 -#: cfp/templates/cfp/staff/room_details.html:39 -#: cfp/templates/cfp/staff/talk_list.html:62 -msgid "and" -msgstr "et" - -#: cfp/templates/cfp/staff/participant_details.html:46 +#: cfp/templates/cfp/staff/participant_details.html:50 msgid "in" msgstr "dans la session" -#: cfp/templates/cfp/staff/participant_details.html:52 +#: cfp/templates/cfp/staff/participant_details.html:56 msgid "No talks" msgstr "Aucun exposé" -#: cfp/templates/cfp/staff/participant_details.html:55 +#: cfp/templates/cfp/staff/participant_details.html:59 #: cfp/templates/cfp/staff/talk_details.html:120 msgid "Messaging" msgstr "Messagerie" -#: cfp/templates/cfp/staff/participant_details.html:59 +#: cfp/templates/cfp/staff/participant_details.html:63 msgid "" "Send a message – this message will be received by this participant and " "all the staff team" @@ -574,10 +745,6 @@ msgstr "" "Envoyer un message – ce message sera reçu par le participant et l’équipe " "d’organisation" -#: cfp/templates/cfp/staff/participant_form.html:8 -msgid "Edit a speaker" -msgstr "Éditer un orateur" - #: cfp/templates/cfp/staff/participant_list.html:10 #: cfp/templates/cfp/staff/talk_list.html:10 #: cfp/templates/cfp/staff/volunteer_list.html:11 @@ -614,21 +781,21 @@ msgstr "Contacter :" msgid "link" msgstr "lien" -#: cfp/templates/cfp/staff/participant_list.html:53 +#: cfp/templates/cfp/staff/participant_list.html:56 #, python-format msgid "accepted: %(accepted)s" msgid_plural "accepted: %(accepted)s" msgstr[0] "accepté : %(accepted)s" msgstr[1] "acceptés : %(accepted)s" -#: cfp/templates/cfp/staff/participant_list.html:55 +#: cfp/templates/cfp/staff/participant_list.html:58 #, python-format msgid "pending: %(pending)s" msgid_plural "pending: %(pending)s" msgstr[0] "en attente : %(pending)s" msgstr[1] "en attente : %(pending)s" -#: cfp/templates/cfp/staff/participant_list.html:57 +#: cfp/templates/cfp/staff/participant_list.html:60 #, python-format msgid "refused: %(refused)s" msgid_plural "refused: %(refused)s" @@ -715,11 +882,6 @@ msgstr "Décliner la proposition" msgid "Information" msgstr "Informations" -#: cfp/templates/cfp/staff/talk_details.html:18 -#: cfp/templates/cfp/staff/talk_list.html:48 -msgid "Status" -msgstr "Statut" - #: cfp/templates/cfp/staff/talk_details.html:25 msgctxt "session" msgid "not defined" @@ -748,10 +910,6 @@ msgstr "non défini" msgid "download" msgstr "télécharger" -#: cfp/templates/cfp/staff/talk_details.html:66 -msgid "No description provided." -msgstr "Aucune description fournie." - #: cfp/templates/cfp/staff/talk_details.html:75 msgid "No speakers." msgstr "Aucun orateur." @@ -913,7 +1071,7 @@ msgstr "Merci pour votre participation !" msgid "Okay, no problem!" msgstr "Ok, pas de soucis !" -#: cfp/views.py:179 +#: cfp/views.py:161 msgid "" "Hi {},\n" "\n" @@ -924,9 +1082,9 @@ msgid "" "Description: {}\n" "\n" "You can at anytime:\n" -"- edit your talk: {}\n" +"- review and edit your profile: {}\n" +"- review and edit your talk: {}\n" "- add a new co-speaker: {}\n" -"- edit your profile: {}\n" "\n" "If you have any question, your can answer to this email.\n" "\n" @@ -944,78 +1102,133 @@ msgstr "" "Description: {}\n" "\n" "Vous pouvez à tout moment:\n" -"- éditer votre proposition: {}\n" -"- ajouter un co-speaker: {}\n" -"- éditer votre profil: {}\n" +"- consulter et modifier votre profil : {}\n" +"- consulter et modifier votre proposition : {}\n" +"- ajouter un autre intervenant : {}\n" "\n" "Si vous avez une question, vous pouvez répondre à ce mail.\n" "\n" "{}\n" "\n" -#: cfp/views.py:257 +#: cfp/views.py:191 cfp/views.py:275 +msgid "You proposition have been successfully submitted!" +msgstr "Votre proposition a été transmise avec succès !" + +#: cfp/views.py:205 +msgid "Sorry, we do not know this email." +msgstr "Désolé, nous ne connaissons pas cette e-mail." + +#: cfp/views.py:210 +msgid "" +"Hi {},\n" +"\n" +"Someone, probably you, ask to access your profile.\n" +"You can edit your talks or add new ones following this url:\n" +"\n" +" {}\n" +"\n" +"If you have any question, your can answer to this email.\n" +"\n" +"Sincerely,\n" +"\n" +"{}\n" +"\n" +msgstr "" +"Bonjour {},\n" +"\n" +"Quelqu’un, sans doute vous, a demandé à accéder à votre profil.\n" +"Vous pouvez modifier vos propositions ou en soumettre de nouvelles à l’url " +"suivante :\n" +"\n" +" {}\n" +"\n" +"Si vous avez une question, vous pouvez répondre à ce mail.\n" +"\n" +"Sincèrement,\n" +"\n" +"{}\n" +"\n" + +#: cfp/views.py:230 +msgid "A email have been sent with a link to access to your profil." +msgstr "Un e-mail vous a été envoyé avec un lien pour accéder à votre profil." + +#: cfp/views.py:271 +msgid "Changes saved." +msgstr "Modifications sauvegardées." + +#: cfp/views.py:292 +msgid "You already confirmed your participation to this talk." +msgstr "Vous avez déjà confirmé votre participation à cet exposé." + +#: cfp/views.py:294 +msgid "You already cancelled your participation to this talk." +msgstr "Vous avez déjà annulé votre participation à cet exposé." + +#: cfp/views.py:299 msgid "Your participation has been taken into account, thank you!" msgstr "Votre participation a été prise en compte, merci !" -#: cfp/views.py:259 +#: cfp/views.py:300 #, python-format msgid "Speaker %(speaker)s confirmed his/her participation." msgstr "L’intervenant %(speaker)s a confirmé sa participation." -#: cfp/views.py:261 -msgid "The talk have been confirmed." -msgstr "L’exposé a été confirmé." - -#: cfp/views.py:263 +#: cfp/views.py:302 msgid "We have noted your unavailability." msgstr "Nous avons enregistré votre indisponibilité." -#: cfp/views.py:265 +#: cfp/views.py:303 #, python-format msgid "Speaker %(speaker)s CANCELLED his/her participation." msgstr "L’intervenant %(speaker)s a ANNULÉ sa participation." -#: cfp/views.py:267 +#: cfp/views.py:398 +msgid "The speaker confirmation have been noted." +msgstr "La confirmation de l’orateur a été notée." + +#: cfp/views.py:399 +msgid "The talk have been confirmed." +msgstr "L’exposé a été confirmé." + +#: cfp/views.py:401 +msgid "The speaker unavailability have been noted." +msgstr "L’indisponibilité de l’intervenant a été notée." + +#: cfp/views.py:402 msgid "The talk have been cancelled." msgstr "L’exposé a été annulé." -#: cfp/views.py:274 -msgid "You already confirmed your participation to this talk." -msgstr "Vous avez déjà confirmé votre participation à cet exposé." - -#: cfp/views.py:276 -msgid "You already cancelled your participation to this talk." -msgstr "Vous avez déjà annulé votre participation à cet exposé." - -#: cfp/views.py:352 cfp/views.py:454 +#: cfp/views.py:477 cfp/views.py:579 msgid "The talk has been accepted." msgstr "L’exposé a été accepté." -#: cfp/views.py:354 cfp/views.py:456 +#: cfp/views.py:479 cfp/views.py:581 msgid "The talk has been declined." msgstr "L’exposé a été décliné." -#: cfp/views.py:423 cfp/views.py:516 +#: cfp/views.py:548 cfp/views.py:641 msgid "Message sent!" msgstr "Message envoyé !" -#: cfp/views.py:437 +#: cfp/views.py:562 msgid "Vote successfully created" msgstr "A voté !" -#: cfp/views.py:437 +#: cfp/views.py:562 msgid "Vote successfully updated" msgstr "Vote mis à jour" -#: cfp/views.py:458 +#: cfp/views.py:583 msgid "Decision taken in account" msgstr "Décision enregistrée" -#: cfp/views.py:544 +#: cfp/views.py:669 msgid "[{}] You have been added to the staff team" msgstr "[{}] Vous avez été ajouté aux membres du staff" -#: cfp/views.py:545 +#: cfp/views.py:670 msgid "" "Hi {},\n" "\n" @@ -1039,15 +1252,15 @@ msgstr "" "{}\n" "\n" -#: cfp/views.py:566 +#: cfp/views.py:691 msgid "Modifications successfully saved." msgstr "Modification enregistrée avec succès." -#: cfp/views.py:643 +#: cfp/views.py:768 msgid "User created successfully." msgstr "Utilisateur créé avec succès." -#: cfp/views.py:664 +#: cfp/views.py:789 #, python-format msgid "Format '%s' not available" msgstr "Format '%s' non disponible" @@ -1129,6 +1342,15 @@ msgstr "Changement de mot de passe" msgid "Email address" msgstr "Adresse e-mail" +#~ msgid "My proposals" +#~ msgstr "Mes propositions" + +#~ msgid "Propose a talk" +#~ msgstr "Proposer un exposé" + +#~ msgid "My talks" +#~ msgstr "Mes exposés" + #~ msgid "Moderation" #~ msgstr "Modération" @@ -1249,12 +1471,6 @@ msgstr "Adresse e-mail" #~ msgid "Subscribe to the conversation" #~ msgstr "S’abonner à la discussion" -#~ msgid "Profile" -#~ msgstr "Profil" - -#~ msgid "Change avatar" -#~ msgstr "Changer d’avatar" - #~ msgid "Your current avatar: " #~ msgstr "Votre avatar actuel : " @@ -1368,9 +1584,6 @@ msgstr "Adresse e-mail" #~ msgid "Home page" #~ msgstr "Page d’accueil" -#~ msgid "My talks:" -#~ msgstr "Mes exposés :" - #~ msgid "Proposed talks for others speakers:" #~ msgstr "Exposés proposés pour un tier :" @@ -1383,9 +1596,6 @@ msgstr "Adresse e-mail" #~ msgid "until %(closing_date)s" #~ msgstr "jusqu’au %(closing_date)s" -#~ msgid "Propose a talk" -#~ msgstr "Proposer un exposé" - #~ msgid "Sorry, the Call for Participation is closed." #~ msgstr "Désolé, l’appel à participation est fermé." diff --git a/ponyconf/templates/base.html b/ponyconf/templates/base.html index 49150ff..67d421d 100644 --- a/ponyconf/templates/base.html +++ b/ponyconf/templates/base.html @@ -21,7 +21,7 @@  {% trans "Home" %} {% endif %} -  {% trans "Call for participation" %} +  {% trans "Call for participation" %} {% if conference.schedule_available %}  {% trans "Schedule" %} From c76ba3d6aa08d98343dfe1463da3b597019a7860 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89lie=20Bouttier?= Date: Sat, 4 Nov 2017 15:59:58 +0100 Subject: [PATCH 2/7] show speaker secret link in staff area --- cfp/models.py | 7 +- .../cfp/staff/participant_details.html | 1 + cfp/views.py | 3 +- locale/fr/LC_MESSAGES/django.mo | Bin 21304 -> 20632 bytes locale/fr/LC_MESSAGES/django.po | 242 +++++++++--------- 5 files changed, 125 insertions(+), 128 deletions(-) diff --git a/cfp/models.py b/cfp/models.py index f9c8ff8..0a4fada 100644 --- a/cfp/models.py +++ b/cfp/models.py @@ -115,8 +115,11 @@ class Participant(PonyConfModel): objects = ParticipantManager() - def get_absolute_url(self): - return reverse('proposal-dashboard', kwargs={'speaker_token': self.token}) + def get_secret_url(self, full=False): + url = reverse('proposal-dashboard', kwargs={'speaker_token': self.token}) + if full: + url = ('https' if self.site.conference.secure_domain else 'http') + '://' + self.site.domain + url + return url class Meta: # A User can participe only once to a Conference (= Site) diff --git a/cfp/templates/cfp/staff/participant_details.html b/cfp/templates/cfp/staff/participant_details.html index 91a8073..2ddbff5 100644 --- a/cfp/templates/cfp/staff/participant_details.html +++ b/cfp/templates/cfp/staff/participant_details.html @@ -32,6 +32,7 @@ {% if participant.mastodon %}
  • {% trans "Mastodon:" %} {{ participant.mastodon }}
  • {% endif %} {% if participant.phone_number %}
  • {% trans "Phone number:" %} {{ participant.phone_number }}
  • {% endif %} {% if participant.language %}
  • {% trans "Language:" %} {{ participant.language }}
  • {% endif %} +
  • {% trans "Secret link:" %} {{ participant.token }}
  • {% trans "Talks" %}

    diff --git a/cfp/views.py b/cfp/views.py index b82d475..200d159 100644 --- a/cfp/views.py +++ b/cfp/views.py @@ -46,7 +46,6 @@ def volunteer_enrole(request): volunteer = form.save(commit=False) volunteer.language = request.LANGUAGE_CODE volunteer.save() - volunteer_url = ('https' if request.is_secure() else 'http') + '://' + request.conference.site.domain + volunteer.get_absolute_url() body = _("""Hi {}, Thank your for your help in the organization of the conference {}! @@ -59,7 +58,7 @@ Thanks! {} -""").format(volunteer.name, request.conference.name, volunteer_url, request.conference.name) +""").format(volunteer.name, request.conference.name, volunteer.get_secret_url(full=True), request.conference.name) #Message.objects.create( # thread=volunteer.conversation, # author=request.conference, diff --git a/locale/fr/LC_MESSAGES/django.mo b/locale/fr/LC_MESSAGES/django.mo index 6e261cdf7e30ae5942d2eb2c7fc6d52ee3870781..6a3a1c50613ce61f3c9a438e8fb55d61ecfeffe5 100644 GIT binary patch delta 5824 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 TS2y*RUvB(M-}_p2d+ho@{ljaO delta 6372 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 Zy(*(~Vsx;<%KZG=CxV>6a_l+JzW};_4p#sG diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index 66bfd3d..74b942e 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-11-04 14:28+0000\n" -"PO-Revision-Date: 2017-11-04 15:29+0100\n" +"POT-Creation-Date: 2017-11-04 14:58+0000\n" +"PO-Revision-Date: 2017-11-04 15:58+0100\n" "Last-Translator: \n" "Language-Team: \n" "Language: fr\n" @@ -34,15 +34,15 @@ msgstr "Décliné" msgid "Waiting" msgstr "En attente" -#: cfp/forms.py:29 cfp/forms.py:130 cfp/forms.py:237 cfp/models.py:350 +#: cfp/forms.py:29 cfp/forms.py:130 cfp/forms.py:237 cfp/models.py:353 msgid "Confirmed" msgstr "Confirmé" -#: cfp/forms.py:30 cfp/models.py:352 +#: cfp/forms.py:30 cfp/models.py:355 msgid "Cancelled" msgstr "Annulé" -#: cfp/forms.py:62 cfp/models.py:445 +#: cfp/forms.py:62 cfp/models.py:448 msgid "Activity" msgstr "Activité" @@ -65,13 +65,13 @@ msgstr "Catégorie" msgid "Title" msgstr "Titre" -#: cfp/forms.py:108 cfp/models.py:144 cfp/models.py:440 +#: cfp/forms.py:108 cfp/models.py:147 cfp/models.py:443 #: cfp/templates/cfp/proposal_talk_details.html:67 #: cfp/templates/cfp/staff/talk_details.html:64 msgid "Description" msgstr "Description" -#: cfp/forms.py:109 cfp/models.py:111 cfp/models.py:421 +#: cfp/forms.py:109 cfp/models.py:111 cfp/models.py:424 #: cfp/templates/cfp/staff/participant_details.html:19 #: cfp/templates/cfp/staff/talk_details.html:78 #: cfp/templates/cfp/staff/volunteer_details.html:20 @@ -82,7 +82,7 @@ msgstr "Notes" msgid "Visible by speakers" msgstr "Visible par les orateurs" -#: cfp/forms.py:136 cfp/forms.py:243 cfp/models.py:307 +#: cfp/forms.py:136 cfp/forms.py:243 cfp/models.py:310 #: cfp/templates/cfp/staff/talk_details.html:21 #: cfp/templates/cfp/staff/talk_list.html:46 #: cfp/templates/cfp/staff/track_form.html:14 @@ -120,7 +120,7 @@ msgstr "Programmé" msgid "Filter talks already / not yet scheduled" msgstr "Filtrer les exposés déjà / pas encore planifiées" -#: cfp/forms.py:160 cfp/models.py:324 +#: cfp/forms.py:160 cfp/models.py:327 #: cfp/templates/cfp/staff/talk_details.html:54 msgid "Materials" msgstr "Supports" @@ -157,7 +157,7 @@ msgstr "Ajouter une étiquette" msgid "Put in a room" msgstr "Assigner à une salle" -#: cfp/forms.py:259 cfp/models.py:416 +#: cfp/forms.py:259 cfp/models.py:419 #: cfp/templates/cfp/staff/volunteer_details.html:11 #: cfp/templates/cfp/staff/volunteer_list.html:30 msgid "Email" @@ -242,7 +242,7 @@ msgstr "" "L’adresse de réponse doit être une chaine de texte formatable avec un " "argument « token » (e.g. ponyconf+{token}@exemple.com)." -#: cfp/models.py:99 cfp/models.py:142 cfp/models.py:194 cfp/models.py:438 +#: cfp/models.py:99 cfp/models.py:145 cfp/models.py:197 cfp/models.py:441 #: cfp/templates/cfp/staff/participant_list.html:35 #: cfp/templates/cfp/staff/volunteer_list.html:29 msgid "Name" @@ -277,12 +277,12 @@ msgstr "Facebook" msgid "Mastodon" msgstr "Mastodon" -#: cfp/models.py:109 cfp/models.py:418 +#: cfp/models.py:109 cfp/models.py:421 #: cfp/templates/cfp/staff/volunteer_details.html:14 msgid "Phone number" msgstr "Numéro de téléphone" -#: cfp/models.py:112 cfp/models.py:306 +#: cfp/models.py:112 cfp/models.py:309 msgid "This field is only visible by organizers." msgstr "Ce champs est uniquement visible par les organisateurs." @@ -290,23 +290,23 @@ msgstr "Ce champs est uniquement visible par les organisateurs." msgid "Invited speaker" msgstr "Orateur invité" -#: cfp/models.py:196 +#: cfp/models.py:199 msgid "Color" msgstr "Couleur" -#: cfp/models.py:228 +#: cfp/models.py:231 msgid "Default duration (min)" msgstr "Durée par défaut (min)" -#: cfp/models.py:229 +#: cfp/models.py:232 msgid "Color on program" msgstr "Couleur sur le programme" -#: cfp/models.py:230 +#: cfp/models.py:233 msgid "Label on program" msgstr "Label dans le xml du programme" -#: cfp/models.py:301 cfp/templates/cfp/proposal_talk_details.html:51 +#: cfp/models.py:304 cfp/templates/cfp/proposal_talk_details.html:51 #: cfp/templates/cfp/staff/base.html:11 #: cfp/templates/cfp/staff/participant_list.html:8 #: cfp/templates/cfp/staff/talk_details.html:68 @@ -314,19 +314,19 @@ msgstr "Label dans le xml du programme" msgid "Speakers" msgstr "Orateurs" -#: cfp/models.py:302 +#: cfp/models.py:305 msgid "Talk Title" msgstr "Titre de la proposition" -#: cfp/models.py:305 +#: cfp/models.py:308 msgid "Description of your talk" msgstr "Description de votre proposition" -#: cfp/models.py:309 cfp/templates/cfp/proposal_talk_details.html:77 +#: cfp/models.py:312 cfp/templates/cfp/proposal_talk_details.html:77 msgid "Message to organizers" msgstr "Message aux organisateurs" -#: cfp/models.py:310 +#: cfp/models.py:313 msgid "" "If you have any constraint or if you have anything that may help you to " "select your talk, like a video or slides of your talk, please write it down " @@ -336,67 +336,67 @@ msgstr "" "votre proposition, comme une vidéo, des slides, n'hésitez pas à les ajouter " "ici." -#: cfp/models.py:313 +#: cfp/models.py:316 msgid "Talk Category" msgstr "Catégorie de proposition" -#: cfp/models.py:314 +#: cfp/models.py:317 msgid "I'm ok to be recorded on video" msgstr "J’accepte d’être enregistré en vidéo" -#: cfp/models.py:316 +#: cfp/models.py:319 msgid "Video licence" msgstr "Licence vidéo" -#: cfp/models.py:317 +#: cfp/models.py:320 msgid "I need sound" msgstr "J’ai besoin de son" -#: cfp/models.py:320 +#: cfp/models.py:323 msgid "Beginning date and time" msgstr "Date et heure de début" -#: cfp/models.py:321 +#: cfp/models.py:324 msgid "Duration (min)" msgstr "Durée (min)" -#: cfp/models.py:325 +#: cfp/models.py:328 msgid "" "You can use this field to share some materials related to your intervention." msgstr "" "Vous pouvez utiliser ce champs pour partager les supports de votre " "intervention." -#: cfp/models.py:354 +#: cfp/models.py:357 msgid "Waiting confirmation" msgstr "En attente de confirmation" -#: cfp/models.py:356 +#: cfp/models.py:359 msgid "Refused" msgstr "Refusé" -#: cfp/models.py:358 +#: cfp/models.py:361 #, python-format msgid "Pending decision, score: %(score).1f" msgstr "En cours, score : %(score).1f" -#: cfp/models.py:415 +#: cfp/models.py:418 msgid "Your Name" msgstr "Votre Nom" -#: cfp/models.py:419 +#: cfp/models.py:422 msgid "SMS prefered" msgstr "SMS préférés" -#: cfp/models.py:422 +#: cfp/models.py:425 msgid "If you have some constraints, you can indicate them here." msgstr "Si vous avez des contraintes, vous pouvez les indiquer ici." -#: cfp/models.py:441 cfp/templates/cfp/staff/volunteer_details.html:8 +#: cfp/models.py:444 cfp/templates/cfp/staff/volunteer_details.html:8 msgid "Volunteer" msgstr "Bénévole" -#: cfp/models.py:446 cfp/templates/cfp/staff/volunteer_details.html:25 +#: cfp/models.py:449 cfp/templates/cfp/staff/volunteer_details.html:25 #: cfp/templates/cfp/staff/volunteer_list.html:32 msgid "Activities" msgstr "Activités" @@ -431,61 +431,14 @@ msgid "Add a new user" msgstr "Ajouter un nouvel utilisateur" #: cfp/templates/cfp/admin/conference.html:14 -#: cfp/templates/cfp/proposal.html:28 +#: cfp/templates/cfp/proposal_home.html:28 #: cfp/templates/cfp/proposal_mail_token.html:25 #: cfp/templates/cfp/proposal_speaker_form.html:38 #: cfp/templates/cfp/proposal_talk_form.html:28 -#: cfp/templates/cfp/propose.html:22 cfp/templates/cfp/speaker.html:21 #: cfp/templates/cfp/staff/create_user.html:13 msgid "Save" msgstr "Envoyer" -#: cfp/templates/cfp/closed.html:9 cfp/templates/cfp/proposal.html:12 -#: cfp/templates/cfp/propose.html:11 cfp/templates/cfp/speaker.html:11 -msgid "Participate" -msgstr "Participer" - -#: cfp/templates/cfp/closed.html:13 -msgid "Sorry, the Call for Participation is closed!" -msgstr "Désolé, l’appel à participation est fermé !" - -#: cfp/templates/cfp/complete.html:10 -msgid "Your proposition have been successfully submitted!" -msgstr "Votre proposition a été transmise avec succès !" - -#: cfp/templates/cfp/complete.html:16 -msgid "Thanks for your proposal" -msgstr "Merci pour votre proposition" - -#: cfp/templates/cfp/complete.html:17 -msgid "You can at anytime:" -msgstr "Vous pouvez à tout moment :" - -#: cfp/templates/cfp/complete.html:19 -msgid "Edit your talk:" -msgstr "Modifiez votre exposé :" - -#: cfp/templates/cfp/complete.html:20 -msgid "Add an additionnal speaker:" -msgstr "Ajouter un co-speaker :" - -#: cfp/templates/cfp/complete.html:21 -msgid "Edit your profile:" -msgstr "Éditer votre profil :" - -#: cfp/templates/cfp/complete.html:24 -msgid "An email has been sent to you with those URLs" -msgstr "Un mail vous a été envoyé avec toutes les URLs" - -#: cfp/templates/cfp/proposal.html:21 -#, python-format -msgid "" -"If you already have submitted a talk and you want to edit it or submit " -"another one, please click here." -msgstr "" -"Si vous avez déjà soumis une proposition et que vous souhaitez l’éditer ou " -"en soumettre une autre, cliquez ici." - #: cfp/templates/cfp/proposal_dashboard.html:11 #, python-format msgid "Welcome %(name)s!" @@ -553,7 +506,7 @@ msgid "with" msgstr "avec" #: cfp/templates/cfp/proposal_dashboard.html:55 -#: cfp/templates/cfp/staff/participant_details.html:47 +#: cfp/templates/cfp/staff/participant_details.html:48 #: cfp/templates/cfp/staff/room_details.html:21 #: cfp/templates/cfp/staff/room_details.html:39 #: cfp/templates/cfp/staff/talk_list.html:62 @@ -581,6 +534,19 @@ msgstr "Aucune proposition." msgid "New proposal" msgstr "Nouvelle proposition" +#: cfp/templates/cfp/proposal_home.html:12 +msgid "Participate" +msgstr "Participer" + +#: cfp/templates/cfp/proposal_home.html:21 +#, python-format +msgid "" +"If you already have submitted a talk and you want to edit it or submit " +"another one, please click here." +msgstr "" +"Si vous avez déjà soumis une proposition et que vous souhaitez l’éditer ou " +"en soumettre une autre, cliquez ici." + #: cfp/templates/cfp/proposal_mail_token.html:12 msgid "Access an existing profile" msgstr "Accéder à un profil existant" @@ -677,7 +643,7 @@ msgid "Schedule" msgstr "Programme" #: cfp/templates/cfp/staff/base.html:10 -#: cfp/templates/cfp/staff/participant_details.html:37 +#: cfp/templates/cfp/staff/participant_details.html:38 #: cfp/templates/cfp/staff/talk_list.html:8 msgid "Talks" msgstr "Exposés" @@ -720,24 +686,28 @@ msgstr "Informations" msgid "Language:" msgstr "Langue :" -#: cfp/templates/cfp/staff/participant_details.html:44 +#: cfp/templates/cfp/staff/participant_details.html:35 +msgid "Secret link:" +msgstr "Lien secret :" + +#: cfp/templates/cfp/staff/participant_details.html:45 msgid "by" msgstr "par" -#: cfp/templates/cfp/staff/participant_details.html:50 +#: cfp/templates/cfp/staff/participant_details.html:51 msgid "in" msgstr "dans la session" -#: cfp/templates/cfp/staff/participant_details.html:56 +#: cfp/templates/cfp/staff/participant_details.html:57 msgid "No talks" msgstr "Aucun exposé" -#: cfp/templates/cfp/staff/participant_details.html:59 +#: cfp/templates/cfp/staff/participant_details.html:60 #: cfp/templates/cfp/staff/talk_details.html:120 msgid "Messaging" msgstr "Messagerie" -#: cfp/templates/cfp/staff/participant_details.html:63 +#: cfp/templates/cfp/staff/participant_details.html:64 msgid "" "Send a message – this message will be received by this participant and " "all the staff team" @@ -1024,7 +994,7 @@ msgstr "" msgid "We are looking for help with the following activities:" msgstr "Nous cherchons de l’aide pour les activités suivantes :" -#: cfp/views.py:50 +#: cfp/views.py:49 msgid "" "Hi {},\n" "\n" @@ -1052,26 +1022,26 @@ msgstr "" "{}\n" "\n" -#: cfp/views.py:70 +#: cfp/views.py:69 msgid "Thank you for your help!" msgstr "Merci pour votre aide !" -#: cfp/views.py:75 +#: cfp/views.py:74 msgid "" "Thank you for your participation! You can now subscribe to some activities." msgstr "" "Merci pour votre participation ! Vous pouvez maintenant vous inscrire à une " "ou plusieurs activités." -#: cfp/views.py:99 +#: cfp/views.py:98 msgid "Thank you for your participation!" msgstr "Merci pour votre participation !" -#: cfp/views.py:103 +#: cfp/views.py:102 msgid "Okay, no problem!" msgstr "Ok, pas de soucis !" -#: cfp/views.py:161 +#: cfp/views.py:160 msgid "" "Hi {},\n" "\n" @@ -1111,15 +1081,15 @@ msgstr "" "{}\n" "\n" -#: cfp/views.py:191 cfp/views.py:275 +#: cfp/views.py:190 cfp/views.py:274 msgid "You proposition have been successfully submitted!" msgstr "Votre proposition a été transmise avec succès !" -#: cfp/views.py:205 +#: cfp/views.py:204 msgid "Sorry, we do not know this email." msgstr "Désolé, nous ne connaissons pas cette e-mail." -#: cfp/views.py:210 +#: cfp/views.py:209 msgid "" "Hi {},\n" "\n" @@ -1150,85 +1120,85 @@ msgstr "" "{}\n" "\n" -#: cfp/views.py:230 +#: cfp/views.py:229 msgid "A email have been sent with a link to access to your profil." msgstr "Un e-mail vous a été envoyé avec un lien pour accéder à votre profil." -#: cfp/views.py:271 +#: cfp/views.py:270 msgid "Changes saved." msgstr "Modifications sauvegardées." -#: cfp/views.py:292 +#: cfp/views.py:291 msgid "You already confirmed your participation to this talk." msgstr "Vous avez déjà confirmé votre participation à cet exposé." -#: cfp/views.py:294 +#: cfp/views.py:293 msgid "You already cancelled your participation to this talk." msgstr "Vous avez déjà annulé votre participation à cet exposé." -#: cfp/views.py:299 +#: cfp/views.py:298 msgid "Your participation has been taken into account, thank you!" msgstr "Votre participation a été prise en compte, merci !" -#: cfp/views.py:300 +#: cfp/views.py:299 #, python-format msgid "Speaker %(speaker)s confirmed his/her participation." msgstr "L’intervenant %(speaker)s a confirmé sa participation." -#: cfp/views.py:302 +#: cfp/views.py:301 msgid "We have noted your unavailability." msgstr "Nous avons enregistré votre indisponibilité." -#: cfp/views.py:303 +#: cfp/views.py:302 #, python-format msgid "Speaker %(speaker)s CANCELLED his/her participation." msgstr "L’intervenant %(speaker)s a ANNULÉ sa participation." -#: cfp/views.py:398 +#: cfp/views.py:397 msgid "The speaker confirmation have been noted." msgstr "La confirmation de l’orateur a été notée." -#: cfp/views.py:399 +#: cfp/views.py:398 msgid "The talk have been confirmed." msgstr "L’exposé a été confirmé." -#: cfp/views.py:401 +#: cfp/views.py:400 msgid "The speaker unavailability have been noted." msgstr "L’indisponibilité de l’intervenant a été notée." -#: cfp/views.py:402 +#: cfp/views.py:401 msgid "The talk have been cancelled." msgstr "L’exposé a été annulé." -#: cfp/views.py:477 cfp/views.py:579 +#: cfp/views.py:476 cfp/views.py:578 msgid "The talk has been accepted." msgstr "L’exposé a été accepté." -#: cfp/views.py:479 cfp/views.py:581 +#: cfp/views.py:478 cfp/views.py:580 msgid "The talk has been declined." msgstr "L’exposé a été décliné." -#: cfp/views.py:548 cfp/views.py:641 +#: cfp/views.py:547 cfp/views.py:640 msgid "Message sent!" msgstr "Message envoyé !" -#: cfp/views.py:562 +#: cfp/views.py:561 msgid "Vote successfully created" msgstr "A voté !" -#: cfp/views.py:562 +#: cfp/views.py:561 msgid "Vote successfully updated" msgstr "Vote mis à jour" -#: cfp/views.py:583 +#: cfp/views.py:582 msgid "Decision taken in account" msgstr "Décision enregistrée" -#: cfp/views.py:669 +#: cfp/views.py:668 msgid "[{}] You have been added to the staff team" msgstr "[{}] Vous avez été ajouté aux membres du staff" -#: cfp/views.py:670 +#: cfp/views.py:669 msgid "" "Hi {},\n" "\n" @@ -1252,15 +1222,15 @@ msgstr "" "{}\n" "\n" -#: cfp/views.py:691 +#: cfp/views.py:690 msgid "Modifications successfully saved." msgstr "Modification enregistrée avec succès." -#: cfp/views.py:768 +#: cfp/views.py:767 msgid "User created successfully." msgstr "Utilisateur créé avec succès." -#: cfp/views.py:789 +#: cfp/views.py:788 #, python-format msgid "Format '%s' not available" msgstr "Format '%s' non disponible" @@ -1342,6 +1312,30 @@ msgstr "Changement de mot de passe" msgid "Email address" msgstr "Adresse e-mail" +#~ msgid "Sorry, the Call for Participation is closed!" +#~ msgstr "Désolé, l’appel à participation est fermé !" + +#~ msgid "Your proposition have been successfully submitted!" +#~ msgstr "Votre proposition a été transmise avec succès !" + +#~ msgid "Thanks for your proposal" +#~ msgstr "Merci pour votre proposition" + +#~ msgid "You can at anytime:" +#~ msgstr "Vous pouvez à tout moment :" + +#~ msgid "Edit your talk:" +#~ msgstr "Modifiez votre exposé :" + +#~ msgid "Add an additionnal speaker:" +#~ msgstr "Ajouter un co-speaker :" + +#~ msgid "Edit your profile:" +#~ msgstr "Éditer votre profil :" + +#~ msgid "An email has been sent to you with those URLs" +#~ msgstr "Un mail vous a été envoyé avec toutes les URLs" + #~ msgid "My proposals" #~ msgstr "Mes propositions" From abf5b4361477f7397c4053f73e494da1e365668e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89lie=20Bouttier?= Date: Sat, 4 Nov 2017 16:05:53 +0100 Subject: [PATCH 3/7] fix a backward compatibility issue --- cfp/views.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cfp/views.py b/cfp/views.py index 200d159..5e1a89c 100644 --- a/cfp/views.py +++ b/cfp/views.py @@ -359,8 +359,8 @@ def proposal_speaker_remove(request, speaker, talk_id, co_speaker_id): # BACKWARD COMPATIBILITY def talk_proposal(request, talk_id=None, participant_id=None): if talk_id and participant_id: - talk = get_object_or_404(Talk, token=talk_id, site=site) - speaker = get_object_or_404(Participant, token=participant_id, site=site) + talk = get_object_or_404(Talk, token=talk_id, site=request.conference.site) + speaker = get_object_or_404(Participant, token=participant_id, site=request.conference.site) return render(reverse('proposal-talk-edit', kwargs=dict(speaker_token=speaker.token, talk_id=talk.pk))) else: return render(reverse('proposal-home')) @@ -369,11 +369,11 @@ def talk_proposal(request, talk_id=None, participant_id=None): # BACKWARD COMPATIBILITY def talk_proposal_speaker_edit(request, talk_id, participant_id=None): talk = get_object_or_404(Talk, token=talk_id, site=request.conference.site) - speaker = talk.speakers.first() # no other choice here… if participant_id: - co_speaker = get_object_or_404(Participant, token=participant_id, site=request.conference.site) - return redirect(reverse('proposal-speaker-edit', kwargs=dict(speaker_token=speaker.token, talk_id=talk.pk, co_speaker_id=co_speaker.pk))) + speaker = get_object_or_404(Participant, token=participant_id, site=request.conference.site) + return redirect(reverse('proposal-profile-edit', kwargs=dict(speaker_token=speaker.token))) else: + speaker = talk.speakers.first() # no other choice here… return redirect(reverse('proposal-speaker-add', kwargs=dict(speaker_token=speaker.token, talk_id=talk.pk))) From 38b850fe638a72e9c03b333c90b77a43a3ac5002 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89lie=20Bouttier?= Date: Sat, 4 Nov 2017 16:21:10 +0100 Subject: [PATCH 4/7] fix typo --- cfp/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cfp/views.py b/cfp/views.py index 5e1a89c..daa3188 100644 --- a/cfp/views.py +++ b/cfp/views.py @@ -361,7 +361,7 @@ def talk_proposal(request, talk_id=None, participant_id=None): if talk_id and participant_id: talk = get_object_or_404(Talk, token=talk_id, site=request.conference.site) speaker = get_object_or_404(Participant, token=participant_id, site=request.conference.site) - return render(reverse('proposal-talk-edit', kwargs=dict(speaker_token=speaker.token, talk_id=talk.pk))) + return redirect(reverse('proposal-talk-edit', kwargs=dict(speaker_token=speaker.token, talk_id=talk.pk))) else: return render(reverse('proposal-home')) From 5bab52981cfe4ee517e0d701c54ab96cb2f55b8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89lie=20Bouttier?= Date: Sat, 4 Nov 2017 20:11:50 +0100 Subject: [PATCH 5/7] suggest to add already known co-speaker --- cfp/models.py | 4 + cfp/templates/cfp/proposal_speaker_form.html | 22 ++- cfp/templates/cfp/proposal_talk_details.html | 8 +- cfp/urls.py | 17 +-- cfp/views.py | 30 +++-- locale/fr/LC_MESSAGES/django.mo | Bin 20632 -> 21053 bytes locale/fr/LC_MESSAGES/django.po | 134 +++++++++++-------- 7 files changed, 131 insertions(+), 84 deletions(-) diff --git a/cfp/models.py b/cfp/models.py index 0a4fada..f35d182 100644 --- a/cfp/models.py +++ b/cfp/models.py @@ -129,6 +129,10 @@ class Participant(PonyConfModel): def __str__(self): return str(self.name) + @property + def co_speaker_set(self): + return Participant.objects.filter(site=self.site, talk__in=self.talk_set.values_list('pk')).exclude(pk=self.pk).order_by('name').distinct() + @property def accepted_talk_set(self): return self.talk_set.filter(accepted=True) diff --git a/cfp/templates/cfp/proposal_speaker_form.html b/cfp/templates/cfp/proposal_speaker_form.html index 13e2a82..baa8090 100644 --- a/cfp/templates/cfp/proposal_speaker_form.html +++ b/cfp/templates/cfp/proposal_speaker_form.html @@ -30,13 +30,23 @@
    -
    - {% csrf_token %} - {{ form|crispy }} -
    - + {% if co_speaker_candidates %} +
    + {% trans "You may want to add one of the following speakers:" %} + {% for spkr in co_speaker_candidates %} + {% if forloop.first %}{% endif %} + {% endfor %}
    - + {% endif %} +
    + {% csrf_token %} + {{ form|crispy }} +
    + +
    +
    {% endblock %} diff --git a/cfp/templates/cfp/proposal_talk_details.html b/cfp/templates/cfp/proposal_talk_details.html index 9c2878a..5707479 100644 --- a/cfp/templates/cfp/proposal_talk_details.html +++ b/cfp/templates/cfp/proposal_talk_details.html @@ -55,7 +55,13 @@ {% if forloop.first %}
      {% endif %}
    • {{ spkr }} - {% if spkr.pk == speaker.pk %} ({% trans "you!" %}){% endif %} + {% if spkr.pk == speaker.pk %} + ({% trans "you!" %}) + {% else %} + +  {% trans "remove" %} + + {% endif %}
    • {% if forloop.last %}
    {% endif %} {% endfor %} diff --git a/cfp/urls.py b/cfp/urls.py index e15e192..41067d8 100644 --- a/cfp/urls.py +++ b/cfp/urls.py @@ -10,14 +10,15 @@ urlpatterns = [ url(r'^cfp/(?P[\w\-]+)/$', views.proposal_dashboard, name='proposal-dashboard'), url(r'^cfp/(?P[\w\-]+)/profile/$', views.proposal_speaker_edit, name='proposal-profile-edit'), url(r'^cfp/(?P[\w\-]+)/talk/add/$', views.proposal_talk_edit, name='proposal-talk-add'), - url(r'^cfp/(?P[\w\-]+)/talk/(?P[\w\-]+)/$', views.proposal_talk_details, name='proposal-talk-details'), - url(r'^cfp/(?P[\w\-]+)/talk/(?P[\w\-]+)/edit/$', views.proposal_talk_edit, name='proposal-talk-edit'), - url(r'^cfp/(?P[\w\-]+)/talk/(?P[\w\-]+)/speaker/add/$', views.proposal_speaker_edit, name='proposal-speaker-add'), - url(r'^cfp/(?P[\w\-]+)/talk/(?P[\w\-]+)/confirm/$', views.proposal_talk_acknowledgment, {'confirm': True}, name='proposal-talk-confirm'), - url(r'^cfp/(?P[\w\-]+)/talk/(?P[\w\-]+)/desist/$', views.proposal_talk_acknowledgment, {'confirm': False}, name='proposal-talk-desist'), - #url(r'^cfp/(?P[\w\-]+)/talk/(?P[\w\-]+)/speaker/(?P[\w\-]+)/$', views.proposal_speaker_details, name='proposal-speaker-details'), - url(r'^cfp/(?P[\w\-]+)/talk/(?P[\w\-]+)/speaker/(?P[\w\-]+)/edit/$', views.proposal_speaker_edit, name='proposal-speaker-edit'), - url(r'^cfp/(?P[\w\-]+)/talk/(?P[\w\-]+)/speaker/(?P[\w\-]+)/remove/$', views.proposal_speaker_remove, name='proposal-speaker-remove'), + url(r'^cfp/(?P[\w\-]+)/talk/(?P[0-9]+)/$', views.proposal_talk_details, name='proposal-talk-details'), + url(r'^cfp/(?P[\w\-]+)/talk/(?P[0-9]+)/edit/$', views.proposal_talk_edit, name='proposal-talk-edit'), + url(r'^cfp/(?P[\w\-]+)/talk/(?P[0-9]+)/speaker/add/$', views.proposal_speaker_edit, name='proposal-speaker-add'), + url(r'^cfp/(?P[\w\-]+)/talk/(?P[0-9]+)/speaker/add/(?P[0-9]+)/$', views.proposal_speaker_add, name='proposal-speaker-add-existing'), + #url(r'^cfp/(?P[\w\-]+)/talk/(?P[0-9]+)/speaker/(?P[0-9]+)/$', views.proposal_speaker_details, name='proposal-speaker-details'), + url(r'^cfp/(?P[\w\-]+)/talk/(?P[0-9]+)/speaker/(?P[0-9]+)/edit/$', views.proposal_speaker_edit, name='proposal-speaker-edit'), + url(r'^cfp/(?P[\w\-]+)/talk/(?P[0-9]+)/speaker/(?P[0-9]+)/remove/$', views.proposal_speaker_remove, name='proposal-speaker-remove'), + url(r'^cfp/(?P[\w\-]+)/talk/(?P[0-9]+)/confirm/$', views.proposal_talk_acknowledgment, {'confirm': True}, name='proposal-talk-confirm'), + url(r'^cfp/(?P[\w\-]+)/talk/(?P[0-9]+)/desist/$', views.proposal_talk_acknowledgment, {'confirm': False}, name='proposal-talk-desist'), # Backward compatibility url(r'^cfp/(?P[\w\-]+)/speaker/add/$', views.talk_proposal_speaker_edit, name='talk-proposal-speaker-add'), url(r'^cfp/(?P[\w\-]+)/speaker/(?P[\w\-]+)/$', views.talk_proposal_speaker_edit, name='talk-proposal-speaker-edit'), diff --git a/cfp/views.py b/cfp/views.py index daa3188..0e7d2cf 100644 --- a/cfp/views.py +++ b/cfp/views.py @@ -319,21 +319,15 @@ def proposal_talk_acknowledgment(request, speaker, talk_id, confirm): @speaker_required def proposal_speaker_edit(request, speaker, talk_id=None, co_speaker_id=None): + talk, co_speaker, co_speaker_candidates = None, None, None if talk_id: talk = get_object_or_404(Talk, site=request.conference.site, speakers__pk=speaker.pk, pk=talk_id) if co_speaker_id: co_speaker = get_object_or_404(Participant, site=request.conference.site, talk__pk=talk.pk, pk=co_speaker_id) else: - co_speaker = None - else: - talk = None - co_speaker = None + 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) if request.method == 'POST' and form.is_valid(): - # TODO: Allow to add a co-speaker which already exists. - # This should be automatically allowed if the speaker already have a talk in common with the co-speaker. - # Otherwise, we should send an speaker request to the other user OR allow the other user to join the talk with his token. - # This last requirements in planned for v3. edited_speaker = form.save() if talk: talk.speakers.add(edited_speaker) @@ -345,15 +339,31 @@ def proposal_speaker_edit(request, speaker, talk_id=None, co_speaker_id=None): 'speaker': speaker, 'talk': talk, 'co_speaker': co_speaker, + 'co_speaker_candidates': co_speaker_candidates, 'form': form, }) +@speaker_required +def proposal_speaker_add(request, speaker, talk_id, speaker_id): + talk = get_object_or_404(Talk, site=request.conference.site, speakers__pk=speaker.pk, pk=talk_id) + co_speaker = get_object_or_404(Participant, pk__in=speaker.co_speaker_set.values_list('pk')) + talk.speakers.add(co_speaker) + messages.success(request, _('Co-speaker successfully added to the talk.')) + return redirect(reverse('proposal-talk-details', kwargs=dict(speaker_token=speaker.token, talk_id=talk_id))) + + +# TODO: ask for confirmation (with POST request needed) @speaker_required def proposal_speaker_remove(request, speaker, talk_id, co_speaker_id): talk = get_object_or_404(Talk, site=request.conference.site, speakers__pk=speaker.pk, pk=talk_id) - co_speaker = get_object_or_404(Participant, site=request.conference.site, talk_set__pk=talk.pk, pk=co_speaker_id) - return redirect(reverse('proposal-speaker-details', kwargs=dict())) + co_speaker = get_object_or_404(Participant, site=request.conference.site, talk__pk=talk.pk, pk=co_speaker_id) + # prevent speaker from removing his/her self + if co_speaker.pk == speaker.pk: + raise PermissionDenied + talk.speakers.remove(co_speaker) + messages.success(request, _('Co-speaker successfully removed from the talk.')) + return redirect(reverse('proposal-talk-details', kwargs=dict(speaker_token=speaker.token, talk_id=talk_id))) # BACKWARD COMPATIBILITY diff --git a/locale/fr/LC_MESSAGES/django.mo b/locale/fr/LC_MESSAGES/django.mo index 6a3a1c50613ce61f3c9a438e8fb55d61ecfeffe5..731ab28f779e900cd0b78be40671dc52cf19180a 100644 GIT binary patch delta 6179 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 V+=QCU;g>@i+nc(*3(`kS`Zo}c+~xoP delta 5766 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 E0Ri(+DF6Tf diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index 74b942e..e40e7a9 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-11-04 14:58+0000\n" -"PO-Revision-Date: 2017-11-04 15:58+0100\n" +"POT-Creation-Date: 2017-11-04 19:09+0000\n" +"PO-Revision-Date: 2017-11-04 20:11+0100\n" "Last-Translator: \n" "Language-Team: \n" "Language: fr\n" @@ -34,15 +34,15 @@ msgstr "Décliné" msgid "Waiting" msgstr "En attente" -#: cfp/forms.py:29 cfp/forms.py:130 cfp/forms.py:237 cfp/models.py:353 +#: cfp/forms.py:29 cfp/forms.py:130 cfp/forms.py:237 cfp/models.py:357 msgid "Confirmed" msgstr "Confirmé" -#: cfp/forms.py:30 cfp/models.py:355 +#: cfp/forms.py:30 cfp/models.py:359 msgid "Cancelled" msgstr "Annulé" -#: cfp/forms.py:62 cfp/models.py:448 +#: cfp/forms.py:62 cfp/models.py:452 msgid "Activity" msgstr "Activité" @@ -65,13 +65,13 @@ msgstr "Catégorie" msgid "Title" msgstr "Titre" -#: cfp/forms.py:108 cfp/models.py:147 cfp/models.py:443 -#: cfp/templates/cfp/proposal_talk_details.html:67 +#: cfp/forms.py:108 cfp/models.py:151 cfp/models.py:447 +#: cfp/templates/cfp/proposal_talk_details.html:73 #: cfp/templates/cfp/staff/talk_details.html:64 msgid "Description" msgstr "Description" -#: cfp/forms.py:109 cfp/models.py:111 cfp/models.py:424 +#: cfp/forms.py:109 cfp/models.py:111 cfp/models.py:428 #: cfp/templates/cfp/staff/participant_details.html:19 #: cfp/templates/cfp/staff/talk_details.html:78 #: cfp/templates/cfp/staff/volunteer_details.html:20 @@ -82,7 +82,7 @@ msgstr "Notes" msgid "Visible by speakers" msgstr "Visible par les orateurs" -#: cfp/forms.py:136 cfp/forms.py:243 cfp/models.py:310 +#: cfp/forms.py:136 cfp/forms.py:243 cfp/models.py:314 #: cfp/templates/cfp/staff/talk_details.html:21 #: cfp/templates/cfp/staff/talk_list.html:46 #: cfp/templates/cfp/staff/track_form.html:14 @@ -120,7 +120,7 @@ msgstr "Programmé" msgid "Filter talks already / not yet scheduled" msgstr "Filtrer les exposés déjà / pas encore planifiées" -#: cfp/forms.py:160 cfp/models.py:327 +#: cfp/forms.py:160 cfp/models.py:331 #: cfp/templates/cfp/staff/talk_details.html:54 msgid "Materials" msgstr "Supports" @@ -157,7 +157,7 @@ msgstr "Ajouter une étiquette" msgid "Put in a room" msgstr "Assigner à une salle" -#: cfp/forms.py:259 cfp/models.py:419 +#: cfp/forms.py:259 cfp/models.py:423 #: cfp/templates/cfp/staff/volunteer_details.html:11 #: cfp/templates/cfp/staff/volunteer_list.html:30 msgid "Email" @@ -242,7 +242,7 @@ msgstr "" "L’adresse de réponse doit être une chaine de texte formatable avec un " "argument « token » (e.g. ponyconf+{token}@exemple.com)." -#: cfp/models.py:99 cfp/models.py:145 cfp/models.py:197 cfp/models.py:441 +#: cfp/models.py:99 cfp/models.py:149 cfp/models.py:201 cfp/models.py:445 #: cfp/templates/cfp/staff/participant_list.html:35 #: cfp/templates/cfp/staff/volunteer_list.html:29 msgid "Name" @@ -277,12 +277,12 @@ msgstr "Facebook" msgid "Mastodon" msgstr "Mastodon" -#: cfp/models.py:109 cfp/models.py:421 +#: cfp/models.py:109 cfp/models.py:425 #: cfp/templates/cfp/staff/volunteer_details.html:14 msgid "Phone number" msgstr "Numéro de téléphone" -#: cfp/models.py:112 cfp/models.py:309 +#: cfp/models.py:112 cfp/models.py:313 msgid "This field is only visible by organizers." msgstr "Ce champs est uniquement visible par les organisateurs." @@ -290,23 +290,23 @@ msgstr "Ce champs est uniquement visible par les organisateurs." msgid "Invited speaker" msgstr "Orateur invité" -#: cfp/models.py:199 +#: cfp/models.py:203 msgid "Color" msgstr "Couleur" -#: cfp/models.py:231 +#: cfp/models.py:235 msgid "Default duration (min)" msgstr "Durée par défaut (min)" -#: cfp/models.py:232 +#: cfp/models.py:236 msgid "Color on program" msgstr "Couleur sur le programme" -#: cfp/models.py:233 +#: cfp/models.py:237 msgid "Label on program" msgstr "Label dans le xml du programme" -#: cfp/models.py:304 cfp/templates/cfp/proposal_talk_details.html:51 +#: cfp/models.py:308 cfp/templates/cfp/proposal_talk_details.html:51 #: cfp/templates/cfp/staff/base.html:11 #: cfp/templates/cfp/staff/participant_list.html:8 #: cfp/templates/cfp/staff/talk_details.html:68 @@ -314,19 +314,19 @@ msgstr "Label dans le xml du programme" msgid "Speakers" msgstr "Orateurs" -#: cfp/models.py:305 +#: cfp/models.py:309 msgid "Talk Title" msgstr "Titre de la proposition" -#: cfp/models.py:308 +#: cfp/models.py:312 msgid "Description of your talk" msgstr "Description de votre proposition" -#: cfp/models.py:312 cfp/templates/cfp/proposal_talk_details.html:77 +#: cfp/models.py:316 cfp/templates/cfp/proposal_talk_details.html:83 msgid "Message to organizers" msgstr "Message aux organisateurs" -#: cfp/models.py:313 +#: cfp/models.py:317 msgid "" "If you have any constraint or if you have anything that may help you to " "select your talk, like a video or slides of your talk, please write it down " @@ -336,67 +336,67 @@ msgstr "" "votre proposition, comme une vidéo, des slides, n'hésitez pas à les ajouter " "ici." -#: cfp/models.py:316 +#: cfp/models.py:320 msgid "Talk Category" msgstr "Catégorie de proposition" -#: cfp/models.py:317 +#: cfp/models.py:321 msgid "I'm ok to be recorded on video" msgstr "J’accepte d’être enregistré en vidéo" -#: cfp/models.py:319 +#: cfp/models.py:323 msgid "Video licence" msgstr "Licence vidéo" -#: cfp/models.py:320 +#: cfp/models.py:324 msgid "I need sound" msgstr "J’ai besoin de son" -#: cfp/models.py:323 +#: cfp/models.py:327 msgid "Beginning date and time" msgstr "Date et heure de début" -#: cfp/models.py:324 +#: cfp/models.py:328 msgid "Duration (min)" msgstr "Durée (min)" -#: cfp/models.py:328 +#: cfp/models.py:332 msgid "" "You can use this field to share some materials related to your intervention." msgstr "" "Vous pouvez utiliser ce champs pour partager les supports de votre " "intervention." -#: cfp/models.py:357 +#: cfp/models.py:361 msgid "Waiting confirmation" msgstr "En attente de confirmation" -#: cfp/models.py:359 +#: cfp/models.py:363 msgid "Refused" msgstr "Refusé" -#: cfp/models.py:361 +#: cfp/models.py:365 #, python-format msgid "Pending decision, score: %(score).1f" msgstr "En cours, score : %(score).1f" -#: cfp/models.py:418 +#: cfp/models.py:422 msgid "Your Name" msgstr "Votre Nom" -#: cfp/models.py:422 +#: cfp/models.py:426 msgid "SMS prefered" msgstr "SMS préférés" -#: cfp/models.py:425 +#: cfp/models.py:429 msgid "If you have some constraints, you can indicate them here." msgstr "Si vous avez des contraintes, vous pouvez les indiquer ici." -#: cfp/models.py:444 cfp/templates/cfp/staff/volunteer_details.html:8 +#: cfp/models.py:448 cfp/templates/cfp/staff/volunteer_details.html:8 msgid "Volunteer" msgstr "Bénévole" -#: cfp/models.py:449 cfp/templates/cfp/staff/volunteer_details.html:25 +#: cfp/models.py:453 cfp/templates/cfp/staff/volunteer_details.html:25 #: cfp/templates/cfp/staff/volunteer_list.html:32 msgid "Activities" msgstr "Activités" @@ -433,7 +433,7 @@ msgstr "Ajouter un nouvel utilisateur" #: cfp/templates/cfp/admin/conference.html:14 #: cfp/templates/cfp/proposal_home.html:28 #: cfp/templates/cfp/proposal_mail_token.html:25 -#: cfp/templates/cfp/proposal_speaker_form.html:38 +#: cfp/templates/cfp/proposal_speaker_form.html:48 #: cfp/templates/cfp/proposal_talk_form.html:28 #: cfp/templates/cfp/staff/create_user.html:13 msgid "Save" @@ -565,14 +565,18 @@ msgid "Edit a speaker" msgstr "Éditer un orateur" #: cfp/templates/cfp/proposal_speaker_form.html:15 -#: cfp/templates/cfp/proposal_talk_details.html:63 +#: cfp/templates/cfp/proposal_talk_details.html:69 msgid "Add a co-speaker" -msgstr "Ajouter un co-orateur" +msgstr "Ajouter un co-intervenant" #: cfp/templates/cfp/proposal_speaker_form.html:17 msgid "Go back to the talk" msgstr "Retourner à l’exposé" +#: cfp/templates/cfp/proposal_speaker_form.html:36 +msgid "You may want to add one of the following speakers:" +msgstr "Vous souhaitez peut-être ajouter un des intervenants suivants :" + #: cfp/templates/cfp/proposal_talk_details.html:14 msgid "My profile" msgstr "Mon profil" @@ -619,12 +623,16 @@ msgstr "Bonne nouvelle, je peux finalement être présent !" msgid "Sorry, refused :-(" msgstr "Désolé, refusé :-(" -#: cfp/templates/cfp/proposal_talk_details.html:58 +#: cfp/templates/cfp/proposal_talk_details.html:59 msgid "you!" msgstr "vous !" -#: cfp/templates/cfp/proposal_talk_details.html:73 -#: cfp/templates/cfp/proposal_talk_details.html:83 +#: cfp/templates/cfp/proposal_talk_details.html:62 +msgid "remove" +msgstr "supprimer" + +#: cfp/templates/cfp/proposal_talk_details.html:79 +#: cfp/templates/cfp/proposal_talk_details.html:89 #: cfp/templates/cfp/staff/talk_details.html:66 msgid "No description provided." msgstr "Aucune description fournie." @@ -1154,51 +1162,59 @@ msgstr "Nous avons enregistré votre indisponibilité." msgid "Speaker %(speaker)s CANCELLED his/her participation." msgstr "L’intervenant %(speaker)s a ANNULÉ sa participation." -#: cfp/views.py:397 +#: cfp/views.py:352 +msgid "Co-speaker successfully added to the talk." +msgstr "Co-intervenant ajouté à l’exposé avec succès." + +#: cfp/views.py:365 +msgid "Co-speaker successfully removed from the talk." +msgstr "Co-intervenant supprimé de l’exposé avec succès." + +#: cfp/views.py:407 msgid "The speaker confirmation have been noted." msgstr "La confirmation de l’orateur a été notée." -#: cfp/views.py:398 +#: cfp/views.py:408 msgid "The talk have been confirmed." msgstr "L’exposé a été confirmé." -#: cfp/views.py:400 +#: cfp/views.py:410 msgid "The speaker unavailability have been noted." msgstr "L’indisponibilité de l’intervenant a été notée." -#: cfp/views.py:401 +#: cfp/views.py:411 msgid "The talk have been cancelled." msgstr "L’exposé a été annulé." -#: cfp/views.py:476 cfp/views.py:578 +#: cfp/views.py:486 cfp/views.py:588 msgid "The talk has been accepted." msgstr "L’exposé a été accepté." -#: cfp/views.py:478 cfp/views.py:580 +#: cfp/views.py:488 cfp/views.py:590 msgid "The talk has been declined." msgstr "L’exposé a été décliné." -#: cfp/views.py:547 cfp/views.py:640 +#: cfp/views.py:557 cfp/views.py:650 msgid "Message sent!" msgstr "Message envoyé !" -#: cfp/views.py:561 +#: cfp/views.py:571 msgid "Vote successfully created" msgstr "A voté !" -#: cfp/views.py:561 +#: cfp/views.py:571 msgid "Vote successfully updated" msgstr "Vote mis à jour" -#: cfp/views.py:582 +#: cfp/views.py:592 msgid "Decision taken in account" msgstr "Décision enregistrée" -#: cfp/views.py:668 +#: cfp/views.py:678 msgid "[{}] You have been added to the staff team" msgstr "[{}] Vous avez été ajouté aux membres du staff" -#: cfp/views.py:669 +#: cfp/views.py:679 msgid "" "Hi {},\n" "\n" @@ -1222,15 +1238,15 @@ msgstr "" "{}\n" "\n" -#: cfp/views.py:690 +#: cfp/views.py:700 msgid "Modifications successfully saved." msgstr "Modification enregistrée avec succès." -#: cfp/views.py:767 +#: cfp/views.py:777 msgid "User created successfully." msgstr "Utilisateur créé avec succès." -#: cfp/views.py:788 +#: cfp/views.py:798 #, python-format msgid "Format '%s' not available" msgstr "Format '%s' non disponible" From c7f20b236298a72b371f2f1d2a89a3e8fbf89b6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89lie=20Bouttier?= Date: Sat, 4 Nov 2017 21:12:58 +0100 Subject: [PATCH 6/7] notify co-speaker --- cfp/forms.py | 5 ++ cfp/views.py | 43 +++++++++++++- locale/fr/LC_MESSAGES/django.mo | Bin 21053 -> 21786 bytes locale/fr/LC_MESSAGES/django.po | 102 +++++++++++++++++++++++--------- 4 files changed, 120 insertions(+), 30 deletions(-) diff --git a/cfp/forms.py b/cfp/forms.py index a2bc667..ec862e1 100644 --- a/cfp/forms.py +++ b/cfp/forms.py @@ -196,12 +196,17 @@ class TalkActionForm(forms.Form): class ParticipantForm(OnSiteNamedModelForm): + 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 diff --git a/cfp/views.py b/cfp/views.py index 0e7d2cf..416c6e9 100644 --- a/cfp/views.py +++ b/cfp/views.py @@ -326,11 +326,52 @@ 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) + 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() if talk: talk.speakers.add(edited_speaker) + if co_speaker_id: + messages.success(request, _('Changes saved.')) + else: + if 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)) + url_speaker_add = base_url + reverse('proposal-speaker-add', kwargs=dict(speaker_token=edited_speaker.token, talk_id=talk.pk)) + body = _("""Hi {}, + +{} add you as a co-speaker for the conference {}. + +Here is a summary of the talk: +Title: {} +Description: {} + +You can at anytime: +- review and edit your profile: {} +- review and edit the talk: {} +- add another co-speaker: {} + +If you have any question, your can answer to this email. + +Thanks! + +{} + +""").format( + edited_speaker.name, speaker.name, request.conference.name, + talk.title, talk.description, + url_dashboard, url_talk_details, url_speaker_add, + request.conference.name, + ) + Message.objects.create( + thread=edited_speaker.conversation, + author=request.conference, + from_email=request.conference.contact_email, + content=body, + ) + messages.success(request, _('Co-speaker successfully added to the talk.')) #return redirect(reverse('proposal-speaker-details', kwargs=dict(speaker_token=speaker.token, talk_id=talk.pk))) return redirect(reverse('proposal-talk-details', kwargs=dict(speaker_token=speaker.token, talk_id=talk.pk))) else: diff --git a/locale/fr/LC_MESSAGES/django.mo b/locale/fr/LC_MESSAGES/django.mo index 731ab28f779e900cd0b78be40671dc52cf19180a..62cf5537c7e6fed2d9cb8525c88498302e07a6dd 100644 GIT binary patch delta 6060 zcmYk=33L=i0><$Q#ab>YF49eU{j<$WXv`S8u5FmfqaC~_&IjMudxdzw{|vCOrb6i zMh)}{+x`sd_}8!{Zb8k+9@LB-K@F%Lb^aL)spH=$Xv8rrpr$4nJ(z|aa4=@!47?Io zVlHk*t$jUeM$Vz`Fp&pI*U7TxqB`t~+TR;>UTHe(pGl#dhWBw9F2^x#SU)_5**uIl zwlyXnXSZ|jc#Y#;;1$$E_%`y7*~7mykWe`L_+2GqkAz-XL@8ej_SkIKj;M!Z7-|5MQ6rv#dWb@(j+UU-FpSZ-8`Z%+R0jua`%%=5eTSNn z)7GRM%>e74ML~CT73#!d)YK0{U3dac!YQbM?LsX@J!;9~JGd8ikQc!8LcM;asN>48 z8!okOM}45qU_AYsCLP_8w?y6X<)}N(z*zKHd!nYi7#m{=YJjDv<8MZtUuLaB&Bz_7 zJ70_%&{H@Rw_~W1LSiTPj^`q6X1T3z#?I9DqVDXx^)ecHGfh`(30_4#fCac3^~KzW zx?WVSy9Aw41L}slvBF&Dzm!5h+py9e@U*Qzk8$jO3FEOAH3M6bZS)(oBsBQSeY$iW=co)E(}`LOg)YFeTspm1~cDD$Een zlK7ETF-uV$Z$!ps-o&PO95qAd?EVYbh!>DiiU!Hz9qzF8J+2|MpMs|HfZcH(heXl9{0xDiUELp> zM^P87!^mrhdj0A#6EE2P8N6#+<6P8lKo46VjT(R#b$$i5(ffZlg%&hChx+;5h$*-W zHT6fZ2cAM*ActR+zUZ+AQ3I*9erWv)HIVbD>&EgRXlB}2voJyLe;x(>*z`nAZ7Fgy zW-M~9S&lmKUDQLh8>eDDYH3OsT`Jy+8ekPR#|5bU%PNZU52f24eHt0hMLJ8sPp!tuJc(>=3i6v zwcT+F`%*uP%(m&-%YEo7F^Bp}9Esae&rC~R5#8CPyh_8l-p0IuHATi$(msN}IDNS78h7LwecjitGwKenLp^-Apzd%H zcE$%$--WHX0)NBR_;5e|`oV&0d63Z`qM)fQ=2OwAE_r$5A$Z!v+^$L890a?^#1=ufmJYVuX7&~FKUGM zqB?vO>6CZorW4 zU>gNZSsm)baR6iSThu^)Ks^(`U;?%rYQGPt_Kv8BvOns3Fc#H;-?q<2hx&5#;X1qv z(}pqskuTFQ_vv4cTAL%Nk^hQXL(dKF(>?V!;N&%-9vuSVTrF*-N~^%l%Q4fuA{jIF?C_@r%r z2{mIoFcJ4+E`El27$3UP{dw$;>Zmtr2?nB09F1CIFBanM*acrlFV>?5Jh;R?zXY|$ zV^K3R8?V6)$f4#m_Qe5wMhh@>HwAV4Pi&6wU^m=v>+z%9_rEo2Df*#07>6F5j~c)$ zn2(!KGjR+X;Yrl>e?-mLdDM(w#HRFb;%;(Zn^cTuM;2f;C-aH6XUGDg z`P@xrkm*F5rs{)8i63}tWBPcW@=2nHfGuQ>@oz1Zw)Nx*GKMTC>0}>ymfTCuks5O8 zrZ3KEveh?fGxSMzJDsqA7TivjYrtk*wley$)l11JldN1E1yU2a&|5ehF=u4sRMqV zEv&$qpBgG`10cm^KCGyEzNcmPU{hDj^4jsM2s}43GKnFNkP6bUt)wuUv?u*+ z<8l1Wmb+Siv5IVx7{#BxZ7ym2kn+?^>KT;hTvFde`7!d5ZF?Q3*)lJ^d5!cXsbnlk zBA=5rBsP4aRZggs(hj2SYceWQ;;$r3BOA$gB!+27uv3vjy_{%!iu5Kw5r^nIGl6Kk zncPOslbxiHyhN&qw((lr<`n)x{!XIk;A!kZz926WZArB6!M{an{B?{atuT$xyP5j3ljz zHvOf2wAPn)I(}riGk-yDLc;t7j(5@|XKrAo1kR^6)@)`Q*9Igt<tP)9RS26 delta 5765 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 Date: Sat, 4 Nov 2017 21:37:53 +0100 Subject: [PATCH 7/7] handle closed cfp --- cfp/templates/cfp/closed.html | 18 ++++++++++++++++++ cfp/templates/cfp/proposal_dashboard.html | 2 ++ cfp/templates/cfp/proposal_talk_details.html | 2 ++ cfp/views.py | 2 ++ 4 files changed, 24 insertions(+) create mode 100644 cfp/templates/cfp/closed.html diff --git a/cfp/templates/cfp/closed.html b/cfp/templates/cfp/closed.html new file mode 100644 index 0000000..3fc2bc3 --- /dev/null +++ b/cfp/templates/cfp/closed.html @@ -0,0 +1,18 @@ +{% extends 'base.html' %} +{% load i18n %} + +{% block proposetab %} class="active"{% endblock %} + +{% block content %} + + +

    {% trans "Sorry, the Call for Participation is closed!" %}

    + +{% url 'proposal-mail-token' as mail_token_url %} +

    {% blocktrans %}If you already have submitted a talk and you want to edit it, please click here.{% endblocktrans %}

    + +{% endblock %} diff --git a/cfp/templates/cfp/proposal_dashboard.html b/cfp/templates/cfp/proposal_dashboard.html index c1d3b28..0fabb3c 100644 --- a/cfp/templates/cfp/proposal_dashboard.html +++ b/cfp/templates/cfp/proposal_dashboard.html @@ -71,7 +71,9 @@ {% trans "No proposals." %} {% endfor %}

    +{% if conference.opened_categories.exists %}

    {% trans "New proposal" %}

    +{% endif %} {% endblock %} diff --git a/cfp/templates/cfp/proposal_talk_details.html b/cfp/templates/cfp/proposal_talk_details.html index 5707479..7a0fd6a 100644 --- a/cfp/templates/cfp/proposal_talk_details.html +++ b/cfp/templates/cfp/proposal_talk_details.html @@ -13,9 +13,11 @@  {% trans "My profile" %} + {% if conference.opened_categories.exists %}  {% trans "New proposal" %} + {% endif %}  {% trans "Edit this proposal" %} diff --git a/cfp/views.py b/cfp/views.py index 416c6e9..b02ad68 100644 --- a/cfp/views.py +++ b/cfp/views.py @@ -143,6 +143,8 @@ def proposal_home(request): 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) 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])):