Compare commits

..

No commits in common. "main" and "main" have entirely different histories.
main ... main

29 changed files with 183 additions and 354 deletions

View File

@ -1,5 +1,5 @@
from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth.forms import AuthenticationForm
from django.utils.translation import gettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.forms.models import modelform_factory from django.forms.models import modelform_factory

View File

@ -1,7 +1,7 @@
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.urls import reverse from django.urls import reverse
from django.db import models from django.db import models
from django.utils.translation import gettext_lazy as _ from django.utils.translation import ugettext_lazy as _
class Profile(models.Model): class Profile(models.Model):

View File

@ -4,8 +4,8 @@ from django.contrib.auth.signals import user_logged_in, user_logged_out
#from django.contrib.sites.shortcuts import get_current_site #from django.contrib.sites.shortcuts import get_current_site
from django.db.models.signals import post_save from django.db.models.signals import post_save
from django.dispatch import receiver from django.dispatch import receiver
from django.utils.translation import gettext_lazy as _ from django.utils.translation import ugettext_lazy as _
#from django.utils.translation import gettext_noop #from django.utils.translation import ugettext_noop
from ponyconf.decorators import disable_for_loaddata from ponyconf.decorators import disable_for_loaddata

View File

@ -1,6 +1,6 @@
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.contrib.auth.views import LoginView from django.contrib.auth.views import LoginView
from django.utils.translation import gettext as _ from django.utils.translation import ugettext as _
from django.shortcuts import redirect, render from django.shortcuts import redirect, render
from django.contrib import messages from django.contrib import messages

View File

@ -1,4 +1,4 @@
from django.utils.translation import gettext as _ from django.utils.translation import ugettext as _
from django.utils.html import escape from django.utils.html import escape
from pprint import pformat from pprint import pformat

View File

@ -3,7 +3,7 @@ from django.forms.models import modelform_factory
from django.contrib.auth.admin import UserAdmin from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.auth.forms import UsernameField from django.contrib.auth.forms import UsernameField
from django.utils.translation import gettext_lazy as _, pgettext_lazy from django.utils.translation import ugettext_lazy as _, pgettext_lazy
from django.template.defaultfilters import slugify from django.template.defaultfilters import slugify
from django.utils.crypto import get_random_string from django.utils.crypto import get_random_string
@ -86,7 +86,7 @@ class TalkForm(forms.ModelForm):
class Meta: class Meta:
model = Talk model = Talk
fields = ('category', 'title', 'language', 'description', 'notes', 'materials',) fields = ('category', 'title', 'description', 'notes', 'materials',)
class TalkStaffForm(forms.ModelForm): class TalkStaffForm(forms.ModelForm):

View File

@ -1,19 +0,0 @@
# Generated by Django 4.1.7 on 2024-02-22 12:43
import cfp.models
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cfp', '0027_auto_20200809_1530'),
]
operations = [
migrations.AlterField(
model_name='volunteer',
name='phone_number',
field=models.CharField(blank=True, default='', max_length=64, validators=[cfp.models.validate_phone_number], verbose_name='Phone number'),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 4.1.7 on 2024-02-22 12:45
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cfp', '0028_alter_volunteer_phone_number'),
]
operations = [
migrations.AddField(
model_name='talk',
name='language',
field=models.CharField(blank=True, max_length=10),
),
]

View File

@ -1,6 +1,5 @@
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.sites.models import Site from django.contrib.sites.models import Site
from django.conf import settings
from django.urls import reverse from django.urls import reverse
from django.core.validators import MaxValueValidator, MinValueValidator from django.core.validators import MaxValueValidator, MinValueValidator
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
@ -8,14 +7,13 @@ from django.db import models
from django.db.models import Q, Count, Avg, Case, When from django.db.models import Q, Count, Avg, Case, When
from django.db.models.functions import Coalesce from django.db.models.functions import Coalesce
from django.utils import timezone from django.utils import timezone
from django.utils.translation import gettext, gettext_lazy as _ from django.utils.translation import ugettext, ugettext_lazy as _
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.html import escape, format_html from django.utils.html import escape, format_html
from autoslug import AutoSlugField from autoslug import AutoSlugField
from colorful.fields import RGBColorField from colorful.fields import RGBColorField
from functools import partial from functools import partial
import phonenumbers
import uuid import uuid
from datetime import timedelta from datetime import timedelta
@ -100,10 +98,9 @@ class ParticipantManager(models.Manager):
def get_queryset(self): def get_queryset(self):
qs = super().get_queryset() qs = super().get_queryset()
qs = qs.annotate( qs = qs.annotate(
accepted_talk_count=Count(Case(When(Q(talk__accepted=True) & (Q(talk__confirmed=True) | Q(talk__confirmed__isnull=True)), then='talk__pk'), output_field=models.IntegerField()), distinct=True), accepted_talk_count=Count(Case(When(talk__accepted=True, then='talk__pk'), output_field=models.IntegerField()), distinct=True),
pending_talk_count=Count(Case(When(talk__accepted=None, then='talk__pk'), output_field=models.IntegerField()), distinct=True), pending_talk_count=Count(Case(When(talk__accepted=None, then='talk__pk'), output_field=models.IntegerField()), distinct=True),
refused_talk_count=Count(Case(When(talk__accepted=False, then='talk__pk'), output_field=models.IntegerField()), distinct=True), refused_talk_count=Count(Case(When(talk__accepted=False, then='talk__pk'), output_field=models.IntegerField()), distinct=True),
canceled_talk_count=Count(Case(When(talk__confirmed=False, then='talk__pk'), output_field=models.IntegerField()), distinct=True),
) )
return qs return qs
@ -155,10 +152,7 @@ class Participant(PonyConfModel):
@property @property
def accepted_talk_set(self): def accepted_talk_set(self):
return self.talk_set.filter(accepted=True).exclude(confirmed=False) return self.talk_set.filter(accepted=True)
@property
def canceled_talk_set(self):
return self.talk_set.filter(confirmed=False)
@property @property
def pending_talk_set(self): def pending_talk_set(self):
return self.talk_set.filter(accepted=None) return self.talk_set.filter(accepted=None)
@ -281,7 +275,7 @@ class TalkCategory(models.Model): # type of talk (conf 30min, 1h, stand, …)
verbose_name_plural = "categories" verbose_name_plural = "categories"
def __str__(self): def __str__(self):
return gettext(self.name) return ugettext(self.name)
def get_absolute_url(self): def get_absolute_url(self):
return reverse('category-list') return reverse('category-list')
@ -317,7 +311,7 @@ class TalkCategory(models.Model): # type of talk (conf 30min, 1h, stand, …)
class TalkManager(models.Manager): class TalkManager(models.Manager):
def get_queryset(self): def get_queryset(self):
qs = super().get_queryset() qs = super().get_queryset()
qs = qs.annotate(score=Coalesce(Avg('vote__vote'), 0.0)) qs = qs.annotate(score=Coalesce(Avg('vote__vote'), 0))
return qs return qs
@ -364,7 +358,6 @@ class Talk(PonyConfModel):
video = models.URLField(max_length=1000, blank=True, default='', verbose_name='Video URL') video = models.URLField(max_length=1000, blank=True, default='', verbose_name='Video URL')
token = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) token = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
conversation = models.OneToOneField(MessageThread, on_delete=models.PROTECT) conversation = models.OneToOneField(MessageThread, on_delete=models.PROTECT)
language = models.CharField(max_length=10, blank=True)
objects = TalkManager() objects = TalkManager()
@ -394,7 +387,7 @@ class Talk(PonyConfModel):
elif self.accepted is False: elif self.accepted is False:
return _('Refused') return _('Refused')
else: else:
return _('Pending decision') return _('Pending decision, score: %(score).1f') % {'score': self.score}
def get_status_color(self): def get_status_color(self):
if self.accepted is True: if self.accepted is True:
@ -430,7 +423,6 @@ class Talk(PonyConfModel):
1 if self.plenary else 0, 1 if self.plenary else 0,
self.materials, self.materials,
self.video, self.video,
self.score,
] ]
@property @property
@ -491,22 +483,12 @@ class Activity(models.Model):
return self.name return self.name
def validate_phone_number(phone_number: str):
try:
number = phonenumbers.parse(phone_number, region=settings.DEFAULT_PHONE_REGION)
except phonenumbers.phonenumberutil.NumberParseException as err:
raise ValidationError(str(err))
else:
if not phonenumbers.is_valid_number(number):
raise ValidationError(_("Invalid phone number, try using the country code (like +33 for France)"))
class Volunteer(PonyConfModel): class Volunteer(PonyConfModel):
site = models.ForeignKey(Site, on_delete=models.CASCADE) 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=_('Your Name'))
email = models.EmailField(verbose_name=_('Email')) email = models.EmailField(verbose_name=_('Email'))
token = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) token = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
phone_number = models.CharField(max_length=64, blank=True, default='', verbose_name=_('Phone number'), validators=[validate_phone_number]) phone_number = models.CharField(max_length=64, blank=True, default='', verbose_name=_('Phone number'))
sms_prefered = models.BooleanField(default=False, verbose_name=_('SMS prefered')) sms_prefered = models.BooleanField(default=False, verbose_name=_('SMS prefered'))
language = models.CharField(max_length=10, blank=True) language = models.CharField(max_length=10, blank=True)
notes = models.TextField(default='', blank=True, verbose_name=_('Notes'), notes = models.TextField(default='', blank=True, verbose_name=_('Notes'),

View File

@ -2,7 +2,7 @@ from django.db.models.signals import pre_save, post_save
from django.dispatch import receiver from django.dispatch import receiver
from django.contrib.sites.models import Site from django.contrib.sites.models import Site
from django.conf import settings from django.conf import settings
from django.utils.translation import gettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.urls import reverse from django.urls import reverse
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model

View File

@ -15,7 +15,7 @@
</h1> </h1>
</div> </div>
<h3>{% trans "Your information" %}</h3> <h3>{% trans "Your informations" %}</h3>
<p> <p>
<ul> <ul>

View File

@ -1,8 +1,6 @@
{% extends 'cfp/staff/base.html' %} {% extends 'cfp/staff/base.html' %}
{% load i18n %} {% load i18n %}
{% block title %}{{ participant.name }} - {{ conference.name }}{% endblock %}
{% block speakerstab %} class="active"{% endblock %} {% block speakerstab %} class="active"{% endblock %}
{% block content %} {% block content %}
@ -27,7 +25,7 @@
<p>{{ participant.notes|linebreaksbr }}</p> <p>{{ participant.notes|linebreaksbr }}</p>
{% endif %} {% endif %}
<h2>{% trans "Information" %}</h2> <h2>{% trans "Informations" %}</h2>
<ul> <ul>
{% if participant.vip %}<li><b>{% trans "Invited speaker" %}</b></li>{% endif %} {% if participant.vip %}<li><b>{% trans "Invited speaker" %}</b></li>{% endif %}
<li><b>{% trans "E-mail:" %}</b> <a href="mailto:{{ participant.email }}">{{ participant.email }}</a></li> <li><b>{% trans "E-mail:" %}</b> <a href="mailto:{{ participant.email }}">{{ participant.email }}</a></li>
@ -58,7 +56,6 @@
<i>{% trans "in" %}</i> <i>{% trans "in" %}</i>
{{ talk.track }} {{ talk.track }}
{% endif %} {% endif %}
<span class="label label-{{ talk.get_status_color }}">{{ talk.get_status_str }}</span>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>

View File

@ -81,8 +81,6 @@
<span class="text-warning">{% blocktrans count pending=participant.pending_talk_count %}pending: {{ pending }}{% plural %}pending: {{ pending }}{% endblocktrans %}</span> <span class="text-warning">{% blocktrans count pending=participant.pending_talk_count %}pending: {{ pending }}{% plural %}pending: {{ pending }}{% endblocktrans %}</span>
<span class="text-danger">{% blocktrans count refused=participant.refused_talk_count %}refused: {{ refused }}{% plural %}refused: {{ refused }}{% endblocktrans %}</span> <span class="text-danger">{% blocktrans count refused=participant.refused_talk_count %}refused: {{ refused }}{% plural %}refused: {{ refused }}{% endblocktrans %}</span>
<span class="text-danger">{% blocktrans count canceled=participant.canceled_talk_count %}canceled: {{ canceled }}{% plural %}canceled: {{ canceled }}{% endblocktrans %}</span>
</td> </td>
</tr> </tr>
{% if forloop.last %} {% if forloop.last %}

View File

@ -95,20 +95,7 @@
<a class="btn {% if vote == 2 %} active {% endif %}btn-success" href="{% url 'talk-vote' talk.pk 2 %}">+2</a> <a class="btn {% if vote == 2 %} active {% endif %}btn-success" href="{% url 'talk-vote' talk.pk 2 %}">+2</a>
</div> </div>
</p> </p>
<p>{{ talk.vote_set.count }} {% trans "vote" %}{{ talk.vote_set.count|pluralize }}, {% trans "average:" %} {{ talk.score|floatformat:1 }}</p>
<p><button class="btn btn-info" onclick="toggle_votes()">{% trans "Toggle actual votes" %}</button> <span id="actual_votes" class="invisible">{{ talk.vote_set.count }} {% trans "vote" %}{{ talk.vote_set.count|pluralize }}, {% trans "average:" %} {{ talk.score|floatformat:1 }}</span></p>
<script>
function toggle_votes(){
let votes = document.getElementById('actual_votes');
if (votes != null) {
if (votes.className == "invisible") {
votes.className = "visible";
} else {
votes.className = "invisible";
}
}
}
</script>
<a href="{% url 'talk-accept' talk.pk %}" class="btn btn-success">{% trans "Accept" %}</a> <a href="{% url 'talk-accept' talk.pk %}" class="btn btn-success">{% trans "Accept" %}</a>
<a href="{% url 'talk-decline' talk.pk %}" class="btn btn-danger">{% trans "Decline" %}</a> <a href="{% url 'talk-decline' talk.pk %}" class="btn btn-danger">{% trans "Decline" %}</a>

View File

@ -55,11 +55,9 @@
<th class="text-center">{% trans "Title" %} <a href="?{{ sort_urls.title }}"><span class="glyphicon glyphicon-{{ sort_glyphicons.title }} pull-right"></span></a></th> <th class="text-center">{% trans "Title" %} <a href="?{{ sort_urls.title }}"><span class="glyphicon glyphicon-{{ sort_glyphicons.title }} pull-right"></span></a></th>
<th class="text-center">{% trans "Intervention kind" %} <a href="?{{ sort_urls.category }}"><span class="glyphicon glyphicon-{{ sort_glyphicons.category }} pull-right"></span></a></th> <th class="text-center">{% trans "Intervention kind" %} <a href="?{{ sort_urls.category }}"><span class="glyphicon glyphicon-{{ sort_glyphicons.category }} pull-right"></span></a></th>
<th class="text-center">{% trans "Speakers" %}</th> <th class="text-center">{% trans "Speakers" %}</th>
<th class="text-center">{% trans "Language" %}</th>
<th class="text-center">{% trans "Track" %}</th> <th class="text-center">{% trans "Track" %}</th>
<th class="text-center">{% trans "Tags" %}</th> <th class="text-center">{% trans "Tags" %}</th>
<th class="text-center">{% trans "Status" %} <a href="?{{ sort_urls.status }}"><span class="glyphicon glyphicon-{{ sort_glyphicons.status }} pull-right"></span></a></th> <th class="text-center">{% trans "Status" %} <a href="?{{ sort_urls.status }}"><span class="glyphicon glyphicon-{{ sort_glyphicons.status }} pull-right"></span></a></th>
<th class="text-center">{% trans "Score" %} <a href="?{{ sort_urls.score }}"><span class="glyphicon glyphicon-{{ sort_glyphicons.score }} pull-right"></span></a></th>
</tr> </tr>
</thead> </thead>
<tfoot> <tfoot>
@ -84,11 +82,11 @@
{% empty %} {% empty %}
{% endfor %} {% endfor %}
</td> </td>
<td>{{ talk.language }}</td>
<td>{{ talk.track|default:"" }}</td> <td>{{ talk.track|default:"" }}</td>
<td>{{ talk.get_tags_html }}</td> <td>{{ talk.get_tags_html }}</td>
<td>{{ talk.get_status_str }}</td> <td>
<td>{{ talk.score }}</td> {{ talk.get_status_str }}
</td>
</tr> </tr>
{% if forloop.last%} {% if forloop.last%}
</tbody> </tbody>

View File

@ -28,7 +28,7 @@
{% for activity in volunteer.activities.all %} {% for activity in volunteer.activities.all %}
{% if forloop.first %} {% if forloop.first %}
{% trans "This volunteer applied for the following activities:" %} {% trans "The volunteer applied for following activities:" %}
<ul> <ul>
{% endif %} {% endif %}
<li> <li>
@ -38,7 +38,7 @@
</ul> </ul>
{% endif %} {% endif %}
{% empty %} {% empty %}
{% trans "This volunteer hasn't applied for any activities." %} {% trans "The volunteer does not applied for any activities." %}
{% endfor %} {% endfor %}

View File

@ -17,7 +17,7 @@
</div> </div>
<h2>{% trans "Your information" %}</h2> <h2>{% trans "Your informations" %}</h2>
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">

View File

@ -9,7 +9,7 @@
<div class="page-header"> <div class="page-header">
<h1> <h1>
{% trans "Become a volunteer!" %} {% trans "Become a volunteers!" %}
</h1> </h1>
{% blocktrans %}We need you! To participate, please enter your name and e-mail and select the activities you are interested in.{% endblocktrans %} {% blocktrans %}We need you! To participate, please enter your name and e-mail and select the activities you are interested in.{% endblocktrans %}
</div> </div>

View File

@ -2,7 +2,7 @@ from django.core.mail import send_mail
from django.shortcuts import get_object_or_404, redirect, render from django.shortcuts import get_object_or_404, redirect, render
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.urls import reverse, reverse_lazy from django.urls import reverse, reverse_lazy
from django.utils.translation import gettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.views.generic import DeleteView, FormView, TemplateView from django.views.generic import DeleteView, FormView, TemplateView
from django.contrib import messages from django.contrib import messages
from django.db.models import Q, Count, Sum from django.db.models import Q, Count, Sum
@ -120,7 +120,7 @@ def volunteer_mail_token(request):
subject=_("[%(conference)s] Someone asked to access your profil") % {'conference': request.conference}, subject=_("[%(conference)s] Someone asked to access your profil") % {'conference': request.conference},
content=body, content=body,
) )
messages.success(request, _('An email has been sent with a link to access to your profil.')) messages.success(request, _('A email have been sent with a link to access to your profil.'))
return redirect(reverse('volunteer-mail-token')) return redirect(reverse('volunteer-mail-token'))
return render(request, 'cfp/volunteer_mail_token.html', { return render(request, 'cfp/volunteer_mail_token.html', {
'form': form, 'form': form,
@ -331,7 +331,7 @@ Thanks!
}, },
content=body, content=body,
) )
messages.success(request, _('Your proposition has been successfully submitted!')) messages.success(request, _('Your proposition have been successfully submitted!'))
return redirect(reverse('proposal-talk-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)))
return render(request, 'cfp/proposal_home.html', { return render(request, 'cfp/proposal_home.html', {
'speaker_form': speaker_form, 'speaker_form': speaker_form,
@ -372,7 +372,7 @@ Sincerely,
}, },
content=body, content=body,
) )
messages.success(request, _('An email has been sent with a link to access to your profil.')) messages.success(request, _('A email have been sent with a link to access to your profil.'))
return redirect(reverse('proposal-mail-token')) return redirect(reverse('proposal-mail-token'))
return render(request, 'cfp/proposal_mail_token.html', { return render(request, 'cfp/proposal_mail_token.html', {
'form': form, 'form': form,
@ -414,7 +414,7 @@ def proposal_talk_edit(request, speaker, talk_id=None):
else: else:
# TODO: it could be great to receive the proposition by mail # 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 # but this is not crucial as the speaker already have a link in its mailbox
messages.success(request, _('Your proposition has been successfully submitted!')) messages.success(request, _('Your proposition have been successfully submitted!'))
return redirect(reverse('proposal-talk-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)))
return render(request, 'cfp/proposal_talk_form.html', { return render(request, 'cfp/proposal_talk_form.html', {
'speaker': speaker, 'speaker': speaker,
@ -584,17 +584,17 @@ def talk_acknowledgment(request, talk_id, confirm):
talk.confirmed = confirm talk.confirmed = confirm
talk.save() talk.save()
if confirm: if confirm:
confirmation_message= _('The speaker confirmation has been noted.') confirmation_message= _('The speaker confirmation have been noted.')
action = _('confirmed') action = _('confirmed')
thread_note = _('The talk has been confirmed.') thread_note = _('The talk have been confirmed.')
else: else:
confirmation_message = _('The speaker unavailability has been noted.') confirmation_message = _('The speaker unavailability have been noted.')
action = _('cancelled') action = _('cancelled')
thread_note = _('The talk has been %(action)s.') % {'action': action} thread_note = _('The talk have been %(action)s.') % {'action': action}
send_message( send_message(
thread=talk.conversation, thread=talk.conversation,
author=request.user, author=request.user,
subject=_("[%(conference)s] The talk '%(talk)s' has been %(action)s.") % { subject=_("[%(conference)s] The talk '%(talk)s' have been %(action)s.") % {
'conference': request.conference, 'conference': request.conference,
'talk': talk, 'talk': talk,
'action': action, 'action': action,
@ -695,7 +695,7 @@ def talk_list(request):
send_message( send_message(
thread=talk.conversation, thread=talk.conversation,
author=request.user, author=request.user,
subject=_("[%(conference)s] The talk '%(talk)s' has been %(action)s") % { subject=_("[%(conference)s] The talk '%(talk)s' have been %(action)s") % {
'conference': request.conference, 'conference': request.conference,
'talk': talk, 'talk': talk,
'action': action, 'action': action,
@ -730,7 +730,6 @@ def talk_list(request):
'title': 'title', 'title': 'title',
'category': 'category', 'category': 'category',
'status': 'accepted', 'status': 'accepted',
'score': 'score',
} }
sort = request.GET.get('sort') sort = request.GET.get('sort')
if sort in SORT_MAPPING.keys(): if sort in SORT_MAPPING.keys():
@ -831,7 +830,7 @@ def talk_decide(request, talk_id, accept):
send_message( send_message(
thread=participant.conversation, thread=participant.conversation,
author=request.conference, author=request.conference,
subject=_("[%(conference)s] Your talk '%(talk)s' has been %(action)s") % { subject=_("[%(conference)s] Your talk '%(talk)s' have been %(action)s") % {
'conference': request.conference, 'conference': request.conference,
'talk': talk, 'talk': talk,
'action': action, 'action': action,
@ -842,7 +841,7 @@ def talk_decide(request, talk_id, accept):
send_message( send_message(
thread=talk.conversation, thread=talk.conversation,
author=request.user, author=request.user,
subject=_("[%(conference)s] The talk '%(talk)s' has been %(action)s") % { subject=_("[%(conference)s] The talk '%(talk)s' have been %(action)s") % {
'conference': request.conference, 'conference': request.conference,
'talk': talk, 'talk': talk,
'action': action, 'action': action,

View File

@ -12,7 +12,7 @@ Commands starting with ``$`` must be run as ``ponyconf`` user.
Requirements Requirements
------------ ------------
PonyConf has been tested with python 3.5 and 3.6. PonyConf have been tested with python 3.5 and 3.6.
Preparation Preparation

Binary file not shown.

View File

@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-01-30 13:44+0000\n" "POT-Creation-Date: 2019-11-02 12:00+0000\n"
"PO-Revision-Date: 2019-11-02 13:06+0100\n" "PO-Revision-Date: 2019-11-02 13:06+0100\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: \n" "Language-Team: \n"
@ -22,11 +22,11 @@ msgstr ""
msgid "Email address" msgid "Email address"
msgstr "Adresse e-mail" msgstr "Adresse e-mail"
#: accounts/models.py:10 cfp/models.py:120 cfp/models.py:491 #: accounts/models.py:10 cfp/models.py:120 cfp/models.py:493
msgid "Phone number" msgid "Phone number"
msgstr "Numéro de téléphone" msgstr "Numéro de téléphone"
#: accounts/models.py:11 cfp/models.py:492 #: accounts/models.py:11 cfp/models.py:494
msgid "SMS prefered" msgid "SMS prefered"
msgstr "SMS préférés" msgstr "SMS préférés"
@ -136,15 +136,15 @@ msgstr "Décliné"
msgid "Waiting" msgid "Waiting"
msgstr "En attente" msgstr "En attente"
#: cfp/forms.py:30 cfp/forms.py:132 cfp/forms.py:258 cfp/models.py:382 #: cfp/forms.py:30 cfp/forms.py:132 cfp/forms.py:258 cfp/models.py:384
msgid "Confirmed" msgid "Confirmed"
msgstr "Confirmé" msgstr "Confirmé"
#: cfp/forms.py:31 cfp/models.py:384 #: cfp/forms.py:31 cfp/models.py:386
msgid "Cancelled" msgid "Cancelled"
msgstr "Annulé" msgstr "Annulé"
#: cfp/forms.py:63 cfp/models.py:473 #: cfp/forms.py:63 cfp/models.py:475
msgid "Activity" msgid "Activity"
msgstr "Activité" msgstr "Activité"
@ -167,13 +167,13 @@ msgstr "Catégorie"
msgid "Title" msgid "Title"
msgstr "Titre" msgstr "Titre"
#: cfp/forms.py:110 cfp/models.py:168 cfp/models.py:469 #: cfp/forms.py:110 cfp/models.py:168 cfp/models.py:471
#: cfp/templates/cfp/proposal_talk_details.html:75 #: cfp/templates/cfp/proposal_talk_details.html:75
#: cfp/templates/cfp/staff/talk_details.html:64 #: cfp/templates/cfp/staff/talk_details.html:64
msgid "Description" msgid "Description"
msgstr "Description" msgstr "Description"
#: cfp/forms.py:111 cfp/models.py:122 cfp/models.py:494 #: cfp/forms.py:111 cfp/models.py:122 cfp/models.py:496
#: cfp/templates/cfp/staff/participant_details.html:24 #: cfp/templates/cfp/staff/participant_details.html:24
#: cfp/templates/cfp/staff/talk_details.html:83 #: cfp/templates/cfp/staff/talk_details.html:83
#: cfp/templates/cfp/staff/volunteer_details.html:22 #: cfp/templates/cfp/staff/volunteer_details.html:22
@ -184,7 +184,7 @@ msgstr "Notes"
msgid "Visible by speakers" msgid "Visible by speakers"
msgstr "Visible par les orateurs" msgstr "Visible par les orateurs"
#: cfp/forms.py:138 cfp/forms.py:264 cfp/models.py:338 #: cfp/forms.py:138 cfp/forms.py:264 cfp/models.py:340
#: cfp/templates/cfp/staff/talk_details.html:21 #: cfp/templates/cfp/staff/talk_details.html:21
#: cfp/templates/cfp/staff/talk_list.html:58 #: cfp/templates/cfp/staff/talk_list.html:58
#: cfp/templates/cfp/staff/track_form.html:14 #: cfp/templates/cfp/staff/track_form.html:14
@ -222,7 +222,7 @@ msgstr "Programmé"
msgid "Filter talks already / not yet scheduled" msgid "Filter talks already / not yet scheduled"
msgstr "Filtrer les exposés déjà / pas encore planifiées" msgstr "Filtrer les exposés déjà / pas encore planifiées"
#: cfp/forms.py:162 cfp/models.py:356 #: cfp/forms.py:162 cfp/models.py:358
#: cfp/templates/cfp/proposal_talk_details.html:89 #: cfp/templates/cfp/proposal_talk_details.html:89
#: cfp/templates/cfp/staff/talk_details.html:54 #: cfp/templates/cfp/staff/talk_details.html:54
msgid "Materials" msgid "Materials"
@ -277,7 +277,7 @@ msgstr "Envoyer un e-mail"
msgid "Notify by mail?" msgid "Notify by mail?"
msgstr "Notifier par e-mail ?" msgstr "Notifier par e-mail ?"
#: cfp/forms.py:280 cfp/models.py:489 #: cfp/forms.py:280 cfp/models.py:491
#: cfp/templates/cfp/staff/volunteer_list.html:43 #: cfp/templates/cfp/staff/volunteer_list.html:43
msgid "Email" msgid "Email"
msgstr "E-mail" msgstr "E-mail"
@ -403,8 +403,8 @@ msgstr ""
"Ladresse de réponse doit être une chaine de texte formatable avec un " "Ladresse de réponse doit être une chaine de texte formatable avec un "
"argument « token » (e.g. ponyconf+{token}@exemple.com)." "argument « token » (e.g. ponyconf+{token}@exemple.com)."
#: cfp/models.py:110 cfp/models.py:166 cfp/models.py:186 cfp/models.py:216 #: cfp/models.py:110 cfp/models.py:166 cfp/models.py:188 cfp/models.py:218
#: cfp/models.py:467 cfp/templates/cfp/staff/participant_list.html:54 #: cfp/models.py:469 cfp/templates/cfp/staff/participant_list.html:54
#: cfp/templates/cfp/staff/volunteer_list.html:42 #: cfp/templates/cfp/staff/volunteer_list.html:42
msgid "Name" msgid "Name"
msgstr "Nom" msgstr "Nom"
@ -417,39 +417,39 @@ msgstr "Ce champ est uniquement visible par les organisateurs."
msgid "Invited speaker" msgid "Invited speaker"
msgstr "Orateur invité" msgstr "Orateur invité"
#: cfp/models.py:188 #: cfp/models.py:190
msgid "Label" msgid "Label"
msgstr "Étiquette" msgstr "Étiquette"
#: cfp/models.py:189 #: cfp/models.py:191
msgid "Capacity" msgid "Capacity"
msgstr "Capacité" msgstr "Capacité"
#: cfp/models.py:218 #: cfp/models.py:220
msgid "Color" msgid "Color"
msgstr "Couleur" msgstr "Couleur"
#: cfp/models.py:220 #: cfp/models.py:222
msgid "Show the tag on the public program" msgid "Show the tag on the public program"
msgstr "Afficher létiquette sur le programme public" msgstr "Afficher létiquette sur le programme public"
#: cfp/models.py:221 #: cfp/models.py:223
msgid "Show the tag on the staff program" msgid "Show the tag on the staff program"
msgstr "Afficher létiquette sur le programme organisateur" msgstr "Afficher létiquette sur le programme organisateur"
#: cfp/models.py:257 #: cfp/models.py:259
msgid "Default duration (min)" msgid "Default duration (min)"
msgstr "Durée par défaut (min)" msgstr "Durée par défaut (min)"
#: cfp/models.py:258 #: cfp/models.py:260
msgid "Color on program" msgid "Color on program"
msgstr "Couleur sur le programme" msgstr "Couleur sur le programme"
#: cfp/models.py:259 #: cfp/models.py:261
msgid "Label on program" msgid "Label on program"
msgstr "Label dans le xml du programme" msgstr "Label dans le xml du programme"
#: cfp/models.py:333 cfp/templates/cfp/proposal_talk_details.html:53 #: cfp/models.py:335 cfp/templates/cfp/proposal_talk_details.html:53
#: cfp/templates/cfp/staff/base.html:10 #: cfp/templates/cfp/staff/base.html:10
#: cfp/templates/cfp/staff/participant_list.html:16 #: cfp/templates/cfp/staff/participant_list.html:16
#: cfp/templates/cfp/staff/talk_details.html:68 #: cfp/templates/cfp/staff/talk_details.html:68
@ -457,23 +457,23 @@ msgstr "Label dans le xml du programme"
msgid "Speakers" msgid "Speakers"
msgstr "Orateurs" msgstr "Orateurs"
#: cfp/models.py:334 #: cfp/models.py:336
msgid "Talk Title" msgid "Talk Title"
msgstr "Titre de la proposition" msgstr "Titre de la proposition"
#: cfp/models.py:336 #: cfp/models.py:338
msgid "Description of your talk" msgid "Description of your talk"
msgstr "Description de votre proposition" msgstr "Description de votre proposition"
#: cfp/models.py:337 #: cfp/models.py:339
msgid "This description will be visible on the program." msgid "This description will be visible on the program."
msgstr "Cette description sera visible sur le programme." msgstr "Cette description sera visible sur le programme."
#: cfp/models.py:340 cfp/templates/cfp/proposal_talk_details.html:99 #: cfp/models.py:342 cfp/templates/cfp/proposal_talk_details.html:99
msgid "Message to organizers" msgid "Message to organizers"
msgstr "Message aux organisateurs" msgstr "Message aux organisateurs"
#: cfp/models.py:341 #: cfp/models.py:343
msgid "" msgid ""
"If you have any constraint or if you have anything that may help you to " "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 " "select your talk, like a video or slides of your talk, please write it down "
@ -483,51 +483,51 @@ msgstr ""
"votre proposition, comme une vidéo, des slides, n'hésitez pas à les ajouter " "votre proposition, comme une vidéo, des slides, n'hésitez pas à les ajouter "
"ici. Ce champ ne sera visible que par les organisateurs." "ici. Ce champ ne sera visible que par les organisateurs."
#: cfp/models.py:345 #: cfp/models.py:347
msgid "Talk Category" msgid "Talk Category"
msgstr "Catégorie de proposition" msgstr "Catégorie de proposition"
#: cfp/models.py:346 #: cfp/models.py:348
msgid "I'm ok to be recorded on video" msgid "I'm ok to be recorded on video"
msgstr "Jaccepte dêtre enregistré en vidéo" msgstr "Jaccepte dêtre enregistré en vidéo"
#: cfp/models.py:348 #: cfp/models.py:350
msgid "Video licence" msgid "Video licence"
msgstr "Licence vidéo" msgstr "Licence vidéo"
#: cfp/models.py:349 #: cfp/models.py:351
msgid "I need sound" msgid "I need sound"
msgstr "Jai besoin de son" msgstr "Jai besoin de son"
#: cfp/models.py:352 #: cfp/models.py:354
msgid "Beginning date and time" msgid "Beginning date and time"
msgstr "Date et heure de début" msgstr "Date et heure de début"
#: cfp/models.py:353 #: cfp/models.py:355
msgid "Duration (min)" msgid "Duration (min)"
msgstr "Durée (min)" msgstr "Durée (min)"
#: cfp/models.py:357 #: cfp/models.py:359
msgid "" msgid ""
"You can use this field to share some materials related to your intervention." "You can use this field to share some materials related to your intervention."
msgstr "" msgstr ""
"Vous pouvez utiliser ce champ pour partager les supports de votre " "Vous pouvez utiliser ce champ pour partager les supports de votre "
"intervention." "intervention."
#: cfp/models.py:386 #: cfp/models.py:388
msgid "Waiting confirmation" msgid "Waiting confirmation"
msgstr "En attente de confirmation" msgstr "En attente de confirmation"
#: cfp/models.py:388 #: cfp/models.py:390
msgid "Refused" msgid "Refused"
msgstr "Refusé" msgstr "Refusé"
#: cfp/models.py:390 #: cfp/models.py:392
#, python-format #, python-format
msgid "Pending decision, score: %(score).1f" msgid "Pending decision, score: %(score).1f"
msgstr "En cours, score : %(score).1f" msgstr "En cours, score : %(score).1f"
#: cfp/models.py:474 cfp/models.py:496 #: cfp/models.py:476 cfp/models.py:498
#: cfp/templates/cfp/admin/activity_list.html:9 #: cfp/templates/cfp/admin/activity_list.html:9
#: cfp/templates/cfp/admin/base.html:14 #: cfp/templates/cfp/admin/base.html:14
#: cfp/templates/cfp/staff/volunteer_details.html:27 #: cfp/templates/cfp/staff/volunteer_details.html:27
@ -536,11 +536,11 @@ msgstr "En cours, score : %(score).1f"
msgid "Activities" msgid "Activities"
msgstr "Activités" msgstr "Activités"
#: cfp/models.py:488 #: cfp/models.py:490
msgid "Your Name" msgid "Your Name"
msgstr "Votre Nom" msgstr "Votre Nom"
#: cfp/models.py:495 #: cfp/models.py:497
msgid "If you have some constraints, you can indicate them here." msgid "If you have some constraints, you can indicate them here."
msgstr "Si vous avez des contraintes, vous pouvez les indiquer ici." msgstr "Si vous avez des contraintes, vous pouvez les indiquer ici."
@ -734,7 +734,7 @@ msgstr "Éditer votre profil"
#: cfp/templates/cfp/proposal_dashboard.html:18 #: cfp/templates/cfp/proposal_dashboard.html:18
#: cfp/templates/cfp/volunteer_dashboard.html:20 #: cfp/templates/cfp/volunteer_dashboard.html:20
msgid "Your information" msgid "Your informations"
msgstr "Vos informations" msgstr "Vos informations"
#: cfp/templates/cfp/proposal_dashboard.html:22 #: cfp/templates/cfp/proposal_dashboard.html:22
@ -976,8 +976,7 @@ msgid "Remove"
msgstr "Supprimer" msgstr "Supprimer"
#: cfp/templates/cfp/staff/participant_details.html:28 #: cfp/templates/cfp/staff/participant_details.html:28
#: cfp/templates/cfp/staff/talk_details.html:12 msgid "Informations"
msgid "Information"
msgstr "Informations" msgstr "Informations"
#: cfp/templates/cfp/staff/participant_details.html:39 #: cfp/templates/cfp/staff/participant_details.html:39
@ -1223,6 +1222,10 @@ msgstr "Accepter la proposition"
msgid "Decline the proposal" msgid "Decline the proposal"
msgstr "Décliner la proposition" msgstr "Décliner la proposition"
#: cfp/templates/cfp/staff/talk_details.html:12
msgid "Information"
msgstr "Informations"
#: cfp/templates/cfp/staff/talk_details.html:25 #: cfp/templates/cfp/staff/talk_details.html:25
msgctxt "session" msgctxt "session"
msgid "not defined" msgid "not defined"
@ -1338,11 +1341,11 @@ msgid "Email:"
msgstr "E-mail :" msgstr "E-mail :"
#: cfp/templates/cfp/staff/volunteer_details.html:31 #: cfp/templates/cfp/staff/volunteer_details.html:31
msgid "This volunteer applied for the following activities:" msgid "The volunteer applied for following activities:"
msgstr "Le bénévole s'est proposé pour les activités suivantes :" msgstr "Le bénévole s'est proposé pour les activités suivantes :"
#: cfp/templates/cfp/staff/volunteer_details.html:41 #: cfp/templates/cfp/staff/volunteer_details.html:41
msgid "This volunteer hasn't applied for any activities." msgid "The volunteer does not applied for any activities."
msgstr "Le bénévole ne sest proposé pour aucune activité." msgstr "Le bénévole ne sest proposé pour aucune activité."
#: cfp/templates/cfp/staff/volunteer_details.html:49 #: cfp/templates/cfp/staff/volunteer_details.html:49
@ -1389,7 +1392,7 @@ msgid "Sorry, I have a setback"
msgstr "Désolé, jai un contretemps" msgstr "Désolé, jai un contretemps"
#: cfp/templates/cfp/volunteer_enrole.html:12 #: cfp/templates/cfp/volunteer_enrole.html:12
msgid "Become a volunteer!" msgid "Become a volunteers!"
msgstr "Devenez un bénévole !" msgstr "Devenez un bénévole !"
#: cfp/templates/cfp/volunteer_enrole.html:14 #: cfp/templates/cfp/volunteer_enrole.html:14
@ -1460,7 +1463,7 @@ msgid "[%(conference)s] Someone asked to access your profil"
msgstr "[%(conference)s] Quelquun a demandé à accéder à votre profil" msgstr "[%(conference)s] Quelquun a demandé à accéder à votre profil"
#: cfp/views.py:123 cfp/views.py:375 #: cfp/views.py:123 cfp/views.py:375
msgid "An email has been sent with a link to access to your profil." 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." msgstr "Un e-mail vous a été envoyé avec un lien pour accéder à votre profil."
#: cfp/views.py:143 cfp/views.py:413 cfp/views.py:500 #: cfp/views.py:143 cfp/views.py:413 cfp/views.py:500
@ -1539,7 +1542,7 @@ msgid "[%(conference)s] Thank you for your proposition '%(talk)s'"
msgstr "[%(conference)s] Merci pour votre proposition « %(talk)s »" msgstr "[%(conference)s] Merci pour votre proposition « %(talk)s »"
#: cfp/views.py:334 cfp/views.py:417 #: cfp/views.py:334 cfp/views.py:417
msgid "Your proposition has been successfully submitted!" 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/views.py:353 #: cfp/views.py:353
@ -1658,32 +1661,39 @@ msgid "Co-speaker successfully removed from the talk."
msgstr "Co-intervenant supprimé de lexposé avec succès." msgstr "Co-intervenant supprimé de lexposé avec succès."
#: cfp/views.py:587 #: cfp/views.py:587
msgid "The speaker confirmation has been noted." msgid "The speaker confirmation have been noted."
msgstr "La confirmation de lorateur a été notée." msgstr "La confirmation de lorateur a été notée."
#: cfp/views.py:589 #: cfp/views.py:589
msgid "The talk has been confirmed." msgid "The talk have been confirmed."
msgstr "Lexposé a été confirmé." msgstr "Lexposé a été confirmé."
#: cfp/views.py:591 #: cfp/views.py:591
msgid "The speaker unavailability has been noted." msgid "The speaker unavailability have been noted."
msgstr "Lindisponibilité de lintervenant a été notée." msgstr "Lindisponibilité de lintervenant a été notée."
#: cfp/views.py:593 cfp/views.py:694 cfp/views.py:849 #: cfp/views.py:593
#, python-format #, python-format
msgid "The talk has been %(action)s." msgid "The talk have been %(action)s."
msgstr "Lexposé a été %(action)s." msgstr "Lexposé a été %(action)s."
#: cfp/views.py:597 #: cfp/views.py:597
msgid "[%(conference)s] The talk '%(talk)s' has been %(action)s." #, python-format
msgid "[%(conference)s] The talk '%(talk)s' have been %(action)s."
msgstr "[%(conference)s] Lexposé « %(talk)s » a été %(action)s." msgstr "[%(conference)s] Lexposé « %(talk)s » a été %(action)s."
#: cfp/views.py:693 cfp/views.py:825 #: cfp/views.py:693 cfp/views.py:825
msgid "declined" msgid "declined"
msgstr "décliné" msgstr "décliné"
#: cfp/views.py:694 cfp/views.py:849
#, python-format
msgid "The talk has been %(action)s."
msgstr "Lexposé a été %(action)s."
#: cfp/views.py:698 cfp/views.py:844 #: cfp/views.py:698 cfp/views.py:844
msgid "[%(conference)s] The talk '%(talk)s' has been %(action)s" #, python-format
msgid "[%(conference)s] The talk '%(talk)s' have been %(action)s"
msgstr "[%(conference)s] Lexposé « %(talk)s » a été %(action)s" msgstr "[%(conference)s] Lexposé « %(talk)s » a été %(action)s"
#: cfp/views.py:782 #: cfp/views.py:782
@ -1700,7 +1710,8 @@ msgid "Vote successfully updated"
msgstr "Vote mis à jour" msgstr "Vote mis à jour"
#: cfp/views.py:833 #: cfp/views.py:833
msgid "[%(conference)s] Your talk '%(talk)s' has been %(action)s" #, python-format
msgid "[%(conference)s] Your talk '%(talk)s' have been %(action)s"
msgstr "[%(conference)s] Votre exposé « %(talk)s » a été %(action)s" msgstr "[%(conference)s] Votre exposé « %(talk)s » a été %(action)s"
#: cfp/views.py:851 #: cfp/views.py:851
@ -1773,11 +1784,11 @@ msgstr "Envoyer"
msgid "No messages." msgid "No messages."
msgstr "Aucun message." msgstr "Aucun message."
#: ponyconf/settings.py:126 #: ponyconf/settings.py:141
msgid "English" msgid "English"
msgstr "Anglais" msgstr "Anglais"
#: ponyconf/settings.py:127 #: ponyconf/settings.py:142
msgid "French" msgid "French"
msgstr "Français" msgstr "Français"
@ -1829,12 +1840,6 @@ msgstr "Mot de passe oublié ?"
msgid "Password Change" msgid "Password Change"
msgstr "Changement de mot de passe" msgstr "Changement de mot de passe"
#~ msgid "Informations"
#~ msgstr "Informations"
#~ msgid "The talk have been %(action)s."
#~ msgstr "Lexposé a été %(action)s."
#~ msgid "Messages" #~ msgid "Messages"
#~ msgstr "Messages" #~ msgstr "Messages"

View File

@ -4,7 +4,7 @@ from django.core.mail import EmailMessage, get_connection
from django.conf import settings from django.conf import settings
from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.utils.translation import gettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
import hashlib import hashlib
@ -35,7 +35,7 @@ class MessageAuthor(models.Model):
def __str__(self): def __str__(self):
author_class = self.author_type.model_class() author_class = self.author_type.model_class()
if self.author is not None and author_class == get_user_model(): if author_class == get_user_model():
return self.author.get_full_name() return self.author.get_full_name()
else: else:
return str(self.author) return str(self.author)

View File

@ -2,8 +2,6 @@ from ponyconf.settings import *
SECRET_KEY = 'CHANGE ME' SECRET_KEY = 'CHANGE ME'
DEFAULT_PHONE_REGION = "FR"
DEBUG = False DEBUG = False
LOGGING = { LOGGING = {

View File

@ -2,7 +2,7 @@
Django settings for ponyconf project. Django settings for ponyconf project.
""" """
from django.utils.translation import gettext_lazy as _ from django.utils.translation import ugettext_lazy as _
import os import os
@ -34,7 +34,6 @@ INSTALLED_APPS = [
'bootstrap3', 'bootstrap3',
'django_select2', 'django_select2',
'crispy_forms', 'crispy_forms',
'crispy_bootstrap3',
# build-in apps # build-in apps
'django.contrib.admin', 'django.contrib.admin',
@ -92,8 +91,6 @@ DATABASES = {
} }
} }
DEFAULT_AUTO_FIELD='django.db.models.AutoField'
# Password validation # Password validation
# https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators # https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators
@ -131,7 +128,7 @@ LANGUAGES = [
] ]
LANGUAGE_CODE = 'en-us' LANGUAGE_CODE = 'en-us'
DEFAULT_PHONE_REGION = "US"
LOCALE_PATHS = [ LOCALE_PATHS = [
os.path.join(BASE_DIR, 'locale'), os.path.join(BASE_DIR, 'locale'),
] ]
@ -174,3 +171,4 @@ SERVER_EMAIL = 'ponyconf@example.com'
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'localhost' EMAIL_HOST = 'localhost'
EMAIL_PORT = 25 EMAIL_PORT = 25

View File

@ -16,6 +16,6 @@ class PonyConfModel(models.Model):
def markdown_to_html(md): def markdown_to_html(md):
html = markdown(md) html = markdown(md)
allowed_tags = bleach.ALLOWED_TAGS | {'p', 'pre', 'span' } | {'h%d' % i for i in range(1, 7)} allowed_tags = bleach.ALLOWED_TAGS + ['p', 'pre', 'span' ] + ['h%d' % i for i in range(1, 7) ]
html = bleach.clean(html, tags=allowed_tags) html = bleach.clean(html, tags=allowed_tags)
return mark_safe(html) return mark_safe(html)

View File

@ -1,107 +1,47 @@
# #
# This file is autogenerated by pip-compile with Python 3.9 # This file is autogenerated by pip-compile
# by the following command: # To update, run:
# #
# pip-compile requirements-dev.in # pip-compile requirements-dev.in
# #
asgiref==3.6.0 asgiref==3.2.10 # via django
# via django backcall==0.2.0 # via ipython
asttokens==2.2.1 bleach==3.1.5 # via -r requirements.in
# via stack-data chardet==3.0.4 # via -r requirements.in
backcall==0.2.0 decorator==4.4.2 # via ipython, traitlets
# via ipython django-appconf==1.0.4 # via django-select2
bleach==6.0.0 django-autoslug==1.9.8 # via -r requirements.in
# via -r requirements.in django-bootstrap3==14.1.0 # via -r requirements.in
chardet==5.1.0 django-colorful==1.3 # via -r requirements.in
# via -r requirements.in django-crispy-forms==1.9.2 # via -r requirements.in
crispy-bootstrap3==2022.1 django-debug-toolbar==2.2 # via -r requirements-dev.in
# via -r requirements.in django-extensions==3.0.4 # via -r requirements-dev.in
decorator==5.1.1 django-select2==7.4.2 # via -r requirements.in
# via ipython django==3.1 # via -r requirements.in, django-appconf, django-bootstrap3, django-colorful, django-debug-toolbar, django-select2
django==4.1.7 icalendar==4.0.6 # via -r requirements.in
# via importlib-metadata==1.7.0 # via django-bootstrap3, markdown
# -r requirements.in ipython-genutils==0.2.0 # via traitlets
# crispy-bootstrap3 ipython==7.16.1 # via -r requirements-dev.in
# django-appconf jedi==0.17.2 # via ipython
# django-bootstrap3 jinja2==2.11.2 # via -r requirements.in
# django-colorful markdown==3.2.2 # via -r requirements.in
# django-crispy-forms markupsafe==1.1.1 # via jinja2
# django-debug-toolbar packaging==20.4 # via bleach
# django-extensions parso==0.7.1 # via jedi
# django-select2 pexpect==4.8.0 # via ipython
django-appconf==1.0.5 pickleshare==0.7.5 # via ipython
# via django-select2 prompt-toolkit==3.0.5 # via ipython
django-autoslug==1.9.8 ptyprocess==0.6.0 # via pexpect
# via -r requirements.in pygments==2.6.1 # via ipython
django-bootstrap3==22.2 pyparsing==2.4.7 # via packaging
# via -r requirements.in python-dateutil==2.8.1 # via icalendar
django-colorful==1.3 pytz==2020.1 # via django, icalendar
# via -r requirements.in six==1.15.0 # via bleach, packaging, python-dateutil, traitlets
django-crispy-forms==2.0 sqlparse==0.3.1 # via django, django-debug-toolbar
# via traitlets==4.3.3 # via ipython
# -r requirements.in wcwidth==0.2.5 # via prompt-toolkit
# crispy-bootstrap3 webencodings==0.5.1 # via bleach
django-debug-toolbar==3.8.1 zipp==3.1.0 # via importlib-metadata
# via -r requirements-dev.in
django-extensions==3.2.1 # The following packages are considered to be unsafe in a requirements file:
# via -r requirements-dev.in # setuptools
django-select2==8.1.1
# via -r requirements.in
executing==1.2.0
# via stack-data
icalendar==5.0.4
# via -r requirements.in
importlib-metadata==6.0.0
# via markdown
ipython==8.11.0
# via -r requirements-dev.in
jedi==0.18.2
# via ipython
jinja2==3.1.2
# via -r requirements.in
markdown==3.4.1
# via -r requirements.in
markupsafe==2.1.2
# via jinja2
matplotlib-inline==0.1.6
# via ipython
parso==0.8.3
# via jedi
pexpect==4.8.0
# via ipython
phonenumbers==8.13.7
# via -r requirements.in
pickleshare==0.7.5
# via ipython
prompt-toolkit==3.0.38
# via ipython
ptyprocess==0.7.0
# via pexpect
pure-eval==0.2.2
# via stack-data
pygments==2.14.0
# via ipython
python-dateutil==2.8.2
# via icalendar
pytz==2022.7.1
# via icalendar
six==1.16.0
# via
# bleach
# python-dateutil
sqlparse==0.4.3
# via
# django
# django-debug-toolbar
stack-data==0.6.2
# via ipython
traitlets==5.9.0
# via
# ipython
# matplotlib-inline
wcwidth==0.2.6
# via prompt-toolkit
webencodings==0.5.1
# via bleach
zipp==3.15.0
# via importlib-metadata

View File

@ -2,7 +2,6 @@ django
django-bootstrap3 django-bootstrap3
django-crispy-forms django-crispy-forms
crispy-bootstrap3
django-select2 django-select2
django-colorful django-colorful
django-autoslug django-autoslug
@ -12,4 +11,3 @@ bleach
chardet chardet
icalendar icalendar
jinja2 jinja2
phonenumbers

View File

@ -1,63 +1,29 @@
# #
# This file is autogenerated by pip-compile with Python 3.9 # This file is autogenerated by pip-compile
# by the following command: # To update, run:
# #
# pip-compile # pip-compile
# #
asgiref==3.6.0 asgiref==3.2.10 # via django
# via django bleach==3.1.5 # via -r requirements.in
bleach==6.0.0 chardet==3.0.4 # via -r requirements.in
# via -r requirements.in django-appconf==1.0.4 # via django-select2
chardet==5.1.0 django-autoslug==1.9.8 # via -r requirements.in
# via -r requirements.in django-bootstrap3==14.1.0 # via -r requirements.in
crispy-bootstrap3==2022.1 django-colorful==1.3 # via -r requirements.in
# via -r requirements.in django-crispy-forms==1.9.2 # via -r requirements.in
django==4.1.7 django-select2==7.4.2 # via -r requirements.in
# via django==3.1 # via -r requirements.in, django-appconf, django-bootstrap3, django-colorful, django-select2
# -r requirements.in icalendar==4.0.6 # via -r requirements.in
# crispy-bootstrap3 importlib-metadata==1.7.0 # via django-bootstrap3, markdown
# django-appconf jinja2==2.11.2 # via -r requirements.in
# django-bootstrap3 markdown==3.2.2 # via -r requirements.in
# django-colorful markupsafe==1.1.1 # via jinja2
# django-crispy-forms packaging==20.4 # via bleach
# django-select2 pyparsing==2.4.7 # via packaging
django-appconf==1.0.5 python-dateutil==2.8.1 # via icalendar
# via django-select2 pytz==2020.1 # via django, icalendar
django-autoslug==1.9.8 six==1.15.0 # via bleach, packaging, python-dateutil
# via -r requirements.in sqlparse==0.3.1 # via django
django-bootstrap3==22.2 webencodings==0.5.1 # via bleach
# via -r requirements.in zipp==3.1.0 # via importlib-metadata
django-colorful==1.3
# via -r requirements.in
django-crispy-forms==2.0
# via
# -r requirements.in
# crispy-bootstrap3
django-select2==8.1.1
# via -r requirements.in
icalendar==5.0.4
# via -r requirements.in
importlib-metadata==6.0.0
# via markdown
jinja2==3.1.2
# via -r requirements.in
markdown==3.4.1
# via -r requirements.in
markupsafe==2.1.2
# via jinja2
phonenumbers==8.13.7
# via -r requirements.in
python-dateutil==2.8.2
# via icalendar
pytz==2022.7.1
# via icalendar
six==1.16.0
# via
# bleach
# python-dateutil
sqlparse==0.4.3
# via django
webencodings==0.5.1
# via bleach
zipp==3.15.0
# via importlib-metadata