Merge branch 'master' into test/views

This commit is contained in:
Martin Pépin 2017-10-10 15:39:18 +02:00
commit 3d22a1b029
17 changed files with 252 additions and 98 deletions

View file

@ -1,24 +1,24 @@
services:
- mysql:latest
- postgres:latest
- redis:latest
variables:
# GestioCOF settings
DJANGO_SETTINGS_MODULE: "cof.settings_dev"
DBNAME: "cof_gestion"
DBUSER: "cof_gestion"
DBPASSWD: "cof_password"
DBHOST: "mysql"
DJANGO_SETTINGS_MODULE: "cof.settings.prod"
DBHOST: "postgres"
REDIS_HOST: "redis"
REDIS_PASSWD: "dummy"
# Cached packages
PYTHONPATH: "$CI_PROJECT_DIR/vendor/python"
# mysql service configuration
MYSQL_DATABASE: "$DBNAME"
MYSQL_USER: "$DBUSER"
MYSQL_PASSWORD: "$DBPASSWD"
MYSQL_ROOT_PASSWORD: "root_password"
# postgres service configuration
POSTGRES_PASSWORD: "4KZt3nGPLVeWSvtBZPSM3fSzXpzEU4"
POSTGRES_USER: "cof_gestion"
POSTGRES_DB: "cof_gestion"
# psql password authentication
PGPASSWORD: $POSTGRES_PASSWORD
cache:
@ -29,15 +29,14 @@ cache:
before_script:
- mkdir -p vendor/{python,pip,apt}
- apt-get update -q && apt-get -o dir::cache::archives="vendor/apt" install -yqq mysql-client
- mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host="$DBHOST"
-e "GRANT ALL ON test_$DBNAME.* TO '$DBUSER'@'%'"
- apt-get update -q && apt-get -o dir::cache::archives="vendor/apt" install -yqq postgresql-client
- sed -E 's/^REDIS_HOST.*/REDIS_HOST = "redis"/' cof/settings/secret_example.py > cof/settings/secret.py
# Remove the old test database if it has not been done yet
- mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host="$DBHOST"
-e "DROP DATABASE test_$DBNAME" || true
- pip install --cache-dir vendor/pip -t vendor/python -r requirements-devel.txt
- psql --username=$POSTGRES_USER --host=$DBHOST -c "DROP DATABASE IF EXISTS test_$POSTGRES_DB"
- pip install --cache-dir vendor/pip -t vendor/python -r requirements.txt
- redis-cli config set requirepass $REDIS_PASSWD || true
test:
stage: test
script:
- python manage.py test
- python manage.py test -v3

View file

@ -56,17 +56,17 @@ class AttributionInline(admin.TabularInline):
def get_queryset(self, request):
qs = super().get_queryset(request)
if self.listing is not None:
qs.filter(spectacle__listing=self.listing)
qs = qs.filter(spectacle__listing=self.listing)
return qs
class WithListingAttributionInline(AttributionInline):
exclude = ('given', )
form = WithListingAttributionTabularAdminForm
listing = True
class WithoutListingAttributionInline(AttributionInline):
exclude = ('given', )
form = WithoutListingAttributionTabularAdminForm
listing = False

View file

@ -21,6 +21,7 @@ ALLOWED_HOSTS = [
STATIC_ROOT = os.path.join(
os.path.dirname(os.path.dirname(BASE_DIR)),
"public",
"gestion",
"static",
)

View file

@ -3,7 +3,6 @@ from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import User
from django.forms.widgets import RadioSelect, CheckboxSelectMultiple
from django.forms.formsets import BaseFormSet, formset_factory
from django.core.validators import MinLengthValidator
from djconfig.forms import ConfigForm
@ -197,9 +196,6 @@ class RegistrationUserForm(forms.ModelForm):
super(RegistrationUserForm, self).__init__(*args, **kw)
self.fields['username'].help_text = ""
def force_long_username(self):
self.fields['username'].validators = [MinLengthValidator(9)]
class Meta:
model = User
fields = ("username", "first_name", "last_name", "email")

View file

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('gestioncof', '0010_delete_custommail'),
]
operations = [
migrations.AlterField(
model_name='cofprofile',
name='login_clipper',
field=models.CharField(verbose_name='Login clipper', blank=True, max_length=32),
),
]

View file

@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('gestioncof', '0011_remove_cofprofile_num'),
('gestioncof', '0011_longer_clippers'),
]
operations = [
]

View file

@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('gestioncof', '0012_merge'),
]
operations = [
migrations.AlterField(
model_name='cofprofile',
name='occupation',
field=models.CharField(
verbose_name='Occupation',
max_length=9,
default='1A',
choices=[
('exterieur', 'Extérieur'),
('1A', '1A'),
('2A', '2A'),
('3A', '3A'),
('4A', '4A'),
('archicube', 'Archicube'),
('doctorant', 'Doctorant'),
('CST', 'CST'),
('PEI', 'PEI')
]),
),
migrations.AlterField(
model_name='cofprofile',
name='type_cotiz',
field=models.CharField(
verbose_name='Type de cotisation',
max_length=9,
default='normalien',
choices=[
('etudiant', 'Normalien étudiant'),
('normalien', 'Normalien élève'),
('exterieur', 'Extérieur'),
('gratis', 'Gratuit')
]),
),
]

View file

@ -8,23 +8,6 @@ from gestioncof.petits_cours_models import choices_length
from bda.models import Spectacle
OCCUPATION_CHOICES = (
('exterieur', _("Extérieur")),
('1A', _("1A")),
('2A', _("2A")),
('3A', _("3A")),
('4A', _("4A")),
('archicube', _("Archicube")),
('doctorant', _("Doctorant")),
('CST', _("CST")),
)
TYPE_COTIZ_CHOICES = (
('etudiant', _("Normalien étudiant")),
('normalien', _("Normalien élève")),
('exterieur', _("Extérieur")),
)
TYPE_COMMENT_FIELD = (
('text', _("Texte long")),
('char', _("Texte court")),
@ -32,8 +15,44 @@ TYPE_COMMENT_FIELD = (
class CofProfile(models.Model):
STATUS_EXTE = "exterieur"
STATUS_1A = "1A"
STATUS_2A = "2A"
STATUS_3A = "3A"
STATUS_4A = "4A"
STATUS_ARCHI = "archicube"
STATUS_DOCTORANT = "doctorant"
STATUS_CST = "CST"
STATUS_PEI = "PEI"
OCCUPATION_CHOICES = (
(STATUS_EXTE, _("Extérieur")),
(STATUS_1A, _("1A")),
(STATUS_2A, _("2A")),
(STATUS_3A, _("3A")),
(STATUS_4A, _("4A")),
(STATUS_ARCHI, _("Archicube")),
(STATUS_DOCTORANT, _("Doctorant")),
(STATUS_CST, _("CST")),
(STATUS_PEI, _("PEI")),
)
COTIZ_ETUDIANT = "etudiant"
COTIZ_NORMALIEN = "normalien"
COTIZ_EXTE = "exterieur"
COTIZ_GRATIS = "gratis"
TYPE_COTIZ_CHOICES = (
(COTIZ_ETUDIANT, _("Normalien étudiant")),
(COTIZ_NORMALIEN, _("Normalien élève")),
(COTIZ_EXTE, _("Extérieur")),
(COTIZ_GRATIS, _("Gratuit")),
)
user = models.OneToOneField(User, related_name="profile")
login_clipper = models.CharField("Login clipper", max_length=8, blank=True)
login_clipper = models.CharField(
"Login clipper", max_length=32, blank=True
)
is_cof = models.BooleanField("Membre du COF", default=False)
phone = models.CharField("Téléphone", max_length=20, blank=True)
occupation = models.CharField(_("Occupation"),

View file

@ -10,7 +10,7 @@ export_patterns = [
url(r'^mega/avecremarques$', views.export_mega_remarksonly),
url(r'^mega/participants$', views.export_mega_participants),
url(r'^mega/orgas$', views.export_mega_orgas),
url(r'^mega/(?P<type>.+)$', views.export_mega_bytype),
# url(r'^mega/(?P<type>.+)$', views.export_mega_bytype),
url(r'^mega$', views.export_mega),
]

View file

@ -398,7 +398,6 @@ def registration_form2(request, login_clipper=None, username=None,
elif not login_clipper:
# new user
user_form = RegistrationPassUserForm()
user_form.force_long_username()
profile_form = RegistrationProfileForm()
event_formset = EventFormset(events=events, prefix='events')
clubs_form = ClubsForm()
@ -437,12 +436,10 @@ def registration(request):
user_form = RegistrationUserForm(request_dict, instance=member)
if member.profile.login_clipper:
login_clipper = member.profile.login_clipper
else:
user_form.force_long_username()
except User.DoesNotExist:
user_form.force_long_username()
pass
else:
user_form.force_long_username()
pass
# -----
# Validation des formulaires
@ -609,13 +606,13 @@ def csv_export_mega(filename, qs):
@buro_required
def export_mega_remarksonly(request):
filename = 'remarques_mega_2016.csv'
filename = 'remarques_mega_2017.csv'
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename=' + filename
writer = unicodecsv.writer(response)
event = Event.objects.get(title="Mega 2016")
commentfield = event.commentfields.get(name="Commentaires")
event = Event.objects.get(title="MEGA 2017")
commentfield = event.commentfields.get(name="Commentaire")
for val in commentfield.values.all():
reg = val.registration
user = reg.user
@ -627,50 +624,52 @@ def export_mega_remarksonly(request):
return response
@buro_required
def export_mega_bytype(request, type):
types = {"orga-actif": "Orga élève",
"orga-branleur": "Orga étudiant",
"conscrit-eleve": "Conscrit élève",
"conscrit-etudiant": "Conscrit étudiant"}
if type not in types:
raise Http404
event = Event.objects.get(title="Mega 2016")
type_option = event.options.get(name="Type")
participant_type = type_option.choices.get(value=types[type]).id
qs = EventRegistration.objects.filter(event=event).filter(
options__id__exact=participant_type)
return csv_export_mega(type + '_mega_2016.csv', qs)
# @buro_required
# def export_mega_bytype(request, type):
# types = {"orga-actif": "Orga élève",
# "orga-branleur": "Orga étudiant",
# "conscrit-eleve": "Conscrit élève",
# "conscrit-etudiant": "Conscrit étudiant"}
#
# if type not in types:
# raise Http404
#
# event = Event.objects.get(title="MEGA 2017")
# type_option = event.options.get(name="Type")
# participant_type = type_option.choices.get(value=types[type]).id
# qs = EventRegistration.objects.filter(event=event).filter(
# options__id__exact=participant_type)
# return csv_export_mega(type + '_mega_2017.csv', qs)
@buro_required
def export_mega_orgas(request):
event = Event.objects.get(title="Mega 2016")
type_option = event.options.get(name="Conscrit ou orga ?")
participant_type = type_option.choices.get(value="Vieux").id
qs = EventRegistration.objects.filter(event=event).exclude(
options__id=participant_type)
return csv_export_mega('orgas_mega_2016.csv', qs)
event = Event.objects.get(title="MEGA 2017")
type_option = event.options.get(name="Conscrit/Orga ?")
participant_type = type_option.choices.get(value="Orga").id
qs = EventRegistration.objects.filter(event=event).filter(
options__id=participant_type
)
return csv_export_mega('orgas_mega_2017.csv', qs)
@buro_required
def export_mega_participants(request):
event = Event.objects.get(title="Mega 2016")
type_option = event.options.get(name="Conscrit ou orga ?")
event = Event.objects.get(title="MEGA 2017")
type_option = event.options.get(name="Conscrit/Orga ?")
participant_type = type_option.choices.get(value="Conscrit").id
qs = EventRegistration.objects.filter(event=event).filter(
options__id=participant_type)
return csv_export_mega('participants_mega_2016.csv', qs)
options__id=participant_type
)
return csv_export_mega('participants_mega_2017.csv', qs)
@buro_required
def export_mega(request):
event = Event.objects.filter(title="Mega 2016")
event = Event.objects.filter(title="MEGA 2017")
qs = EventRegistration.objects.filter(event=event) \
.order_by("user__username")
return csv_export_mega('all_mega_2016.csv', qs)
return csv_export_mega('all_mega_2017.csv', qs)
@buro_required

View file

@ -5,7 +5,6 @@ from decimal import Decimal
from django import forms
from django.core.exceptions import ValidationError
from django.core.validators import MinLengthValidator
from django.contrib.auth.models import User, Group, Permission
from django.contrib.contenttypes.models import ContentType
from django.forms import modelformset_factory, widgets
@ -110,21 +109,16 @@ class CofRestrictForm(CofForm):
class Meta(CofForm.Meta):
fields = ['departement']
class UserForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
from_clipper = kwargs.pop('from_clipper', False)
new_user = kwargs.get('instance') is None and not from_clipper
super(UserForm, self).__init__(*args, **kwargs)
if new_user:
self.fields['username'].validators = [MinLengthValidator(9)]
class UserForm(forms.ModelForm):
class Meta:
model = User
model = User
fields = ['username', 'first_name', 'last_name', 'email']
help_texts = {
'username': ''
}
class UserRestrictForm(UserForm):
class Meta(UserForm.Meta):
fields = ['first_name', 'last_name']
@ -173,10 +167,22 @@ class GroupForm(forms.ModelForm):
name = self.cleaned_data['name']
return 'K-Fêt %s' % name
def clean_permissions(self):
kfet_perms = self.cleaned_data['permissions']
# TODO: With Django >=1.11, the QuerySet method 'difference' can be used.
# other_groups = self.instance.permissions.difference(
# self.fields['permissions'].queryset
# )
other_perms = self.instance.permissions.exclude(
pk__in=[p.pk for p in self.fields['permissions'].queryset],
)
return list(kfet_perms) + list(other_perms)
class Meta:
model = Group
model = Group
fields = ['name', 'permissions']
class AccountNegativeForm(forms.ModelForm):
class Meta:
model = AccountNegative

View file

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('kfet', '0053_created_at'),
]
operations = [
migrations.AlterField(
model_name='account',
name='promo',
field=models.IntegerField(blank=True, choices=[(1980, 1980), (1981, 1981), (1982, 1982), (1983, 1983), (1984, 1984), (1985, 1985), (1986, 1986), (1987, 1987), (1988, 1988), (1989, 1989), (1990, 1990), (1991, 1991), (1992, 1992), (1993, 1993), (1994, 1994), (1995, 1995), (1996, 1996), (1997, 1997), (1998, 1998), (1999, 1999), (2000, 2000), (2001, 2001), (2002, 2002), (2003, 2003), (2004, 2004), (2005, 2005), (2006, 2006), (2007, 2007), (2008, 2008), (2009, 2009), (2010, 2010), (2011, 2011), (2012, 2012), (2013, 2013), (2014, 2014), (2015, 2015), (2016, 2016), (2017, 2017)], default=2017, null=True),
),
]

View file

@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('kfet', '0056_change_account_meta'),
('kfet', '0054_update_promos'),
]
operations = [
]

View file

@ -14,10 +14,16 @@
.kfetopen .base {
height: 50px;
padding: 15px;
max-width: 16px;
display: inline-flex;
margin-left: 5px;
margin-right: 5px;
display: flex;
flex-wrap: wrap;
align-content: center;
align-items: center;
justify-content: center;
}
.kfetopen .details {
@ -34,10 +40,23 @@
height: 10px;
border-radius: 50%;
transition: background 0.15s;
margin: 3px;
}
.kfetopen .warning {
margin-left: 15px;
display: none;
}
@media (min-width: 576px) {
.kfetopen .base {
max-width: none;
margin-left: 15px;
margin-right: 15px;
}
.kfetopen .warning {
margin-left: 15px;
}
}
.kfetopen .status-text {

View file

@ -74,10 +74,10 @@ OpenKfet.prototype = {
if (this.admin) {
this.add_class(this.admin_status);
if (this.force_close) {
this.dom.warning.addClass('in');
this.dom.warning.show().addClass('in');
this.dom.force_close_btn.html(this.force_text['deactivate']);
} else {
this.dom.warning.removeClass('in');
this.dom.warning.removeClass('in').hide();
this.dom.force_close_btn.html(this.force_text['activate']);
}
}

View file

@ -94,7 +94,7 @@
{% endif %}
<li class="divider"></li>
<li>
<a href="{% url "cof-logout" %}?next=/k-fet/">
<a href="{% url "cof-logout" %}?next={% slugurl "k-fet" %}">
<span class="glyphicon glyphicon-log-out"></span><span>Déconnexion</span>
</a>
</li>
@ -103,7 +103,7 @@
{% endif %}
{% if user.is_authenticated and not perms.kfet.is_team %}
<li>
<a href="{% url "cof-logout" %}?next=/k-fet/" title="Déconnexion">
<a href="{% url "cof-logout" %}?next={% slugurl "k-fet" %}" title="Déconnexion">
<span class="glyphicon glyphicon-log-out"></span>
</a>
</li>

View file

@ -268,10 +268,10 @@ def get_account_create_forms(request=None, username=None, login_clipper=None,
# Form créations
if request:
user_form = UserForm(request.POST, initial=user_initial, from_clipper=True)
user_form = UserForm(request.POST, initial=user_initial)
cof_form = CofForm(request.POST, initial=cof_initial)
else:
user_form = UserForm(initial=user_initial, from_clipper=True)
user_form = UserForm(initial=user_initial)
cof_form = CofForm(initial=cof_initial)
# Protection (read-only) des champs username et login_clipper