Skip to content
Snippets Groups Projects
Commit c5cce4de authored by Dylan Sechet's avatar Dylan Sechet
Browse files

Merge branch 'master' into dev

parents b6ac58c4 f0d02577
No related branches found
No related tags found
14 merge requests!58Hamza,!52Hamza,!54Add field "en attentes" in participations options,!51Hamza,!48Hamza,!45Hamza,!40Solve public permission files on AWS,!36Notifications for Sec-Gen,!34Dev-> Master (ordering students by updated_date, school filter, export_csv for visits),!31Sorties,!24Amélioration de l'interface admin,!28Updated student admin filters,!27Better filtering for registration,!26merge dev into master
Showing
with 426 additions and 17 deletions
......@@ -50,13 +50,17 @@ Le site utilise une base de données SQL. Plusieurs technologies existent mais o
Après avoir installé PostgreSQL, démarrez le serveur en ouvrant pgAdmin, l'interface graphique qui sera installée en même temps que Postgres.
- Créez une nouvelle base de données :
Dans le menu de gauche, dépliez `Servers (1)`, puis votre serveur (nommé `PostgreSQL XX` par défaut), puis faites un clic droit sur l'onglet `Databases` et créez une base de données nommée `oser_backend_db`.
### Installation du projet
- (Recommandé) Créez un environnement virtuel (ici appelé `env`) puis activez-le :
- (Recommandé) Créez un environnement virtuel (appelé ici oser-back) à l'aide de conda et activez-le :
```bash
$ python -m venv env
$ source env/bin/activate
$ conda create -n oser-back
$ conda activate oser-back
```
- Installez les dépendances :
......@@ -70,6 +74,7 @@ $ pip install -r requirements.txt
```bash
$ python manage.py migrate
```
(En cas d'erreur, les logs du serveur PostgreSQL sont disponibles dans : %PROGRAMFILES%\PostgreSQL\POSTGRESQL_VERSION_NUM\data\log)
Il ne vous reste plus qu'à lancer le serveur de développement :
......
......@@ -26,7 +26,7 @@ router.register('users', users_views.UserViewSet)
# Profiles views
router.register('tutors', profiles_views.TutorViewSet)
router.register('students', profiles_views.StudentViewSet)
router.register('students', profiles_views.StudentViewSet, base_name='student')
# Register views
router.register('registrations', register_views.RegistrationViewSet)
......
......@@ -5,7 +5,7 @@ import factory.django
from . import models
class DocumentFactory(factory.DjangoModelFactory):
class DocumentFactory(factory.django.DjangoModelFactory):
"""Document object factory."""
class Meta: # noqa
......@@ -15,7 +15,7 @@ class DocumentFactory(factory.DjangoModelFactory):
content = factory.Faker('text', max_nb_chars=1000, locale='fr')
class AddressFactory(factory.DjangoModelFactory):
class AddressFactory(factory.django.DjangoModelFactory):
"""Address object factory."""
class Meta: # noqa
......
......@@ -28,7 +28,7 @@ class PasswordResetSerializer(serializers.Serializer):
###### USE YOUR TEXT FILE ######
'email_template_name': 'email-reset-template.txt',
'subject_template_name': 'subject-reset-template.txt',
'request': request,
}
self.reset_form.save(**opts)
\ No newline at end of file
......@@ -5,10 +5,13 @@ Common settings suitable for all environmebts.
"""
import os
from dotenv import load_dotenv
import dj_database_url
import pymdownx.emoji
load_dotenv()
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
dn = os.path.dirname
BASE_DIR = dn(dn(dn(os.path.abspath(__file__))))
......@@ -35,7 +38,7 @@ DJANGO_APPS = [
'whitenoise.runserver_nostatic',
'django.contrib.staticfiles',
'django.forms',
'django.contrib.sites',
'django.contrib.sites'
]
THIRD_PARTY_APPS = [
......
......@@ -5,7 +5,7 @@ from .common import *
from .common import BASE_DIR
DEBUG = True
ALLOWED_HOSTS = ['localhost']
ALLOWED_HOSTS = ['localhost','127.0.0.1']
# Static files (CSS, JavaScript, Images) and media files (user-uploaded)
......@@ -25,4 +25,4 @@ DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
# Mails config
# However emails won't be delivered by SendGrid (use dev_sendgrid settings)
MAILS_ENABLED = True
MAILS_ENABLED = False
......@@ -5,3 +5,4 @@ from .dev import *
# Allow to send emails with SendGrid while in DEBUG mode.
# See: https://github.com/sklarsa/django-sendgrid-v5#other-settings
SENDGRID_SANDBOX_MODE_IN_DEBUG = False
from django.contrib import admin
from django.contrib.admin.utils import reverse_field_path
from django.utils.translation import gettext_lazy as _
class MultiSelectFieldListFilter(admin.FieldListFilter):
def __init__(self, field, request, params, model, model_admin, field_path):
self.lookup_kwarg = field_path + '__in'
self.lookup_kwarg_isnull = field_path + '__isnull'
super().__init__(field, request, params, model, model_admin, field_path)
self.lookup_val = self.used_parameters.get(self.lookup_kwarg, [])
if len(self.lookup_val) == 1 and self.lookup_val[0] == '':
self.lookup_val = []
self.lookup_val_isnull = self.used_parameters.get(self.lookup_kwarg_isnull)
self.empty_value_display = model_admin.get_empty_value_display()
parent_model, reverse_path = reverse_field_path(model, field_path)
# Obey parent ModelAdmin queryset when deciding which options to show
if model == parent_model:
queryset = model_admin.get_queryset(request)
else:
queryset = parent_model._default_manager.all()
self.lookup_choices = queryset.distinct().order_by(field.name).values_list(field.name, flat=True)
def expected_parameters(self):
return [self.lookup_kwarg, self.lookup_kwarg_isnull]
def choices(self, changelist):
yield {
'selected': not self.lookup_val and self.lookup_val_isnull is None,
'query_string': changelist.get_query_string(remove=[self.lookup_kwarg, self.lookup_kwarg_isnull]),
'display': _('All'),
}
include_none = False
for val in self.lookup_choices:
if val is None:
include_none = True
continue
val = str(val)
if val in self.lookup_val:
values = [v for v in self.lookup_val if v != val]
else:
values = self.lookup_val + [ val ]
if values:
yield {
'selected': val in self.lookup_val,
'query_string': changelist.get_query_string({self.lookup_kwarg: ','.join(values)}, [self.lookup_kwarg_isnull]),
'display': val,
}
else:
yield {
'selected': val in self.lookup_val,
'query_string': changelist.get_query_string(remove=[self.lookup_kwarg]),
'display': val,
}
if include_none:
yield {
'selected': bool(self.lookup_val_isnull),
'query_string': changelist.get_query_string({self.lookup_kwarg_isnull: 'True'}, [self.lookup_kwarg]),
'display': self.empty_value_display,
}
\ No newline at end of file
......@@ -2,6 +2,8 @@
from django.contrib import admin
from .models import Student, Tutor
from .MultiSelectFieldListFilter import MultiSelectFieldListFilter
import codecs
import csv
from django.http import HttpResponse
......@@ -13,7 +15,8 @@ class ExportCsvMixin:
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename={}.csv'.format(meta)
writer = csv.writer(response)
response.write(codecs.BOM_UTF8) #force response to be UTF-8
writer = csv.writer(response, delimiter=';')
writer.writerow(field_names)
for obj in queryset:
......@@ -21,7 +24,7 @@ class ExportCsvMixin:
return response
export_as_csv.short_description = "Export Selected"
export_as_csv.short_description = "Exporter sélection (en .csv)"
class ProfileAdminMixin:
......@@ -40,10 +43,11 @@ class TutorAdmin(ProfileAdminMixin, admin.ModelAdmin,ExportCsvMixin):
model = Tutor
actions = ["export_as_csv"]
@admin.register(Student)
class StudentAdmin(ProfileAdminMixin, admin.ModelAdmin,ExportCsvMixin):
"""Student admin panel."""
list_filter = (('school',MultiSelectFieldListFilter), 'year')
class Meta: # noqa
model = Student
actions = ["export_as_csv"]
\ No newline at end of file
......@@ -12,7 +12,7 @@ from users.factory import UserFactory
from . import models
class StudentFactory(factory.DjangoModelFactory):
class StudentFactory(factory.django.DjangoModelFactory):
"""Student object factory."""
class Meta: # noqa
......@@ -24,7 +24,7 @@ class StudentFactory(factory.DjangoModelFactory):
_this_year = datetime.today().year
class TutorFactory(factory.DjangoModelFactory):
class TutorFactory(factory.django.DjangoModelFactory):
"""Tutor object factory."""
class Meta: # noqa
......
# Generated by Django 2.2 on 2020-09-13 22:57
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('profiles', '0002_auto_20180911_1938'),
]
operations = [
migrations.AddField(
model_name='student',
name='addressNumber',
field=models.IntegerField(blank=True, null=True, verbose_name='numéro de rue'),
),
migrations.AddField(
model_name='student',
name='city',
field=models.CharField(blank=True, max_length=50, null=True, verbose_name='nom de ville'),
),
migrations.AddField(
model_name='student',
name='dependantsNumber',
field=models.CharField(blank=True, max_length=12, null=True, verbose_name="numero d'urgence"),
),
migrations.AddField(
model_name='student',
name='fatherActivity',
field=models.CharField(blank=True, max_length=70, null=True, verbose_name='metier du pere'),
),
migrations.AddField(
model_name='student',
name='gender',
field=models.CharField(blank=True, max_length=20, null=True, verbose_name='genre'),
),
migrations.AddField(
model_name='student',
name='grade',
field=models.CharField(blank=True, max_length=20, null=True, verbose_name='nom du niveau de la classe'),
),
migrations.AddField(
model_name='student',
name='motherActivity',
field=models.CharField(blank=True, max_length=70, null=True, verbose_name='metier de la mere'),
),
migrations.AddField(
model_name='student',
name='parentsEmail',
field=models.EmailField(blank=True, max_length=20, null=True, verbose_name='adresse mail parentale'),
),
migrations.AddField(
model_name='student',
name='parentsPhone',
field=models.CharField(blank=True, max_length=12, null=True, verbose_name='numéro de téléphone parental'),
),
migrations.AddField(
model_name='student',
name='parentsStatus',
field=models.CharField(blank=True, max_length=30, null=True, verbose_name='statut des parents'),
),
migrations.AddField(
model_name='student',
name='personnalPhone',
field=models.CharField(blank=True, max_length=12, null=True, verbose_name='numéro de téléphone personnel'),
),
migrations.AddField(
model_name='student',
name='scholarship',
field=models.BooleanField(blank=True, null=True, verbose_name='boursier'),
),
migrations.AddField(
model_name='student',
name='school',
field=models.CharField(blank=True, max_length=70, null=True, verbose_name="nom de l'ecole"),
),
migrations.AddField(
model_name='student',
name='street',
field=models.CharField(blank=True, max_length=70, null=True, verbose_name='nom de rue'),
),
migrations.AlterField(
model_name='tutor',
name='promotion',
field=models.IntegerField(choices=[(2023, '2023'), (2022, '2022'), (2021, '2021'), (2020, '2020'), (2019, '2019')], default=2023),
),
]
# Generated by Django 2.2 on 2020-09-15 16:27
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('profiles', '0003_auto_20200914_0057'),
]
operations = [
migrations.AlterField(
model_name='student',
name='dependantsNumber',
field=models.CharField(blank=True, max_length=12, null=True, verbose_name="numéro d'urgence"),
),
migrations.AlterField(
model_name='student',
name='fatherActivity',
field=models.CharField(blank=True, max_length=70, null=True, verbose_name='métier du père'),
),
migrations.AlterField(
model_name='student',
name='grade',
field=models.CharField(blank=True, max_length=20, null=True, verbose_name='niveau de la classe'),
),
migrations.AlterField(
model_name='student',
name='motherActivity',
field=models.CharField(blank=True, max_length=70, null=True, verbose_name='métier de la mère'),
),
migrations.AlterField(
model_name='student',
name='scholarship',
field=models.NullBooleanField(verbose_name='boursier'),
),
migrations.AlterField(
model_name='student',
name='school',
field=models.CharField(blank=True, max_length=70, null=True, verbose_name="nom de l'école"),
),
]
# Generated by Django 2.2 on 2020-09-18 11:20
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('profiles', '0003_auto_20200914_0057'),
]
operations = [
migrations.AlterField(
model_name='student',
name='dependantsNumber',
field=models.CharField(blank=True, max_length=12, null=True, verbose_name="numéro d'urgence"),
),
migrations.AlterField(
model_name='student',
name='fatherActivity',
field=models.CharField(blank=True, max_length=70, null=True, verbose_name='métier du père'),
),
migrations.AlterField(
model_name='student',
name='grade',
field=models.CharField(blank=True, max_length=20, null=True, verbose_name='niveau de la classe'),
),
migrations.AlterField(
model_name='student',
name='motherActivity',
field=models.CharField(blank=True, max_length=70, null=True, verbose_name='métier de la mère'),
),
migrations.AlterField(
model_name='student',
name='scholarship',
field=models.NullBooleanField(verbose_name='boursier'),
),
migrations.AlterField(
model_name='student',
name='school',
field=models.CharField(blank=True, max_length=70, null=True, verbose_name="nom de l'école"),
),
]
# Generated by Django 2.2 on 2020-09-18 16:05
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('profiles', '0004_auto_20200918_1320'),
]
operations = [
migrations.AlterField(
model_name='student',
name='scholarship',
field=models.CharField(blank=True, max_length=10, null=True, verbose_name='boursier'),
),
]
# Generated by Django 2.2 on 2020-09-18 16:18
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('profiles', '0005_auto_20200918_1805'),
]
operations = [
migrations.AddField(
model_name='student',
name='nationality',
field=models.CharField(blank=True, max_length=30, null=True, verbose_name='nationalité'),
),
migrations.AddField(
model_name='student',
name='specialTeaching',
field=models.CharField(blank=True, max_length=30, null=True, verbose_name='enseignement de spécialité'),
),
migrations.AddField(
model_name='student',
name='zipCode',
field=models.CharField(blank=True, max_length=10, null=True, verbose_name='code postal'),
),
]
# Generated by Django 2.2 on 2020-09-18 16:24
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('profiles', '0006_auto_20200918_1818'),
('profiles', '0004_auto_20200915_1827'),
]
operations = [
]
# Generated by Django 2.2 on 2020-09-18 17:13
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('profiles', '0007_merge_20200918_1824'),
]
operations = [
migrations.AlterField(
model_name='student',
name='scholarship',
field=models.CharField(blank=True, max_length=10, null=True, verbose_name='boursier'),
),
]
# Generated by Django 2.2 on 2020-09-23 11:29
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('profiles', '0008_auto_20200918_1913'),
]
operations = [
migrations.AlterField(
model_name='student',
name='dependantsNumber',
field=models.IntegerField(blank=True, null=True, verbose_name='nombre de personnes à charge'),
),
migrations.AlterField(
model_name='student',
name='nationality',
field=models.CharField(blank=True, max_length=50, null=True, verbose_name='nationalité'),
),
migrations.AlterField(
model_name='student',
name='parentsEmail',
field=models.EmailField(blank=True, max_length=70, null=True, verbose_name='adresse mail parentale'),
),
migrations.AlterField(
model_name='student',
name='parentsStatus',
field=models.CharField(blank=True, max_length=70, null=True, verbose_name='statut des parents'),
),
migrations.AlterField(
model_name='student',
name='scholarship',
field=models.CharField(blank=True, max_length=50, null=True, verbose_name='boursier'),
),
migrations.AlterField(
model_name='student',
name='specialTeaching',
field=models.CharField(blank=True, max_length=50, null=True, verbose_name='enseignement de spécialité'),
),
]
# Generated by Django 2.2 on 2020-09-23 12:44
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('profiles', '0009_auto_20200923_1329'),
]
operations = [
migrations.RenameField(
model_name='student',
old_name='personnalPhone',
new_name='personalPhone',
),
]
# Generated by Django 2.2 on 2020-09-24 16:56
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('profiles', '0010_auto_20200923_1444'),
]
operations = [
migrations.AddField(
model_name='student',
name='classType',
field=models.CharField(blank=True, max_length=50, null=True, verbose_name='général/techno'),
),
]
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment