Compare commits

...

10 Commits
main ... main

22 changed files with 270 additions and 94 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 ugettext_lazy as _ from django.utils.translation import gettext_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 ugettext_lazy as _ from django.utils.translation import gettext_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 ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
#from django.utils.translation import ugettext_noop #from django.utils.translation import gettext_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 ugettext as _ from django.utils.translation import gettext 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 ugettext as _ from django.utils.translation import gettext 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 ugettext_lazy as _, pgettext_lazy from django.utils.translation import gettext_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', 'description', 'notes', 'materials',) fields = ('category', 'title', 'language', 'description', 'notes', 'materials',)
class TalkStaffForm(forms.ModelForm): class TalkStaffForm(forms.ModelForm):

View File

@ -0,0 +1,19 @@
# 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

@ -0,0 +1,18 @@
# 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,5 +1,6 @@
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
@ -7,13 +8,14 @@ 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 ugettext, ugettext_lazy as _ from django.utils.translation import gettext, gettext_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
@ -98,9 +100,10 @@ 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(talk__accepted=True, then='talk__pk'), output_field=models.IntegerField()), distinct=True), 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),
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
@ -152,7 +155,10 @@ class Participant(PonyConfModel):
@property @property
def accepted_talk_set(self): def accepted_talk_set(self):
return self.talk_set.filter(accepted=True) return self.talk_set.filter(accepted=True).exclude(confirmed=False)
@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)
@ -275,7 +281,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 ugettext(self.name) return gettext(self.name)
def get_absolute_url(self): def get_absolute_url(self):
return reverse('category-list') return reverse('category-list')
@ -311,7 +317,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)) qs = qs.annotate(score=Coalesce(Avg('vote__vote'), 0.0))
return qs return qs
@ -358,6 +364,7 @@ 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()
@ -387,7 +394,7 @@ class Talk(PonyConfModel):
elif self.accepted is False: elif self.accepted is False:
return _('Refused') return _('Refused')
else: else:
return _('Pending decision, score: %(score).1f') % {'score': self.score} return _('Pending decision')
def get_status_color(self): def get_status_color(self):
if self.accepted is True: if self.accepted is True:
@ -423,6 +430,7 @@ 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
@ -483,12 +491,22 @@ 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')) phone_number = models.CharField(max_length=64, blank=True, default='', verbose_name=_('Phone number'), validators=[validate_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 ugettext_lazy as _ from django.utils.translation import gettext_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

@ -1,6 +1,8 @@
{% 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 %}
@ -56,6 +58,7 @@
<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,6 +81,8 @@
<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,7 +95,20 @@
<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,9 +55,11 @@
<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>
@ -82,11 +84,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> <td>{{ talk.get_status_str }}</td>
{{ talk.get_status_str }} <td>{{ talk.score }}</td>
</td>
</tr> </tr>
{% if forloop.last%} {% if forloop.last%}
</tbody> </tbody>

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 ugettext_lazy as _ from django.utils.translation import gettext_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
@ -730,6 +730,7 @@ 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():

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 ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
import hashlib import hashlib

View File

@ -2,6 +2,8 @@ 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 ugettext_lazy as _ from django.utils.translation import gettext_lazy as _
import os import os
@ -34,6 +34,7 @@ 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',
@ -91,6 +92,8 @@ 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
@ -128,7 +131,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'),
] ]
@ -171,4 +174,3 @@ 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,47 +1,107 @@
# #
# This file is autogenerated by pip-compile # This file is autogenerated by pip-compile with Python 3.9
# To update, run: # by the following command:
# #
# pip-compile requirements-dev.in # pip-compile requirements-dev.in
# #
asgiref==3.2.10 # via django asgiref==3.6.0
backcall==0.2.0 # via ipython # via django
bleach==3.1.5 # via -r requirements.in asttokens==2.2.1
chardet==3.0.4 # via -r requirements.in # via stack-data
decorator==4.4.2 # via ipython, traitlets backcall==0.2.0
django-appconf==1.0.4 # via django-select2 # via ipython
django-autoslug==1.9.8 # via -r requirements.in bleach==6.0.0
django-bootstrap3==14.1.0 # via -r requirements.in # via -r requirements.in
django-colorful==1.3 # via -r requirements.in chardet==5.1.0
django-crispy-forms==1.9.2 # via -r requirements.in # via -r requirements.in
django-debug-toolbar==2.2 # via -r requirements-dev.in crispy-bootstrap3==2022.1
django-extensions==3.0.4 # via -r requirements-dev.in # via -r requirements.in
django-select2==7.4.2 # via -r requirements.in decorator==5.1.1
django==3.1 # via -r requirements.in, django-appconf, django-bootstrap3, django-colorful, django-debug-toolbar, django-select2 # via ipython
icalendar==4.0.6 # via -r requirements.in django==4.1.7
importlib-metadata==1.7.0 # via django-bootstrap3, markdown # via
ipython-genutils==0.2.0 # via traitlets # -r requirements.in
ipython==7.16.1 # via -r requirements-dev.in # crispy-bootstrap3
jedi==0.17.2 # via ipython # 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-debug-toolbar
parso==0.7.1 # via jedi # django-extensions
pexpect==4.8.0 # via ipython # django-select2
pickleshare==0.7.5 # via ipython django-appconf==1.0.5
prompt-toolkit==3.0.5 # via ipython # via django-select2
ptyprocess==0.6.0 # via pexpect django-autoslug==1.9.8
pygments==2.6.1 # via ipython # via -r requirements.in
pyparsing==2.4.7 # via packaging django-bootstrap3==22.2
python-dateutil==2.8.1 # via icalendar # via -r requirements.in
pytz==2020.1 # via django, icalendar django-colorful==1.3
six==1.15.0 # via bleach, packaging, python-dateutil, traitlets # via -r requirements.in
sqlparse==0.3.1 # via django, django-debug-toolbar django-crispy-forms==2.0
traitlets==4.3.3 # via ipython # via
wcwidth==0.2.5 # via prompt-toolkit # -r requirements.in
webencodings==0.5.1 # via bleach # crispy-bootstrap3
zipp==3.1.0 # via importlib-metadata django-debug-toolbar==3.8.1
# via -r requirements-dev.in
# The following packages are considered to be unsafe in a requirements file: django-extensions==3.2.1
# setuptools # via -r requirements-dev.in
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,6 +2,7 @@ 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
@ -11,3 +12,4 @@ bleach
chardet chardet
icalendar icalendar
jinja2 jinja2
phonenumbers

View File

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