From b72e9c9180e78e5b0512babb3040046b81207f44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89lie=20Bouttier?= Date: Wed, 8 Nov 2017 20:17:56 +0100 Subject: [PATCH] downloads talks, speakers and volunteers as CSV --- cfp/models.py | 34 +++ cfp/templates/cfp/staff/participant_list.html | 6 +- cfp/templates/cfp/staff/talk_list.html | 7 + cfp/templates/cfp/staff/volunteer_list.html | 6 +- cfp/views.py | 70 ++++-- locale/fr/LC_MESSAGES/django.mo | Bin 22833 -> 22884 bytes locale/fr/LC_MESSAGES/django.po | 227 +++++++++--------- 7 files changed, 222 insertions(+), 128 deletions(-) diff --git a/cfp/models.py b/cfp/models.py index 5e217a6..c0d57c6 100644 --- a/cfp/models.py +++ b/cfp/models.py @@ -13,6 +13,7 @@ from django.utils.html import escape, format_html from autoslug import AutoSlugField from colorful.fields import RGBColorField +from functools import partial import uuid from datetime import timedelta @@ -124,6 +125,9 @@ class Participant(PonyConfModel): url = ('https' if self.site.conference.secure_domain else 'http') + '://' + self.site.domain + url return url + def get_csv_row(self): + return map(partial(getattr, self), ['pk', 'name', 'email', 'biography', 'twitter', 'linkedin', 'github', 'website', 'facebook', 'mastodon', 'phone_number', 'notes']) + class Meta: # A User can participe only once to a Conference (= Site) unique_together = ('site', 'name') @@ -392,6 +396,26 @@ class Talk(PonyConfModel): def get_tags_html(self): return mark_safe(' '.join(map(lambda tag: tag.link, self.tags.all()))) + def get_csv_row(self): + return [ + self.pk, + self.title, + self.description, + self.category, + self.track, + [speaker.pk for speaker in self.speakers.all()], + [speaker.name for speaker in self.speakers.all()], + [tag.name for tag in self.tags.all()], + 1 if self.videotaped else 0, + self.video_licence, + 1 if self.sound else 0, + self.estimated_duration, + self.room, + 1 if self.plenary else 0, + self.materials, + self.video, + ] + @property def estimated_duration(self): return self.duration or self.category.duration @@ -450,6 +474,16 @@ class Volunteer(PonyConfModel): url = ('https' if self.site.conference.secure_domain else 'http') + '://' + self.site.domain + url return url + def get_csv_row(self): + return [ + self.pk, + self.name, + self.email, + self.phone_number, + 1 if self.sms_prefered else 0, + self.notes, + ] + class Meta: # A volunteer can participe only once to a Conference (= Site) unique_together = ('site', 'email') diff --git a/cfp/templates/cfp/staff/participant_list.html b/cfp/templates/cfp/staff/participant_list.html index 7c19cd0..6edde20 100644 --- a/cfp/templates/cfp/staff/participant_list.html +++ b/cfp/templates/cfp/staff/participant_list.html @@ -39,7 +39,11 @@ - {% trans "Contact:" %} {% trans "link" %} + + {% trans "contact by email" %} + | + {% trans "download as csv" %} + {% for participant in participant_list %} diff --git a/cfp/templates/cfp/staff/talk_list.html b/cfp/templates/cfp/staff/talk_list.html index 9d1b26e..2ce3a09 100644 --- a/cfp/templates/cfp/staff/talk_list.html +++ b/cfp/templates/cfp/staff/talk_list.html @@ -48,6 +48,13 @@ {% trans "Status" %} + + + + {% trans "download as csv" %} + + + {% for talk in talk_list %} {% if forloop.first %} diff --git a/cfp/templates/cfp/staff/volunteer_list.html b/cfp/templates/cfp/staff/volunteer_list.html index 55b17c5..359a405 100644 --- a/cfp/templates/cfp/staff/volunteer_list.html +++ b/cfp/templates/cfp/staff/volunteer_list.html @@ -34,7 +34,11 @@ - {% trans "Contact:" %} {% trans "link" %} + + {% trans "contact by email" %} + | + {% trans "download as csv" %} + {% for volunteer in volunteer_list %} diff --git a/cfp/views.py b/cfp/views.py index 7104064..26d6109 100644 --- a/cfp/views.py +++ b/cfp/views.py @@ -17,6 +17,7 @@ from django.forms import modelform_factory from django_select2.views import AutoResponseView from functools import reduce +import csv from mailing.models import Message from mailing.forms import MessageForm @@ -106,9 +107,9 @@ def volunteer_update_activity(request, volunteer, activity, join): @staff_required def volunteer_list(request): site = request.conference.site - show_filters = False filter_form = VolunteerFilterForm(request.GET or None, site=site) # Filtering + show_filters = False volunteers = Volunteer.objects.filter(site=site).order_by('pk').distinct().prefetch_related('activities') if filter_form.is_valid(): data = filter_form.cleaned_data @@ -121,13 +122,25 @@ def volunteer_list(request): if len(data['activity']): q |= Q(activities__slug__in=data['activity']) volunteers = volunteers.filter(q) - contact_link = 'mailto:' + ','.join([volunteer.email for volunteer in volunteers.all()]) - return render(request, 'cfp/staff/volunteer_list.html', { - 'volunteer_list': volunteers, - 'filter_form': filter_form, - 'show_filters': show_filters, - 'contact_link': contact_link, - }) + if request.GET.get('format') == 'csv': + response = HttpResponse(content_type='text/csv') + response['Content-Disposition'] = 'attachment; filename="volunteers.csv"' + writer = csv.writer(response) + for volunteer in volunteers: + writer.writerow(volunteer.get_csv_row()) + return response + else: + contact_link = 'mailto:' + ','.join([volunteer.email for volunteer in volunteers.all()]) + csv_query_dict = request.GET.copy() + csv_query_dict['format'] = 'csv' + csv_link = '?' + csv_query_dict.urlencode() + return render(request, 'cfp/staff/volunteer_list.html', { + 'volunteer_list': volunteers, + 'filter_form': filter_form, + 'show_filters': show_filters, + 'contact_link': contact_link, + 'csv_link': csv_link, + }) @staff_required @@ -538,6 +551,16 @@ def talk_list(request): talks = talks.exclude(video__exact='') else: talks = talks.filter(video__exact='') + talks = talks.prefetch_related('category', 'speakers', 'track', 'tags') + + if request.GET.get('format') == 'csv': + response = HttpResponse(content_type='text/csv') + response['Content-Disposition'] = 'attachment; filename="talks.csv"' + writer = csv.writer(response) + for talk in talks: + writer.writerow(talk.get_csv_row()) + return response + # Action action_form = TalkActionForm(request.POST or None, talks=talks, site=request.conference.site) if request.method == 'POST' and action_form.is_valid(): @@ -592,7 +615,9 @@ def talk_list(request): glyphicon = 'sort' sort_urls[c] = url.urlencode() sort_glyphicons[c] = glyphicon - talks = talks.prefetch_related('category', 'speakers', 'track', 'tags') + csv_query_dict = request.GET.copy() + csv_query_dict['format'] = 'csv' + csv_link = '?' + csv_query_dict.urlencode() return render(request, 'cfp/staff/talk_list.html', { 'show_filters': show_filters, 'talk_list': talks, @@ -600,6 +625,7 @@ def talk_list(request): 'action_form': action_form, 'sort_urls': sort_urls, 'sort_glyphicons': sort_glyphicons, + 'csv_link': csv_link, }) @@ -691,13 +717,25 @@ def participant_list(request): q |= Q(track__slug__in=data['track']) talks = talks.filter(q) participants = participants.filter(talk__in=talks) - contact_link = 'mailto:' + ','.join([participant.email for participant in participants.all()]) - return render(request, 'cfp/staff/participant_list.html', { - 'filter_form': filter_form, - 'participant_list': participants, - 'show_filters': show_filters, - 'contact_link': contact_link, - }) + if request.GET.get('format') == 'csv': + response = HttpResponse(content_type='text/csv') + response['Content-Disposition'] = 'attachment; filename="participants.csv"' + writer = csv.writer(response) + for participant in participants: + writer.writerow(participant.get_csv_row()) + return response + else: + contact_link = 'mailto:' + ','.join([participant.email for participant in participants.all()]) + csv_query_dict = request.GET.copy() + csv_query_dict['format'] = 'csv' + csv_link = '?' + csv_query_dict.urlencode() + return render(request, 'cfp/staff/participant_list.html', { + 'filter_form': filter_form, + 'participant_list': participants, + 'show_filters': show_filters, + 'contact_link': contact_link, + 'csv_link': csv_link, + }) @staff_required diff --git a/locale/fr/LC_MESSAGES/django.mo b/locale/fr/LC_MESSAGES/django.mo index b10b1718d6745162fa76460ea7ba1e7aa9bd2546..10fc2e445ec3dc94099bdd3e97012c4a73722d3f 100644 GIT binary patch delta 5897 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 Tt}!XD?6mCck(s&8``-Nn%8QB= delta 5846 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 AQvd(} diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index 6191abb..800bb99 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-07 23:13+0000\n" -"PO-Revision-Date: 2017-11-08 00:14+0100\n" +"POT-Creation-Date: 2017-11-08 19:16+0000\n" +"PO-Revision-Date: 2017-11-08 20:17+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:227 cfp/models.py:369 +#: cfp/forms.py:29 cfp/forms.py:130 cfp/forms.py:227 cfp/models.py:373 msgid "Confirmed" msgstr "Confirmé" -#: cfp/forms.py:30 cfp/models.py:371 +#: cfp/forms.py:30 cfp/models.py:375 msgid "Cancelled" msgstr "Annulé" -#: cfp/forms.py:62 cfp/models.py:470 +#: cfp/forms.py:62 cfp/models.py:504 msgid "Activity" msgstr "Activité" @@ -65,13 +65,13 @@ msgstr "Catégorie" msgid "Title" msgstr "Titre" -#: cfp/forms.py:108 cfp/models.py:154 cfp/models.py:465 +#: cfp/forms.py:108 cfp/models.py:158 cfp/models.py:499 #: cfp/templates/cfp/proposal_talk_details.html:75 #: cfp/templates/cfp/staff/talk_details.html:64 msgid "Description" msgstr "Description" -#: cfp/forms.py:109 cfp/models.py:111 cfp/models.py:440 +#: cfp/forms.py:109 cfp/models.py:112 cfp/models.py:464 #: cfp/templates/cfp/staff/participant_details.html:19 #: cfp/templates/cfp/staff/talk_details.html:78 #: cfp/templates/cfp/staff/volunteer_details.html:22 @@ -82,7 +82,7 @@ msgstr "Notes" msgid "Visible by speakers" msgstr "Visible par les orateurs" -#: cfp/forms.py:136 cfp/forms.py:233 cfp/models.py:326 +#: cfp/forms.py:136 cfp/forms.py:233 cfp/models.py:330 #: 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:343 +#: cfp/forms.py:160 cfp/models.py:347 #: cfp/templates/cfp/staff/talk_details.html:54 msgid "Materials" msgstr "Supports" @@ -161,7 +161,7 @@ msgstr "Assigner à une salle" msgid "Notify by mail?" msgstr "Notifier par e-mail ?" -#: cfp/forms.py:249 cfp/models.py:435 +#: cfp/forms.py:249 cfp/models.py:459 #: cfp/templates/cfp/staff/volunteer_list.html:30 msgid "Email" msgstr "E-mail" @@ -180,63 +180,63 @@ msgstr "Un utilisateur avec ce prénom et ce nom existe déjà." msgid "A user with that email already exists." msgstr "Un utilisateur avec cet email existe déjà." -#: cfp/models.py:29 +#: cfp/models.py:30 msgid "Conference name" msgstr "Nom de la conférence" -#: cfp/models.py:30 +#: cfp/models.py:31 msgid "Homepage (markdown)" msgstr "Page d’accueil (markdown)" -#: cfp/models.py:31 +#: cfp/models.py:32 msgid "Venue information" msgstr "Informations sur le lieu" -#: cfp/models.py:32 +#: cfp/models.py:33 msgid "City" msgstr "Ville" -#: cfp/models.py:33 +#: cfp/models.py:34 msgid "Contact email" msgstr "Email de contact" -#: cfp/models.py:34 +#: cfp/models.py:35 msgid "Reply email" msgstr "Adresse de réponse" -#: cfp/models.py:35 +#: cfp/models.py:36 msgid "Staff members" msgstr "Membres du staff" -#: cfp/models.py:36 +#: cfp/models.py:37 msgid "Secure domain (HTTPS)" msgstr "Domaine sécurisé (HTTPS)" -#: cfp/models.py:37 +#: cfp/models.py:38 msgid "Acceptances disclosure date" msgstr "Date de divulgation des acceptations" -#: cfp/models.py:38 +#: cfp/models.py:39 msgid "Schedule publishing date" msgstr "Date de publication du programme" -#: cfp/models.py:39 +#: cfp/models.py:40 msgid "Schedule redirection URL" msgstr "URL de redirection du programme" -#: cfp/models.py:40 +#: cfp/models.py:41 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:41 +#: cfp/models.py:42 msgid "Volunteers enrollment opening date" msgstr "Date d’ouverture de l’appel à bénévole" -#: cfp/models.py:42 +#: cfp/models.py:43 msgid "Volunteers enrollment closing date" msgstr "Date de fermeture de l’appel à bénévole" -#: cfp/models.py:79 +#: cfp/models.py:80 #, python-brace-format msgid "" "The reply email should be a formatable string accepting a token argument (e." @@ -245,74 +245,74 @@ 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:152 cfp/models.py:204 cfp/models.py:463 +#: cfp/models.py:100 cfp/models.py:156 cfp/models.py:208 cfp/models.py:497 #: cfp/templates/cfp/staff/participant_list.html:35 #: cfp/templates/cfp/staff/volunteer_list.html:29 msgid "Name" msgstr "Nom" -#: cfp/models.py:101 cfp/templates/cfp/proposal_dashboard.html:33 +#: cfp/models.py:102 cfp/templates/cfp/proposal_dashboard.html:33 #: cfp/templates/cfp/staff/participant_details.html:15 msgid "Biography" msgstr "Biographie" -#: cfp/models.py:103 +#: cfp/models.py:104 msgid "Twitter" msgstr "Twitter" -#: cfp/models.py:104 +#: cfp/models.py:105 msgid "LinkedIn" msgstr "LinkedIn" -#: cfp/models.py:105 +#: cfp/models.py:106 msgid "Github" msgstr "Github" -#: cfp/models.py:106 +#: cfp/models.py:107 msgid "Website" msgstr "Site web" -#: cfp/models.py:107 +#: cfp/models.py:108 msgid "Facebook" msgstr "Facebook" -#: cfp/models.py:108 +#: cfp/models.py:109 msgid "Mastodon" msgstr "Mastodon" -#: cfp/models.py:109 cfp/models.py:437 +#: cfp/models.py:110 cfp/models.py:461 msgid "Phone number" msgstr "Numéro de téléphone" -#: cfp/models.py:112 cfp/models.py:325 +#: cfp/models.py:113 cfp/models.py:329 msgid "This field is only visible by organizers." msgstr "Ce champs est uniquement visible par les organisateurs." -#: cfp/models.py:113 cfp/templates/cfp/staff/participant_details.html:25 +#: cfp/models.py:114 cfp/templates/cfp/staff/participant_details.html:25 msgid "Invited speaker" msgstr "Orateur invité" -#: cfp/models.py:206 +#: cfp/models.py:210 msgid "Color" msgstr "Couleur" -#: cfp/models.py:208 +#: cfp/models.py:212 msgid "Show the tag on the program" msgstr "Afficher l’étiquette sur le programme" -#: cfp/models.py:244 +#: cfp/models.py:248 msgid "Default duration (min)" msgstr "Durée par défaut (min)" -#: cfp/models.py:245 +#: cfp/models.py:249 msgid "Color on program" msgstr "Couleur sur le programme" -#: cfp/models.py:246 +#: cfp/models.py:250 msgid "Label on program" msgstr "Label dans le xml du programme" -#: cfp/models.py:320 cfp/templates/cfp/proposal_talk_details.html:53 +#: cfp/models.py:324 cfp/templates/cfp/proposal_talk_details.html:53 #: cfp/templates/cfp/staff/base.html:11 #: cfp/templates/cfp/staff/participant_list.html:8 #: cfp/templates/cfp/staff/talk_details.html:68 @@ -320,19 +320,19 @@ msgstr "Label dans le xml du programme" msgid "Speakers" msgstr "Orateurs" -#: cfp/models.py:321 +#: cfp/models.py:325 msgid "Talk Title" msgstr "Titre de la proposition" -#: cfp/models.py:324 +#: cfp/models.py:328 msgid "Description of your talk" msgstr "Description de votre proposition" -#: cfp/models.py:328 cfp/templates/cfp/proposal_talk_details.html:85 +#: cfp/models.py:332 cfp/templates/cfp/proposal_talk_details.html:85 msgid "Message to organizers" msgstr "Message aux organisateurs" -#: cfp/models.py:329 +#: cfp/models.py:333 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 " @@ -342,67 +342,67 @@ msgstr "" "votre proposition, comme une vidéo, des slides, n'hésitez pas à les ajouter " "ici." -#: cfp/models.py:332 +#: cfp/models.py:336 msgid "Talk Category" msgstr "Catégorie de proposition" -#: cfp/models.py:333 +#: cfp/models.py:337 msgid "I'm ok to be recorded on video" msgstr "J’accepte d’être enregistré en vidéo" -#: cfp/models.py:335 +#: cfp/models.py:339 msgid "Video licence" msgstr "Licence vidéo" -#: cfp/models.py:336 +#: cfp/models.py:340 msgid "I need sound" msgstr "J’ai besoin de son" -#: cfp/models.py:339 +#: cfp/models.py:343 msgid "Beginning date and time" msgstr "Date et heure de début" -#: cfp/models.py:340 +#: cfp/models.py:344 msgid "Duration (min)" msgstr "Durée (min)" -#: cfp/models.py:344 +#: cfp/models.py:348 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:373 +#: cfp/models.py:377 msgid "Waiting confirmation" msgstr "En attente de confirmation" -#: cfp/models.py:375 +#: cfp/models.py:379 msgid "Refused" msgstr "Refusé" -#: cfp/models.py:377 +#: cfp/models.py:381 #, python-format msgid "Pending decision, score: %(score).1f" msgstr "En cours, score : %(score).1f" -#: cfp/models.py:434 +#: cfp/models.py:458 msgid "Your Name" msgstr "Votre Nom" -#: cfp/models.py:438 +#: cfp/models.py:462 msgid "SMS prefered" msgstr "SMS préférés" -#: cfp/models.py:441 +#: cfp/models.py:465 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:466 cfp/templates/cfp/staff/volunteer_details.html:8 +#: cfp/models.py:500 cfp/templates/cfp/staff/volunteer_details.html:8 msgid "Volunteer" msgstr "Bénévole" -#: cfp/models.py:471 cfp/templates/cfp/admin/activity_list.html:9 +#: cfp/models.py:505 cfp/templates/cfp/admin/activity_list.html:9 #: cfp/templates/cfp/admin/base.html:13 #: cfp/templates/cfp/staff/volunteer_details.html:27 #: cfp/templates/cfp/staff/volunteer_list.html:32 @@ -603,7 +603,7 @@ msgstr "avec" #: 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 +#: cfp/templates/cfp/staff/talk_list.html:69 msgid "and" msgstr "et" @@ -830,31 +830,32 @@ msgstr "orateur" msgid "Talk count" msgstr "Nombre d’exposé" -#: cfp/templates/cfp/staff/participant_list.html:43 -#: cfp/templates/cfp/staff/volunteer_list.html:37 -msgid "Contact:" -msgstr "Contacter :" +#: cfp/templates/cfp/staff/participant_list.html:44 +#: cfp/templates/cfp/staff/volunteer_list.html:38 +msgid "contact by email" +msgstr "contacter par e-mail" -#: cfp/templates/cfp/staff/participant_list.html:43 -#: cfp/templates/cfp/staff/volunteer_list.html:37 -msgid "link" -msgstr "lien" +#: cfp/templates/cfp/staff/participant_list.html:46 +#: cfp/templates/cfp/staff/talk_list.html:54 +#: cfp/templates/cfp/staff/volunteer_list.html:40 +msgid "download as csv" +msgstr "télécharger au format CSV" -#: cfp/templates/cfp/staff/participant_list.html:56 +#: cfp/templates/cfp/staff/participant_list.html:60 #, 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:58 +#: cfp/templates/cfp/staff/participant_list.html:62 #, 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:60 +#: cfp/templates/cfp/staff/participant_list.html:64 #, python-format msgid "refused: %(refused)s" msgid_plural "refused: %(refused)s" @@ -1016,11 +1017,11 @@ msgstr "Éditer un exposé" msgid "Intervention kind" msgstr "Type d’intervention" -#: cfp/templates/cfp/staff/talk_list.html:80 +#: cfp/templates/cfp/staff/talk_list.html:87 msgid "For selected talks:" msgstr "Pour les exposés sélectionnés :" -#: cfp/templates/cfp/staff/talk_list.html:85 +#: cfp/templates/cfp/staff/talk_list.html:92 msgid "Apply" msgstr "Appliquer" @@ -1078,7 +1079,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:51 +#: cfp/views.py:52 msgid "" "Hi {},\n" "\n" @@ -1106,26 +1107,26 @@ msgstr "" "{}\n" "\n" -#: cfp/views.py:71 +#: cfp/views.py:72 msgid "Thank you for your help!" msgstr "Merci pour votre aide !" -#: cfp/views.py:76 +#: cfp/views.py:77 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:98 +#: cfp/views.py:99 msgid "Thank you for your participation!" msgstr "Merci pour votre participation !" -#: cfp/views.py:102 +#: cfp/views.py:103 msgid "Okay, no problem!" msgstr "Ok, pas de soucis !" -#: cfp/views.py:174 +#: cfp/views.py:187 msgid "" "Hi {},\n" "\n" @@ -1165,15 +1166,15 @@ msgstr "" "{}\n" "\n" -#: cfp/views.py:204 cfp/views.py:288 +#: cfp/views.py:217 cfp/views.py:301 msgid "You proposition have been successfully submitted!" msgstr "Votre proposition a été transmise avec succès !" -#: cfp/views.py:218 +#: cfp/views.py:231 msgid "Sorry, we do not know this email." msgstr "Désolé, nous ne connaissons pas cette e-mail." -#: cfp/views.py:223 +#: cfp/views.py:236 msgid "" "Hi {},\n" "\n" @@ -1204,41 +1205,41 @@ msgstr "" "{}\n" "\n" -#: cfp/views.py:243 +#: cfp/views.py:256 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:284 cfp/views.py:357 +#: cfp/views.py:297 cfp/views.py:370 msgid "Changes saved." msgstr "Modifications sauvegardées." -#: cfp/views.py:305 +#: cfp/views.py:318 msgid "You already confirmed your participation to this talk." msgstr "Vous avez déjà confirmé votre participation à cet exposé." -#: cfp/views.py:307 +#: cfp/views.py:320 msgid "You already cancelled your participation to this talk." msgstr "Vous avez déjà annulé votre participation à cet exposé." -#: cfp/views.py:312 +#: cfp/views.py:325 msgid "Your participation has been taken into account, thank you!" msgstr "Votre participation a été prise en compte, merci !" -#: cfp/views.py:313 +#: cfp/views.py:326 #, python-format msgid "Speaker %(speaker)s confirmed his/her participation." msgstr "L’intervenant %(speaker)s a confirmé sa participation." -#: cfp/views.py:315 +#: cfp/views.py:328 msgid "We have noted your unavailability." msgstr "Nous avons enregistré votre indisponibilité." -#: cfp/views.py:316 +#: cfp/views.py:329 #, python-format msgid "Speaker %(speaker)s CANCELLED his/her participation." msgstr "L’intervenant %(speaker)s a ANNULÉ sa participation." -#: cfp/views.py:364 +#: cfp/views.py:377 msgid "" "Hi {},\n" "\n" @@ -1278,59 +1279,59 @@ msgstr "" "{}\n" "\n" -#: cfp/views.py:395 cfp/views.py:415 +#: cfp/views.py:408 cfp/views.py:428 msgid "Co-speaker successfully added to the talk." msgstr "Co-intervenant ajouté à l’exposé avec succès." -#: cfp/views.py:428 +#: cfp/views.py:441 msgid "Co-speaker successfully removed from the talk." msgstr "Co-intervenant supprimé de l’exposé avec succès." -#: cfp/views.py:470 +#: cfp/views.py:483 msgid "The speaker confirmation have been noted." msgstr "La confirmation de l’orateur a été notée." -#: cfp/views.py:471 +#: cfp/views.py:484 msgid "The talk have been confirmed." msgstr "L’exposé a été confirmé." -#: cfp/views.py:473 +#: cfp/views.py:486 msgid "The speaker unavailability have been noted." msgstr "L’indisponibilité de l’intervenant a été notée." -#: cfp/views.py:474 +#: cfp/views.py:487 msgid "The talk have been cancelled." msgstr "L’exposé a été annulé." -#: cfp/views.py:549 cfp/views.py:651 +#: cfp/views.py:572 cfp/views.py:677 msgid "The talk has been accepted." msgstr "L’exposé a été accepté." -#: cfp/views.py:551 cfp/views.py:653 +#: cfp/views.py:574 cfp/views.py:679 msgid "The talk has been declined." msgstr "L’exposé a été décliné." -#: cfp/views.py:620 cfp/views.py:713 +#: cfp/views.py:646 cfp/views.py:751 msgid "Message sent!" msgstr "Message envoyé !" -#: cfp/views.py:634 +#: cfp/views.py:660 msgid "Vote successfully created" msgstr "A voté !" -#: cfp/views.py:634 +#: cfp/views.py:660 msgid "Vote successfully updated" msgstr "Vote mis à jour" -#: cfp/views.py:655 +#: cfp/views.py:681 msgid "Decision taken in account" msgstr "Décision enregistrée" -#: cfp/views.py:748 +#: cfp/views.py:786 msgid "[{}] You have been added to the staff team" msgstr "[{}] Vous avez été ajouté aux membres du staff" -#: cfp/views.py:749 +#: cfp/views.py:787 msgid "" "Hi {},\n" "\n" @@ -1354,15 +1355,15 @@ msgstr "" "{}\n" "\n" -#: cfp/views.py:770 +#: cfp/views.py:808 msgid "Modifications successfully saved." msgstr "Modification enregistrée avec succès." -#: cfp/views.py:934 +#: cfp/views.py:972 msgid "User created successfully." msgstr "Utilisateur créé avec succès." -#: cfp/views.py:955 +#: cfp/views.py:993 #, python-format msgid "Format '%s' not available" msgstr "Format '%s' non disponible" @@ -1444,6 +1445,12 @@ msgstr "Changement de mot de passe" msgid "Email address" msgstr "Adresse e-mail" +#~ msgid "Contact:" +#~ msgstr "Contacter :" + +#~ msgid "link" +#~ msgstr "lien" + #~ msgid "The volunteer made a few remarks to the staff." #~ msgstr "Le bénévole a fait quelques remarques au staff."