Initial commit
This commit is contained in:
commit
793bb6a488
182 changed files with 17153 additions and 0 deletions
0
common/__init__.py
Normal file
0
common/__init__.py
Normal file
99
common/choices.py
Normal file
99
common/choices.py
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
|
||||
|
||||
AUTORITE_PARENTALE_CHOICES = (
|
||||
('conjointe', 'Conjointe'),
|
||||
('pere', 'Père'),
|
||||
('mere', 'Mère'),
|
||||
('tutelle', 'Tutelle')
|
||||
)
|
||||
|
||||
|
||||
DEMARCHE_CHOICES = (
|
||||
('volontaire', 'Volontaire'),
|
||||
('contrainte', 'Contrainte'),
|
||||
('post_placement', 'Post placement'),
|
||||
('non_placement', 'Eviter placement')
|
||||
)
|
||||
|
||||
|
||||
MANDATS_OPE_CHOICES = (
|
||||
('volontaire', 'Mandat volontaire'),
|
||||
('curatelle', 'Curatelle 308'),
|
||||
('referent', 'Référent'),
|
||||
('enquete', 'Enquête'),
|
||||
('tutelle', 'Curatelle de portée générale'),
|
||||
)
|
||||
|
||||
|
||||
MOTIF_DEMANDE_CHOICES = (
|
||||
('accompagnement', 'Accompagnement psycho-éducatif'),
|
||||
('integration', 'Aide à l’intégration'),
|
||||
('demande', 'Elaboration d’une demande (contrainte)'),
|
||||
('crise', 'Travail sur la crise'),
|
||||
('post-placement', 'Post-placement'),
|
||||
('pre-placement', 'Pré-placement'),
|
||||
('violence', 'Violence / maltraitances'),
|
||||
)
|
||||
|
||||
|
||||
MOTIFS_FIN_SUIVI_CHOICES = (
|
||||
('desengagement', 'Désengagement'),
|
||||
('evol_positive', 'Autonomie familiale'),
|
||||
('relai_amb', 'Relai vers ambulatoire'),
|
||||
('relai', 'Relai vers autre service'),
|
||||
('placement', 'Placement'),
|
||||
('non_aboutie', 'Demande non aboutie'),
|
||||
('non_dispo', 'Pas de disponibilités/place'),
|
||||
('erreur', 'Erreur de saisie'),
|
||||
('autres', 'Autres'), # Obsolète (#435)
|
||||
)
|
||||
|
||||
|
||||
PROVENANCE_DESTINATION_CHOICES = (
|
||||
('famille', 'Famille'),
|
||||
('ies-ne', 'IES-NE'),
|
||||
('ies-hc', 'IES-HC'),
|
||||
('aemo', 'SAEMO'),
|
||||
('fah', "Famille d'accueil"),
|
||||
('refug', "Centre d’accueil réfugiés"),
|
||||
('hopital', "Hôpital"),
|
||||
('autre', 'Autre'), # Obsolète (#435)
|
||||
)
|
||||
|
||||
|
||||
SERVICE_ORIENTEUR_CHOICES = (
|
||||
('famille', 'Famille'),
|
||||
('ope', 'OPE'),
|
||||
('aemo', 'AEMO'),
|
||||
('cnpea', 'CNPea'),
|
||||
('ecole', 'École'),
|
||||
('res_prim', 'Réseau primaire'),
|
||||
('res_sec', 'Réseau secondaire'),
|
||||
('pediatre', 'Pédiatre'),
|
||||
('autre', 'Autre'),
|
||||
)
|
||||
|
||||
|
||||
TYPE_GARDE_CHOICES = (
|
||||
('partage', 'garde partagée'),
|
||||
('droit', 'droit de garde'),
|
||||
('visite', 'droit de visite'),
|
||||
)
|
||||
|
||||
STATUT_FINANCIER_CHOICES = (
|
||||
('ai', 'AI PC'),
|
||||
('gsr', 'GSR'),
|
||||
('osas', 'OSAS'),
|
||||
('revenu', 'Revenu'),
|
||||
)
|
||||
|
||||
|
||||
STATUT_MARITAL_CHOICES = (
|
||||
('celibat', 'Célibataire'),
|
||||
('mariage', 'Marié'),
|
||||
('pacs', 'PACS'),
|
||||
('concubin', 'Concubin'),
|
||||
('veuf', 'Veuf'),
|
||||
('separe', 'Séparé'),
|
||||
('divorce', 'Divorcé')
|
||||
)
|
||||
26
common/fields.py
Normal file
26
common/fields.py
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
from django import forms
|
||||
from django.contrib.postgres.fields import ArrayField
|
||||
|
||||
|
||||
class ChoiceArrayField(ArrayField):
|
||||
"""
|
||||
From https://blogs.gnome.org/danni/2016/03/08/multiple-choice-using-djangos-postgres-arrayfield/
|
||||
A field that allows us to store an array of choices.
|
||||
|
||||
Uses Django's postgres ArrayField and a MultipleChoiceField for its formfield.
|
||||
See also https://code.djangoproject.com/ticket/27704
|
||||
"""
|
||||
widget = forms.CheckboxSelectMultiple
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {
|
||||
'form_class': forms.TypedMultipleChoiceField,
|
||||
'coerce': self.base_field.to_python,
|
||||
'choices': self.base_field.choices,
|
||||
'widget': self.widget(attrs={'class': 'choicearray'}),
|
||||
}
|
||||
defaults.update(kwargs)
|
||||
# Skip our parent's formfield implementation completely as we don't
|
||||
# care for it.
|
||||
# pylint:disable=bad-super-call
|
||||
return super(ArrayField, self).formfield(**defaults)
|
||||
31
common/formats/fr/formats.py
Normal file
31
common/formats/fr/formats.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
# Mix between Django fr and de_CH formats.
|
||||
# see https://docs.djangoproject.com/en/dev/ref/templates/builtins/#date
|
||||
DATE_FORMAT = 'j F Y'
|
||||
TIME_FORMAT = 'H:i'
|
||||
DATETIME_FORMAT = 'j F Y H:i'
|
||||
YEAR_MONTH_FORMAT = 'F Y'
|
||||
MONTH_DAY_FORMAT = 'j F'
|
||||
SHORT_DATE_FORMAT = 'j N Y'
|
||||
SHORT_DATETIME_FORMAT = 'j N Y H:i'
|
||||
FIRST_DAY_OF_WEEK = 1 # Monday
|
||||
|
||||
# The *_INPUT_FORMATS strings use the Python strftime format syntax,
|
||||
# see https://docs.python.org/library/datetime.html#strftime-strptime-behavior
|
||||
DATE_INPUT_FORMATS = [
|
||||
'%d.%m.%Y', '%d.%m.%y', # Swiss [fr_CH), '25.10.2006', '25.10.06'
|
||||
'%d/%m/%Y', '%d/%m/%y', # '25/10/2006', '25/10/06'
|
||||
]
|
||||
DATETIME_INPUT_FORMATS = [
|
||||
'%d.%m.%Y %H:%M:%S', # '25.10.2006 14:30:59'
|
||||
'%d.%m.%Y %H:%M:%S.%f', # '25.10.2006 14:30:59.000200'
|
||||
'%d.%m.%Y %H:%M', # '25.10.2006 14:30'
|
||||
'%d.%m.%Y', # '25.10.2006'
|
||||
'%d/%m/%Y %H:%M:%S', # '25/10/2006 14:30:59'
|
||||
'%d/%m/%Y %H:%M:%S.%f', # '25/10/2006 14:30:59.000200'
|
||||
'%d/%m/%Y %H:%M', # '25/10/2006 14:30'
|
||||
'%d/%m/%Y', # '25/10/2006'
|
||||
]
|
||||
|
||||
DECIMAL_SEPARATOR = ','
|
||||
THOUSAND_SEPARATOR = '\xa0' # non-breaking space
|
||||
NUMBER_GROUPING = 3
|
||||
35
common/middleware.py
Normal file
35
common/middleware.py
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import re
|
||||
from ipaddress import ip_address
|
||||
|
||||
from django.conf import settings
|
||||
from django.urls import reverse
|
||||
from django.http import HttpResponseRedirect
|
||||
|
||||
EXEMPT_URLS = [
|
||||
re.compile(r'^account/*'),
|
||||
re.compile(r'^agenda/rendez-vous*'),
|
||||
re.compile(r'^login/$'),
|
||||
re.compile(r'^logout/$'),
|
||||
re.compile(r'^jsi18n/$'),
|
||||
re.compile(r'^favicon.ico$'),
|
||||
]
|
||||
|
||||
|
||||
class LoginRequiredMiddleware:
|
||||
def __init__(self, get_response):
|
||||
self.get_response = get_response
|
||||
|
||||
def __call__(self, request):
|
||||
path = request.path_info.lstrip('/')
|
||||
ip = ip_address(request.META.get('REMOTE_ADDR'))
|
||||
# is_verified checks 2FA auth
|
||||
if not request.user.is_verified() and not any(m.match(path) for m in EXEMPT_URLS):
|
||||
ip_exempted = any(ip in net for net in settings.EXEMPT_2FA_NETWORKS)
|
||||
if request.user.is_authenticated:
|
||||
if ip_exempted or request.user.username in settings.EXEMPT_2FA_USERS:
|
||||
return self.get_response(request)
|
||||
return HttpResponseRedirect(reverse('two_factor:setup'))
|
||||
else:
|
||||
login_view = reverse('login') if ip_exempted else reverse('two_factor:login')
|
||||
return HttpResponseRedirect("{}?next={}".format(login_view, request.path))
|
||||
return self.get_response(request)
|
||||
42
common/urls.py
Normal file
42
common/urls.py
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
from django.conf import settings
|
||||
from django.contrib import admin
|
||||
from django.contrib.auth.urls import urlpatterns as auth_patterns
|
||||
from django.contrib.auth.views import LoginView, LogoutView
|
||||
from django.urls import path, include
|
||||
from django.views.decorators.cache import cache_page
|
||||
from django.views.i18n import JavaScriptCatalog
|
||||
from django.views.static import serve
|
||||
|
||||
from two_factor.urls import urlpatterns as tf_urls
|
||||
|
||||
from aemo import views
|
||||
|
||||
handler404 = 'aemo.views.page_not_found'
|
||||
|
||||
urlpatterns = [
|
||||
path('', views.HomeView.as_view(), name='home'),
|
||||
path('account/password_change/', views.PasswordChangeView.as_view(), name='password_change'),
|
||||
# Overriden 2FA path:
|
||||
path('account/two_factor/setup/', views.SetupView.as_view(), name='setup'),
|
||||
path('', include(tf_urls)),
|
||||
# Standard login is still permitted depending on IP origin
|
||||
path('login/', LoginView.as_view(template_name='login.html'), name='login'),
|
||||
path('logout/', LogoutView.as_view(next_page='/account/login'), name='logout'),
|
||||
path('jsi18n/', cache_page(86400, key_prefix='jsi18n-1')(JavaScriptCatalog.as_view()),
|
||||
name='javascript-catalog'),
|
||||
path("", include("city_ch_autocomplete.urls")),
|
||||
|
||||
path('tinymce/', include('tinymce.urls')),
|
||||
path('admin/', admin.site.urls),
|
||||
path('', include('aemo.urls')),
|
||||
path('archive/', include('archive.urls')),
|
||||
|
||||
path('media/<path:path>', serve,
|
||||
{'document_root': settings.MEDIA_ROOT, 'show_indexes': False}),
|
||||
]
|
||||
|
||||
# Include contrib.auth password reset URLs under the /account prefix
|
||||
for pat in auth_patterns:
|
||||
if pat.name.startswith('password') and pat.name != 'password_change':
|
||||
pat.pattern._route = f'account/{pat.pattern._route}'
|
||||
urlpatterns.append(pat)
|
||||
33
common/wsgi.py
Normal file
33
common/wsgi.py
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
"""
|
||||
WSGI config for aemo project.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
UPGRADING = False
|
||||
|
||||
|
||||
def upgrade_in_progress(environ, start_response):
|
||||
response_headers = [('Content-type', 'text/html')]
|
||||
response = """
|
||||
<body>
|
||||
<h1>This site is in maintenance mode, please come back in some minutes.</h1>
|
||||
<h1>Ce site est actuellement en maintenance, merci de revenir dans quelques minutes.</h1>
|
||||
</body>
|
||||
"""
|
||||
if environ['REQUEST_METHOD'] == 'GET':
|
||||
status = '200 OK'
|
||||
else:
|
||||
status = '403 Forbidden'
|
||||
start_response(status, response_headers)
|
||||
return [response.encode('utf-8')]
|
||||
|
||||
|
||||
if UPGRADING:
|
||||
application = upgrade_in_progress
|
||||
else:
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings")
|
||||
|
||||
application = get_wsgi_application()
|
||||
Loading…
Add table
Add a link
Reference in a new issue