staff: conference configuration

This commit is contained in:
Élie Bouttier 2017-07-30 20:11:13 +02:00
parent 04848c5067
commit 4538597daf
12 changed files with 240 additions and 121 deletions

View File

@ -1,18 +1,8 @@
from django.contrib.auth.mixins import UserPassesTestMixin
from .utils import is_orga, is_staff
class OrgaRequiredMixin(UserPassesTestMixin):
def test_func(self):
return is_orga(self.request, self.request.user)
from .utils import is_staff
class StaffRequiredMixin(UserPassesTestMixin):
def test_func(self):
return is_staff(self.request, self.request.user)
class SuperuserRequiredMixin(UserPassesTestMixin):
def test_func(self):
return self.request.user.is_superuser

View File

@ -1,7 +1,11 @@
from django import forms
from django.forms.models import modelform_factory
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from .models import Participant, Talk
from django_select2.forms import ModelSelect2MultipleWidget
from .models import Participant, Talk, Conference
class TalkForm(forms.ModelForm):
@ -19,3 +23,11 @@ class TalkForm(forms.ModelForm):
ParticipantForm = modelform_factory(Participant, fields=('name','email', 'biography'))
class UsersWidget(ModelSelect2MultipleWidget):
model = User
search_fields = [ '%s__icontains' % field for field in UserAdmin.search_fields ]
ConferenceForm = modelform_factory(Conference, fields=['name', 'home', 'venue', 'city', 'contact_email', 'staff',], widgets={'staff': UsersWidget(),})

8
cfp/mixins.py Normal file
View File

@ -0,0 +1,8 @@
from django.contrib.auth.mixins import UserPassesTestMixin
from .utils import is_staff
class StaffRequiredMixin(UserPassesTestMixin):
def test_func(self):
return is_staff(self.request, self.request.user)

View File

@ -33,12 +33,12 @@ from django.utils.translation import ugettext
class Conference(models.Model):
site = models.OneToOneField(Site, on_delete=models.CASCADE)
name = models.CharField(blank=True, max_length=100)
home = models.TextField(blank=True, default="")
venue = models.TextField(blank=True, default="")
city = models.CharField(max_length=64, blank=True, default="")
contact_email = models.CharField(max_length=100, blank=True)
staff = models.ManyToManyField(User, verbose_name=_('Staff'), blank=True)
name = models.CharField(blank=True, max_length=100, verbose_name=_('Conference name'))
home = models.TextField(blank=True, default="", verbose_name=_('Homepage (markdown)'))
venue = models.TextField(blank=True, default="", verbose_name=_('Venue information'))
city = models.CharField(max_length=64, blank=True, default="", verbose_name=_('City'))
contact_email = models.CharField(max_length=100, blank=True, verbose_name=_('Contact email'))
staff = models.ManyToManyField(User, blank=True, verbose_name=_('Staff members'))
custom_css = models.TextField(blank=True)
external_css_link = models.URLField(blank=True)

View File

@ -17,6 +17,7 @@
{% endcomment %}
<li{% block talkstab %}{% endblock %}><a href="{% url 'talk-list' %}"><span class="glyphicon glyphicon-blackboard"></span>&nbsp;{% trans "Talks" %}</a></li>
<li{% block speakerstab %}{% endblock %}><a href="{% url 'participant-list' %}"><span class="glyphicon glyphicon-bullhorn"></span>&nbsp;{% trans "Speakers" %}</a></li>
<li{% block conferencetab %}{% endblock %}><a href="{% url 'conference' %}"><span class="glyphicon glyphicon-asterisk"></span>&nbsp;{% trans "Conference" %}</a></li>
{% if request.user.is_staff %}
<li><a href="{% url 'admin:index' %}"><span class="glyphicon glyphicon-dashboard"></span>&nbsp;Django-Admin</a></li>
{% endif %}

View File

@ -0,0 +1,26 @@
{% extends 'cfp/staff/base.html' %}
{% load i18n crispy_forms_tags %}
{% block conferencetab %} class="active"{% endblock %}
{% block content %}
<h1>{% trans "Conference" %}</h1>
<form method="POST">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-primary">{% trans "Save" %}</button>
</form>
{% endblock %}
{% block js_end %}
{{ block.super }}
{{ form.media.js }}
{% endblock %}
{% block css %}
{{ block.super }}
{{ form.media.css }}
{% endblock %}

View File

@ -9,6 +9,7 @@ urlpatterns = [
url(r'^cfp/(?P<talk_id>[\w\-]+)/speaker/(?P<participant_id>[\w\-]+)/$', views.talk_proposal_speaker_edit, name='talk-proposal-speaker-edit'),
url(r'^cfp/(?P<talk_id>[\w\-]+)/(?P<participant_id>[\w\-]+)/$', views.talk_proposal, name='talk-proposal-edit'),
url(r'^staff/$', views.staff, name='staff'),
url(r'^staff/conference/$', views.conference, name='conference'),
url(r'^staff/talks/$', views.talk_list, name='talk-list'),
url(r'^staff/talks/(?P<talk_id>[\w\-]+)/$', views.talk_details, name='talk-details'),
url(r'^staff/talks/(?P<talk_id>[\w\-]+)/vote/(?P<score>[-+0-2]+)/$', views.talk_vote, name='talk-vote'),
@ -16,6 +17,7 @@ urlpatterns = [
url(r'^staff/talks/(?P<talk_id>[\w\-]+)/decline/$', views.talk_decide, {'accept': False}, name='talk-decline'),
url(r'^staff/speakers/$', views.participant_list, name='participant-list'),
url(r'^staff/speakers/(?P<participant_id>[\w\-]+)/$', views.participant_details, name='participant-details'),
url(r'^staff/select2/$', views.Select2View.as_view(), name='django_select2-json'),
#url(r'^markdown/$', views.markdown_preview, name='markdown'),
#url(r'^$', views.home, name='home'),

View File

@ -6,10 +6,13 @@ from django.utils.translation import ugettext_lazy as _
from django.views.generic import FormView, TemplateView
from django.contrib import messages
from django_select2.views import AutoResponseView
from cfp.decorators import staff_required
from .mixins import StaffRequiredMixin
from .utils import is_staff
from .models import Participant, Talk, TalkCategory, Vote
from .forms import TalkForm, ParticipantForm
from .forms import TalkForm, ParticipantForm, ConferenceForm
def home(request, conference):
@ -193,3 +196,21 @@ def participant_details(request, conference, participant_id):
return render(request, 'cfp/staff/participant_details.html', {
'participant': participant,
})
@staff_required
def conference(request, conference):
form = ConferenceForm(request.POST or None, instance=conference)
if request.method == 'POST' and form.is_valid():
form.save()
messages.success(request, _('Modifications successfully saved.'))
return redirect(reverse('conference'))
return render(request, 'cfp/staff/conference.html', {
'form': form,
})
class Select2View(StaffRequiredMixin, AutoResponseView):
pass

Binary file not shown.

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-07-30 14:00+0000\n"
"POT-Creation-Date: 2017-07-30 18:07+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -106,7 +106,7 @@ msgstr "Biographie"
#: accounts/templates/accounts/participant_details.html:27
#: cfp/templates/cfp/staff/base.html:20
#: cfp/templates/cfp/staff/participant_details.html:32
#: cfp/templates/cfp/staff/participant_details.html:31
#: cfp/templates/cfp/staff/talk_list.html:8
#: proposals/templates/proposals/talk_list.html:9
msgid "Talks"
@ -173,7 +173,7 @@ msgid "Constraints"
msgstr "Contraintes"
#: accounts/templates/accounts/participant_details.html:71 cfp/models.py:87
#: cfp/templates/cfp/staff/participant_details.html:27
#: cfp/templates/cfp/staff/participant_details.html:14
#: cfp/templates/cfp/staff/talk_details.html:92 proposals/models.py:161
#: proposals/templates/proposals/talk_detail.html:102
msgid "Notes"
@ -214,7 +214,8 @@ msgstr "Changer davatar"
msgid "Submit"
msgstr "Envoyer"
#: accounts/templates/accounts/profile.html:36 ponyconf/templates/_form.html:16
#: accounts/templates/accounts/profile.html:36
#: cfp/templates/cfp/staff/talk_decide.html:27 ponyconf/templates/_form.html:16
#: proposals/templates/proposals/talk_decide.html:23
msgid "Cancel"
msgstr "Annuler"
@ -286,15 +287,35 @@ msgstr "%(name)s a été ajouté aux participants"
msgid "%(name)s is already a participant"
msgstr "%(name)s est déjà participant"
#: cfp/models.py:41 ponyconf/templates/base.html:36
msgid "Staff"
msgstr ""
#: cfp/models.py:36
msgid "Conference name"
msgstr "Nom de la conférence"
#: cfp/models.py:37
msgid "Homepage (markdown)"
msgstr "Page daccueil (markdown)"
#: cfp/models.py:38
msgid "Venue information"
msgstr "Informations sur le lieu"
#: cfp/models.py:39
msgid "City"
msgstr "Ville"
#: cfp/models.py:40
msgid "Contact email"
msgstr "Email de contact"
#: cfp/models.py:41
msgid "Staff members"
msgstr "Membres du staff"
#: cfp/models.py:70
msgid "Your Name"
msgstr "Votre Nom"
#: cfp/models.py:87 cfp/templates/cfp/staff/participant_details.html:28
#: cfp/models.py:87
msgid "This field is only visible by organizers."
msgstr "Ce champs est uniquement visible par les organisateurs."
@ -383,9 +404,19 @@ msgstr "Jai besoin de son"
msgid "Duration (min)"
msgstr "Durée (min)"
#: cfp/templates/cfp/closed.html:9 cfp/templates/cfp/propose.html:11
#: cfp/templates/cfp/speaker.html:11
#: proposals/templates/proposals/participate.html:9
msgid "Participate"
msgstr "Participer"
#: cfp/templates/cfp/closed.html:13
msgid "Sorry, the Call for Participation is closed!"
msgstr "Désolé, lappel à 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!"
msgstr "Votre proposition a été transmise avec succès !"
#: cfp/templates/cfp/complete.html:16
msgid "Thanks for your proposal"
@ -393,83 +424,84 @@ msgstr "Merci pour votre proposition"
#: cfp/templates/cfp/complete.html:17
msgid "You can at anytime:"
msgstr "Vous pouvez à tout moment:"
msgstr "Vous pouvez à tout moment :"
#: cfp/templates/cfp/complete.html:19
msgid "Edit your talk:"
msgstr "Éditer un exposé"
#: cfp/templates/cfp/complete.html:20
msgid "add an additionnal speaker:"
msgstr "ajouter un co-speaker:"
msgid "Add an additionnal speaker:"
msgstr "Ajouter un co-speaker :"
#: cfp/templates/cfp/complete.html:21
msgid "You can edit your profile:"
msgstr "Vous pouvez éditer votre profil:"
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/propose.html:11 cfp/templates/cfp/speaker.html:11
#: proposals/templates/proposals/participate.html:9
msgid "Participate"
msgstr "Participer"
#: cfp/templates/cfp/propose.html:22 cfp/templates/cfp/speaker.html:21
#: cfp/templates/cfp/staff/conference.html:13
msgid "Save"
msgstr "Envoyer"
#: cfp/templates/cfp/staff/base.html:19
#: cfp/templates/cfp/staff/conference.html:8
msgid "Conference"
msgstr "Conférence"
#: cfp/templates/cfp/staff/base.html:29
msgid "Please select a category."
msgstr "Veuillez sélectionner une catégorie."
#: cfp/templates/cfp/staff/participant_details.html:13
#: cfp/templates/cfp/staff/participant_details.html:18
msgid "Informations"
msgstr "Informations"
#: cfp/templates/cfp/staff/participant_details.html:15
#: cfp/templates/cfp/staff/participant_details.html:20
msgid "E-mail:"
msgstr "E-mail :"
#: cfp/templates/cfp/staff/participant_details.html:16
#: cfp/templates/cfp/staff/participant_details.html:21
msgid "Twitter:"
msgstr "Twitter :"
#: cfp/templates/cfp/staff/participant_details.html:17
#: cfp/templates/cfp/staff/participant_details.html:22
msgid "LinkedIn:"
msgstr "LinkedIn :"
#: cfp/templates/cfp/staff/participant_details.html:18
#: cfp/templates/cfp/staff/participant_details.html:23
msgid "Github:"
msgstr "Github :"
#: cfp/templates/cfp/staff/participant_details.html:19
#: cfp/templates/cfp/staff/participant_details.html:24
msgid "Website:"
msgstr "Website :"
#: cfp/templates/cfp/staff/participant_details.html:20
#: cfp/templates/cfp/staff/participant_details.html:25
msgid "Facebook:"
msgstr "Facebook :"
#: cfp/templates/cfp/staff/participant_details.html:21
#: cfp/templates/cfp/staff/participant_details.html:26
msgid "Mastodon:"
msgstr "Mastodon :"
#: cfp/templates/cfp/staff/participant_details.html:22
#: cfp/templates/cfp/staff/participant_details.html:27
msgid "Phone number:"
msgstr "Numéro de téléphone :"
#: cfp/templates/cfp/staff/participant_details.html:23
#: cfp/templates/cfp/staff/participant_details.html:28
msgid "Language:"
msgstr "Langue :"
#: cfp/templates/cfp/staff/participant_details.html:39
#: cfp/templates/cfp/staff/participant_details.html:38
#: proposals/templates/proposals/_talk_list.html:8
msgid "by"
msgstr "par"
#: cfp/templates/cfp/staff/participant_details.html:42
#: cfp/templates/cfp/staff/participant_details.html:41
#: cfp/templates/cfp/staff/talk_list.html:35
#: proposals/templates/proposals/_talk_list.html:11
#: proposals/templates/proposals/_talk_list.html:17
@ -477,12 +509,12 @@ msgstr "par"
msgid "and"
msgstr "et"
#: cfp/templates/cfp/staff/participant_details.html:45
#: cfp/templates/cfp/staff/participant_details.html:44
#: proposals/templates/proposals/_talk_list.html:14
msgid "in"
msgstr "dans la session"
#: cfp/templates/cfp/staff/participant_details.html:51
#: cfp/templates/cfp/staff/participant_details.html:50
#: proposals/templates/proposals/_talk_list.html:23
msgid "No talks"
msgstr "Aucun exposé"
@ -526,6 +558,41 @@ msgid_plural "refused: %(refused)s"
msgstr[0] "refusé : %(refused)s"
msgstr[1] "refusés : %(refused)s"
#: cfp/templates/cfp/staff/talk_decide.html:8
#: proposals/templates/proposals/talk_decide.html:9
msgid "Are you sure to accept this proposals?"
msgstr "Êtes-vous sûr daccepter cette propositon dintervention ?"
#: cfp/templates/cfp/staff/talk_decide.html:8
#: proposals/templates/proposals/talk_decide.html:9
msgid "Are you sure to decline this proposals?"
msgstr "Êtes-vous sûr de décliner cette propositon dintervention ?"
#: cfp/templates/cfp/staff/talk_decide.html:10
#: proposals/templates/proposals/talk_decide.html:11
msgid "Information about the proposals"
msgstr "Information sur la propositon dintervention"
#: cfp/templates/cfp/staff/talk_decide.html:11
#: proposals/templates/proposals/talk_decide.html:12
msgid "Title:"
msgstr "Titre :"
#: cfp/templates/cfp/staff/talk_decide.html:12
#: proposals/templates/proposals/talk_decide.html:13
msgid "Kind:"
msgstr "Type dintervention :"
#: cfp/templates/cfp/staff/talk_decide.html:26
#: proposals/templates/proposals/talk_decide.html:22
msgid "Accept the proposal"
msgstr "Accepter la proposition"
#: cfp/templates/cfp/staff/talk_decide.html:26
#: proposals/templates/proposals/talk_decide.html:22
msgid "Decline the proposal"
msgstr "Décliner la proposition"
#: cfp/templates/cfp/staff/talk_details.html:16
#: proposals/templates/proposals/talk_detail.html:19
msgid "No abstract provided."
@ -551,6 +618,33 @@ msgstr "Pas encore assignée."
msgid "No notes."
msgstr "Aucune note."
#: cfp/templates/cfp/staff/talk_details.html:96
#: proposals/templates/proposals/talk_detail.html:108
msgid "Moderation"
msgstr "Modération"
#: cfp/templates/cfp/staff/talk_details.html:98
#: cfp/templates/cfp/staff/talk_list.html:20
#: proposals/templates/proposals/talk_detail.html:110
#: proposals/templates/proposals/talk_list.html:52
msgid "Status"
msgstr "Statut"
#: cfp/templates/cfp/staff/talk_details.html:103
#: proposals/templates/proposals/talk_detail.html:115
msgid "Vote"
msgstr "Vote"
#: cfp/templates/cfp/staff/talk_details.html:112
#: proposals/templates/proposals/talk_detail.html:124
msgid "vote"
msgstr "vote"
#: cfp/templates/cfp/staff/talk_details.html:112
#: proposals/templates/proposals/talk_detail.html:124
msgid "average:"
msgstr "moyenne :"
#: cfp/templates/cfp/staff/talk_list.html:11
#: planning/templates/planning/room_list.html:28
#: proposals/templates/proposals/talk_list.html:43
@ -569,12 +663,6 @@ msgstr "Titre"
msgid "Intervention kind"
msgstr "Type dintervention"
#: cfp/templates/cfp/staff/talk_list.html:20
#: proposals/templates/proposals/talk_detail.html:110
#: proposals/templates/proposals/talk_list.html:52
msgid "Status"
msgstr "Statut"
#: cfp/templates/cfp/staff/talk_list.html:42
#: proposals/templates/proposals/talk_list.html:78
msgid "Accepted"
@ -591,11 +679,11 @@ msgstr "Décliné"
msgid "Pending, score: %(score)s"
msgstr "En cours, score : %(score)s"
#: cfp/views.py:53
#: cfp/views.py:62
msgid "Your talk \"{}\" has been submitted for {}"
msgstr "Votre proposition \"{}\" a été transmise à {}"
#: cfp/views.py:54
#: cfp/views.py:63
msgid ""
"Hi {},\n"
"\n"
@ -635,6 +723,24 @@ msgstr ""
"{}\n"
"\n"
#: cfp/views.py:154 proposals/views.py:321
msgid "Vote successfully created"
msgstr "A voté !"
#: cfp/views.py:154 proposals/views.py:321
msgid "Vote successfully updated"
msgstr "Vote mis à jour"
#: cfp/views.py:177 proposals/views.py:347
msgid "Decision taken in account"
msgstr "Décision enregistrée"
#: cfp/views.py:207
#, fuzzy
#| msgid "Vote successfully created"
msgid "Modifications successfully saved."
msgstr "A voté !"
#: conversations/templates/conversations/_message_form.html:4
msgid "Send a message"
msgstr "Envoyer un message"
@ -728,6 +834,10 @@ msgstr "Accueil"
msgid "Call for participation"
msgstr "Appel à participation"
#: ponyconf/templates/base.html:36
msgid "Staff"
msgstr ""
#: ponyconf/templates/base.html:50
#: ponyconf/templates/registration/login.html:10
msgid "Login"
@ -950,26 +1060,6 @@ msgstr "Contacter :"
msgid "link"
msgstr "lien"
#: proposals/templates/proposals/talk_decide.html:9
msgid "Are you sure to accept this proposals?"
msgstr "Êtes-vous sûr daccepter cette propositon dintervention ?"
#: proposals/templates/proposals/talk_decide.html:9
msgid "Are you sure to decline this proposals?"
msgstr "Êtes-vous sûr de décliner cette propositon dintervention ?"
#: proposals/templates/proposals/talk_decide.html:11
msgid "Information about the proposals"
msgstr "Information sur la propositon dintervention"
#: proposals/templates/proposals/talk_decide.html:12
msgid "Title:"
msgstr "Titre :"
#: proposals/templates/proposals/talk_decide.html:13
msgid "Kind:"
msgstr "Type dintervention :"
#: proposals/templates/proposals/talk_decide.html:15
msgid "Information for the proposer"
msgstr "Information à destination de lauteur de la proposition"
@ -983,14 +1073,6 @@ msgstr ""
"le ci-dessous. Noubliez pas de spécifier à quelle proposition "
"dintervention votre message fait référence."
#: proposals/templates/proposals/talk_decide.html:22
msgid "Accept the proposal"
msgstr "Accepter la proposition"
#: proposals/templates/proposals/talk_decide.html:22
msgid "Decline the proposal"
msgstr "Décliner la proposition"
#: proposals/templates/proposals/talk_detail.html:24
msgid "Format"
msgstr "Format"
@ -1030,22 +1112,6 @@ msgstr "Télécharger"
msgid "Assign to"
msgstr "Assigner à"
#: proposals/templates/proposals/talk_detail.html:108
msgid "Moderation"
msgstr "Modération"
#: proposals/templates/proposals/talk_detail.html:115
msgid "Vote"
msgstr "Vote"
#: proposals/templates/proposals/talk_detail.html:124
msgid "vote"
msgstr "vote"
#: proposals/templates/proposals/talk_detail.html:124
msgid "average:"
msgstr "moyenne :"
#: proposals/templates/proposals/talk_detail.html:138
msgid "No attendees yet."
msgstr "Il ny a pas encore dinscrit."
@ -1151,18 +1217,6 @@ msgstr "Exposé proposé avec succès !"
msgid "Talk assigned to track successfully!"
msgstr "Exposé assigné à la session avec succès !"
#: proposals/views.py:321
msgid "Vote successfully created"
msgstr "A voté !"
#: proposals/views.py:321
msgid "Vote successfully updated"
msgstr "Vote mis à jour"
#: proposals/views.py:347
msgid "Decision taken in account"
msgstr "Décision enregistrée"
#: proposals/views.py:445
msgid "Unregistered :-("
msgstr "Vous avez été désinscrit :-("
@ -1209,6 +1263,3 @@ msgstr "Bénévoles"
#: volunteers/templates/volunteers/volunteer_list.html:25
msgid "volunteer"
msgstr "bénévole"
#~ msgid "Conference"
#~ msgstr "Conférence"

View File

@ -49,7 +49,7 @@ INSTALLED_APPS = [
'djangobower',
'bootstrap3',
#'registration',
#'django_select2',
'django_select2',
#'avatar',
'crispy_forms',
@ -208,6 +208,7 @@ BOOTSTRAP3 = {
SELECT2_JS = 'select2/dist/js/select2.min.js'
SELECT2_CSS = 'select2/dist/css/select2.min.css'
SELECT2_I18N_PATH = 'select2/dist/js/i18n'
#AUTHENTICATION_BACKENDS = ['yeouia.backends.YummyEmailOrUsernameInsensitiveAuth']
LOGOUT_REDIRECT_URL = 'home'
@ -221,9 +222,15 @@ INCLUDE_REGISTER_URL = True
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
}
},
'select2': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'select2',
},
}
SELECT2_CACHE_BACKEND = 'select2'
SERVER_EMAIL = 'ponyconf@example.com'
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'localhost'

View File

@ -3,6 +3,7 @@ django<1.12
django-autoslug
django-bootstrap3
django-bower
django-crispy-forms
django-select2
django-colorful