Compare commits
19 commits
master
...
thubrecht/
Author | SHA1 | Date | |
---|---|---|---|
aa949f84b2 | |||
b6d1ee6aa8 | |||
2c92f35a75 | |||
5d3f840de1 | |||
9ddf4d0c6d | |||
56bc3a701e | |||
|
f7ac3313c8 | ||
|
f48570bdaf | ||
|
778c4cde72 | ||
|
de47d9033a | ||
|
bc9fd155e6 | ||
|
04efa743f6 | ||
|
126bce9be3 | ||
|
9004c802eb | ||
|
90aa558896 | ||
|
4e683f62e1 | ||
|
5644ea9290 | ||
|
79eb294ce5 | ||
|
72f28d185c |
33 changed files with 313 additions and 588 deletions
|
@ -1 +0,0 @@
|
|||
insecure-secret-key
|
1
.envrc
1
.envrc
|
@ -1 +0,0 @@
|
|||
use nix
|
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -108,6 +108,6 @@ test.py
|
|||
.#*
|
||||
*.sqlite3
|
||||
.sass-cache
|
||||
/static/
|
||||
settings.py
|
||||
secrets.py
|
||||
.direnv
|
||||
.pre-commit-config.yaml
|
||||
|
|
242
app/settings.py
242
app/settings.py
|
@ -1,242 +0,0 @@
|
|||
"""
|
||||
Django settings for the experiENS project
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from loadcredential import Credentials
|
||||
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
credentials = Credentials(env_prefix="EXPERIENS_")
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
# WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = credentials["SECRET_KEY"]
|
||||
|
||||
# WARNING: don't run with debug turned on in production!
|
||||
DEBUG = credentials.get_json("DEBUG", False)
|
||||
|
||||
ALLOWED_HOSTS = credentials.get_json("ALLOWED_HOSTS", [])
|
||||
|
||||
ADMINS = credentials.get_json("ADMINS", [])
|
||||
|
||||
SITE_ID = 1
|
||||
|
||||
|
||||
###
|
||||
# ElasticSearch configuration
|
||||
|
||||
USE_ELASTICSEARCH = credentials.get_json("USE_ELASTICSEARCH", False)
|
||||
ELASTICSEARCH_DSL = credentials.get_json(
|
||||
"ELASTICSEARCH_DSL", {"default": {"hosts": "127.0.0.1:9200"}}
|
||||
)
|
||||
|
||||
|
||||
###
|
||||
# Libraries configuration
|
||||
|
||||
GDAL_LIBRARY_PATH = credentials.get("GDAL_LIBRARY_PATH")
|
||||
GEOS_LIBRARY_PATH = credentials.get("GEOS_LIBRARY_PATH")
|
||||
|
||||
|
||||
###
|
||||
# List the installed applications
|
||||
|
||||
INSTALLED_APPS = [
|
||||
"django.contrib.admin",
|
||||
"django.contrib.auth",
|
||||
"django.contrib.contenttypes",
|
||||
"django.contrib.sessions",
|
||||
"django.contrib.messages",
|
||||
"django.contrib.staticfiles",
|
||||
"django.contrib.gis",
|
||||
"django.contrib.sites",
|
||||
*(["django_elasticsearch_dsl"] if USE_ELASTICSEARCH else []),
|
||||
"simple_email_confirmation",
|
||||
"authens",
|
||||
"tastypie",
|
||||
"braces",
|
||||
"tinymce",
|
||||
"taggit",
|
||||
"taggit_autosuggest",
|
||||
"avisstage",
|
||||
]
|
||||
|
||||
|
||||
###
|
||||
# List the installed middlewares
|
||||
|
||||
MIDDLEWARE = [
|
||||
"django.middleware.security.SecurityMiddleware",
|
||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
"django.middleware.csrf.CsrfViewMiddleware",
|
||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||
"django.contrib.messages.middleware.MessageMiddleware",
|
||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||
]
|
||||
|
||||
|
||||
###
|
||||
# The main url configuration
|
||||
|
||||
ROOT_URLCONF = "app.urls"
|
||||
|
||||
|
||||
###
|
||||
# Template configuration:
|
||||
# - Django Templating Language is used
|
||||
# - Application directories can be used
|
||||
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||
"DIRS": [],
|
||||
"APP_DIRS": True,
|
||||
"OPTIONS": {
|
||||
"context_processors": [
|
||||
"django.contrib.auth.context_processors.auth",
|
||||
"django.template.context_processors.debug",
|
||||
"django.template.context_processors.i18n",
|
||||
"django.template.context_processors.media",
|
||||
"django.template.context_processors.static",
|
||||
"django.template.context_processors.tz",
|
||||
"django.template.context_processors.request",
|
||||
"django.contrib.messages.context_processors.messages",
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
###
|
||||
# Database configuration
|
||||
# -> https://docs.djangoproject.com/en/4.2/ref/settings/#databases
|
||||
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
|
||||
|
||||
DATABASES = credentials.get_json(
|
||||
"DATABASES",
|
||||
{
|
||||
"default": {
|
||||
"ENGINE": "django.contrib.gis.db.backends.spatialite",
|
||||
"NAME": BASE_DIR / "db.sqlite3",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
CACHES = credentials.get_json(
|
||||
"CACHES",
|
||||
default={
|
||||
"default": {
|
||||
"BACKEND": "django.core.cache.backends.locmem.LocMemCache",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
###
|
||||
# WSGI application configuration
|
||||
|
||||
WSGI_APPLICATION = "app.wsgi.application"
|
||||
|
||||
|
||||
###
|
||||
# Staticfiles configuration
|
||||
|
||||
STATIC_ROOT = credentials["STATIC_ROOT"]
|
||||
STATIC_URL = "/static/"
|
||||
|
||||
MEDIA_ROOT = credentials.get("MEDIA_ROOT", BASE_DIR / "media")
|
||||
MEDIA_URL = "/media/"
|
||||
|
||||
|
||||
###
|
||||
# Internationalization configuration
|
||||
# -> https://docs.djangoproject.com/en/4.2/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = "fr-fr"
|
||||
TIME_ZONE = "Europe/Paris"
|
||||
|
||||
USE_I18N = True
|
||||
USE_L10N = True
|
||||
USE_TZ = True
|
||||
|
||||
LANGUAGES = [
|
||||
("fr", _("Français")),
|
||||
]
|
||||
|
||||
|
||||
###
|
||||
# Authentication configuration
|
||||
|
||||
AUTHENTICATION_BACKENDS = [
|
||||
"django.contrib.auth.backends.ModelBackend",
|
||||
"experiENS.auth.ENSCASBackend",
|
||||
]
|
||||
|
||||
CAS_SERVER_URL = "https://cas.eleves.ens.fr/" # SPI CAS
|
||||
|
||||
AUTHENS_USE_OLDCAS = False
|
||||
|
||||
LOGIN_URL = reverse_lazy("authens:login")
|
||||
LOGOUT_URL = reverse_lazy("authens:logout")
|
||||
LOGIN_REDIRECT_URL = reverse_lazy("avisstage:perso")
|
||||
LOGOUT_REDIRECT_URL = reverse_lazy("avisstage:index")
|
||||
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{"NAME": f"django.contrib.auth.password_validation.{v}"}
|
||||
for v in [
|
||||
"UserAttributeSimilarityValidator",
|
||||
"MinimumLengthValidator",
|
||||
"CommonPasswordValidator",
|
||||
"NumericPasswordValidator",
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
###
|
||||
# Logging configuration
|
||||
|
||||
LOGGING = {
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
"handlers": {
|
||||
"file": {
|
||||
"level": "INFO",
|
||||
"class": "logging.FileHandler",
|
||||
"filename": credentials.get(
|
||||
"RECHERCHE_LOG_FILE", BASE_DIR / "recherche.log"
|
||||
),
|
||||
},
|
||||
},
|
||||
"loggers": {
|
||||
"recherche": {
|
||||
"handlers": ["file"],
|
||||
"level": "INFO",
|
||||
"propagate": True,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
###
|
||||
# LDAP configuration
|
||||
|
||||
CLIPPER_LDAP_SERVER = credentials.get("CLIPPER_LDAP_SERVER", "ldaps://localhost:636")
|
||||
|
||||
|
||||
# Development settings
|
||||
if DEBUG:
|
||||
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
||||
INSTALLED_APPS += [
|
||||
"debug_toolbar",
|
||||
]
|
||||
|
||||
MIDDLEWARE = ["debug_toolbar.middleware.DebugToolbarMiddleware", *MIDDLEWARE]
|
|
@ -4,7 +4,7 @@ from django.contrib import admin
|
|||
from django.contrib.auth.admin import UserAdmin
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from avisstage.models import AvisLieu, AvisStage, Lieu, Normalien, Stage, StageMatiere
|
||||
from avisstage.models import *
|
||||
|
||||
|
||||
class NormalienInline(admin.StackedInline):
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
from tastypie import fields
|
||||
from tastypie import fields, utils
|
||||
from tastypie.authentication import SessionAuthentication
|
||||
from tastypie.resources import ModelResource
|
||||
|
||||
from django.contrib.gis import geos
|
||||
from django.urls import reverse
|
||||
|
||||
from .models import Lieu, Normalien, Stage
|
||||
from .models import Lieu, Normalien, Stage, StageMatiere
|
||||
from .utils import approximate_distance
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from django_elasticsearch_dsl import Document, Index, fields
|
||||
from elasticsearch_dsl import analyzer, token_filter
|
||||
from django_elasticsearch_dsl import DocType, Index, fields
|
||||
from elasticsearch_dsl import analyzer, token_filter, tokenizer
|
||||
|
||||
from .models import Stage
|
||||
from .models import AvisLieu, AvisStage, Stage
|
||||
from .statics import PAYS_OPTIONS
|
||||
|
||||
PAYS_DICT = dict(PAYS_OPTIONS)
|
||||
|
@ -14,6 +14,7 @@ text_analyzer = analyzer(
|
|||
tokenizer="standard",
|
||||
filter=[
|
||||
"lowercase",
|
||||
"standard",
|
||||
"asciifolding",
|
||||
token_filter("frstop", type="stop", stopwords="_french_"),
|
||||
token_filter("frsnow", type="snowball", language="French"),
|
||||
|
@ -23,23 +24,23 @@ stage.analyzer(text_analyzer)
|
|||
|
||||
|
||||
@stage.doc_type
|
||||
class StageDocument(Document):
|
||||
class StageDocument(DocType):
|
||||
lieux = fields.ObjectField(
|
||||
properties={
|
||||
"nom": fields.TextField(),
|
||||
"ville": fields.TextField(),
|
||||
"pays": fields.TextField(),
|
||||
"nom": fields.StringField(),
|
||||
"ville": fields.StringField(),
|
||||
"pays": fields.StringField(),
|
||||
}
|
||||
)
|
||||
auteur = fields.ObjectField(
|
||||
properties={
|
||||
"nom": fields.TextField(),
|
||||
"nom": fields.StringField(),
|
||||
}
|
||||
)
|
||||
thematiques = fields.TextField()
|
||||
matieres = fields.TextField()
|
||||
thematiques = fields.StringField()
|
||||
matieres = fields.StringField()
|
||||
|
||||
class Django:
|
||||
class Meta:
|
||||
model = Stage
|
||||
fields = [
|
||||
"sujet",
|
||||
|
|
|
@ -7,7 +7,7 @@ from django import forms
|
|||
from django.contrib.auth.forms import PasswordResetForm
|
||||
from django.utils import timezone
|
||||
|
||||
from .models import AvisLieu, AvisStage, Lieu, Stage, User
|
||||
from .models import AvisLieu, AvisStage, Lieu, Normalien, Stage, User
|
||||
from .widgets import LatLonField
|
||||
|
||||
|
||||
|
@ -59,10 +59,8 @@ class StageForm(forms.ModelForm):
|
|||
"encadrants",
|
||||
]
|
||||
help_texts = {
|
||||
"thematiques": "Mettez une virgule pour valider votre thématique si la suggestion ne "
|
||||
"correspond pas ou si elle n'existe pas encore",
|
||||
"structure": "Nom de l'équipe, du laboratoire, de la startup... (si le lieu ne suffit "
|
||||
"pas)",
|
||||
"thematiques": "Mettez une virgule pour valider votre thématique si la suggestion ne correspond pas ou si elle n'existe pas encore",
|
||||
"structure": "Nom de l'équipe, du laboratoire, de la startup... (si le lieu ne suffit pas)",
|
||||
}
|
||||
labels = {
|
||||
"date_debut": "Date de début",
|
||||
|
@ -102,30 +100,11 @@ class AvisStageForm(HTMLTrimmerForm):
|
|||
"les_moins",
|
||||
]
|
||||
help_texts = {
|
||||
"chapo": (
|
||||
'"Trop long, pas lu" : une accroche résumant ce que vous avez pensé de ce séjour'
|
||||
),
|
||||
"avis_ambiance": (
|
||||
"Avez-vous passé un bon moment à ce travail ? Étiez-vous assez guidé·e ? "
|
||||
"Aviez-vous un bon contact avec vos encadrant·e·s ? Y avait-il une bonne "
|
||||
"ambiance dans l'équipe ?"
|
||||
),
|
||||
"avis_sujet": (
|
||||
"Quelle était votre mission ? Qu'en avez-vous retiré ? Le travail "
|
||||
"correspondait-il à vos attentes ? Était-ce à votre niveau, trop dur, "
|
||||
"trop facile ?"
|
||||
),
|
||||
"avis_admin": (
|
||||
"Avez-vous commencé votre travail à la date prévue ? Était-ce compliqué "
|
||||
"d'obtenir les documents nécessaires (visa, contrats, etc) ? L'administration "
|
||||
"de l'établissement vous a-t-elle aidé·e ? Étiez-vous rémunéré·e ?"
|
||||
),
|
||||
"avis_prestage": (
|
||||
"Comment avez-vous trouvé où aller pour cette expérience ? À quel moment "
|
||||
"avez-vous commencé à chercher ? Avez-vous eu des entretiens pour obtenir "
|
||||
"votre place ? Avez-vous eu d'autres pistes, pourquoi avez-vous choisi "
|
||||
"cette option ?"
|
||||
),
|
||||
"chapo": '"Trop long, pas lu" : une accroche résumant ce que vous avez pensé de ce séjour',
|
||||
"avis_ambiance": "Avez-vous passé un bon moment à ce travail ? Étiez-vous assez guidé⋅e ? Aviez-vous un bon contact avec vos encadrant⋅e⋅s ? Y avait-il une bonne ambiance dans l'équipe ?",
|
||||
"avis_sujet": "Quelle était votre mission ? Qu'en avez-vous retiré ? Le travail correspondait-il à vos attentes ? Était-ce à votre niveau, trop dur, trop facile ?",
|
||||
"avis_admin": "Avez-vous commencé votre travail à la date prévue ? Était-ce compliqué d'obtenir les documents nécessaires (visa, contrats, etc) ? L'administration de l'établissement vous a-t-elle aidé⋅e ? Étiez-vous rémunéré⋅e ?",
|
||||
"avis_prestage": "Comment avez-vous trouvé où aller pour cette expérience ? À quel moment avez-vous commencé à chercher ? Avez-vous eu des entretiens pour obtenir votre place ? Avez-vous eu d'autres pistes, pourquoi avez-vous choisi cette option ?",
|
||||
"les_plus": "Les principaux points positifs de cette expérience",
|
||||
"les_moins": "Ce qui aurait pu être mieux",
|
||||
}
|
||||
|
@ -144,21 +123,10 @@ class AvisLieuForm(HTMLTrimmerForm):
|
|||
"les_moins",
|
||||
]
|
||||
help_texts = {
|
||||
"chapo": (
|
||||
'"Trop long, pas lu" : une accroche résumant ce que vous avez pensé de cet endroit'
|
||||
),
|
||||
"avis_lieustage": (
|
||||
"Qu'avez-vous pensé des lieux où vous travailliez ? Les bâtiments "
|
||||
"étaient-ils modernes ? Était-il agréable d'y travailler ?"
|
||||
),
|
||||
"avis_pratique": (
|
||||
"Avez-vous eu du mal à trouver un logement ? Y-a-t-il des choses que vous avez "
|
||||
"apprises sur place qu'il vous aurait été utile de savoir avant de partir ?"
|
||||
),
|
||||
"avis_tourisme": (
|
||||
"Y-a-t-il des lieux à visiter dans cette zone ? Avez-vous pratiqué "
|
||||
"des activités sportives ? Est-il facile de faire des rencontres ?"
|
||||
),
|
||||
"chapo": '"Trop long, pas lu" : une accroche résumant ce que vous avez pensé de cet endroit',
|
||||
"avis_lieustage": "Qu'avez-vous pensé des lieux où vous travailliez ? Les bâtiments étaient-ils modernes ? Était-il agréable d'y travailler ?",
|
||||
"avis_pratique": "Avez-vous eu du mal à trouver un logement ? Y-a-t-il des choses que vous avez apprises sur place qu'il vous aurait été utile de savoir avant de partir ?",
|
||||
"avis_tourisme": "Y-a-t-il des lieux à visiter dans cette zone ? Avez-vous pratiqué des activités sportives ? Est-il facile de faire des rencontres ?",
|
||||
"les_plus": "Les meilleures raisons de partir à cet endroit",
|
||||
"les_moins": "Ce qui vous a gêné ou manqué là-bas",
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from django.core.management.base import BaseCommand
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.db.models import Count
|
||||
|
||||
from avisstage.models import Lieu
|
||||
from avisstage.models import Lieu, Stage
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from django.core.management.base import BaseCommand
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.db.models import Count
|
||||
|
||||
from avisstage.models import Stage
|
||||
from avisstage.models import Lieu, Stage
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from django.core.management.base import BaseCommand
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.db.models import Count
|
||||
|
||||
from avisstage.models import Lieu
|
||||
from avisstage.models import Lieu, Stage
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from datetime import timedelta
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.utils import timezone
|
||||
|
||||
from avisstage.models import Normalien
|
||||
|
@ -13,6 +13,6 @@ class Command(BaseCommand):
|
|||
return
|
||||
|
||||
def handle(self, *args, **options):
|
||||
t = timezone.now() - timedelta(days=365)
|
||||
old_conn = timezone.now() - timedelta(days=365)
|
||||
Normalien.objects.all().update(last_cas_connect=t)
|
||||
self.stdout.write(self.style.SUCCESS("Terminé"))
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11 on 2017-06-20 17:45
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import taggit_autosuggest.managers
|
||||
import tinymce.models
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.2 on 2017-10-02 20:43
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import tinymce.models
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from datetime import timedelta
|
||||
|
||||
from authens.models import CASAccount
|
||||
from authens.signals import post_cas_connect
|
||||
from taggit_autosuggest.managers import TaggableManager
|
||||
from tinymce.models import HTMLField as RichTextField
|
||||
|
@ -8,9 +9,12 @@ from django.contrib.auth.models import User
|
|||
from django.contrib.gis.db import models as geomodels
|
||||
from django.db import models
|
||||
from django.db.models.signals import post_save
|
||||
from django.forms.widgets import DateInput
|
||||
from django.template.defaultfilters import slugify
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.html import strip_tags
|
||||
|
||||
from .statics import (
|
||||
DEPARTEMENTS_DEFAUT,
|
||||
|
@ -22,7 +26,7 @@ from .statics import (
|
|||
TYPE_STAGE_DICT,
|
||||
TYPE_STAGE_OPTIONS,
|
||||
)
|
||||
from .utils import choices_length
|
||||
from .utils import choices_length, is_email_ens
|
||||
|
||||
|
||||
def _default_cas_login():
|
||||
|
@ -98,7 +102,6 @@ def create_basic_user_profile(sender, instance, created, **kwargs):
|
|||
|
||||
post_save.connect(create_basic_user_profile, sender=User)
|
||||
|
||||
|
||||
# Hook d'authENS : information du CAS
|
||||
def handle_cas_connection(sender, instance, created, cas_login, attributes, **kwargs):
|
||||
profil, created = Normalien.objects.get_or_create(user=instance)
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# coding: utf-8
|
||||
import re
|
||||
|
||||
from django import template
|
||||
|
|
|
@ -9,11 +9,10 @@ from django.test import TestCase
|
|||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
|
||||
from .models import AvisLieu, Lieu, Stage, StageMatiere, User
|
||||
from .models import AvisLieu, Lieu, Normalien, Stage, StageMatiere, User
|
||||
|
||||
|
||||
class ExperiENSTestCase(TestCase):
|
||||
|
||||
# Dummy database
|
||||
|
||||
def setUp(self):
|
||||
|
|
|
@ -2,7 +2,7 @@ from tastypie.api import Api
|
|||
|
||||
from django.urls import include, path
|
||||
|
||||
from . import api, views, views_search
|
||||
from . import api, views
|
||||
|
||||
v1_api = Api(api_name="v1")
|
||||
v1_api.register(api.LieuResource())
|
||||
|
@ -56,13 +56,9 @@ urlpatterns = [
|
|||
views.DefinirMotDePasse.as_view(),
|
||||
name="mdp_edit",
|
||||
),
|
||||
path("recherche/", views_search.recherche, name="recherche"),
|
||||
path(
|
||||
"recherche/resultats/",
|
||||
views_search.recherche_resultats,
|
||||
name="recherche_resultats",
|
||||
),
|
||||
path("recherche/items/", views_search.stage_items, name="stage_items"),
|
||||
path("recherche/", views.recherche, name="recherche"),
|
||||
path("recherche/resultats/", views.recherche_resultats, name="recherche_resultats"),
|
||||
path("recherche/items/", views.stage_items, name="stage_items"),
|
||||
path("feedback/", views.feedback, name="feedback"),
|
||||
path("moderation/", views.statistiques, name="moderation"),
|
||||
path("api/", include(v1_api.urls)),
|
||||
|
|
|
@ -10,6 +10,7 @@ from django.conf import settings
|
|||
from django.contrib import messages
|
||||
from django.contrib.admin.views.decorators import staff_member_required
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.tokens import default_token_generator
|
||||
from django.contrib.auth.views import PasswordResetConfirmView
|
||||
from django.core.mail import send_mail
|
||||
from django.db.models import Count, Q
|
||||
|
@ -21,6 +22,8 @@ from django.views.generic import (
|
|||
DeleteView,
|
||||
DetailView,
|
||||
FormView,
|
||||
ListView,
|
||||
TemplateView,
|
||||
UpdateView,
|
||||
View,
|
||||
)
|
||||
|
@ -37,12 +40,12 @@ from .forms import (
|
|||
)
|
||||
from .models import AvisLieu, AvisStage, Lieu, Normalien, Stage
|
||||
from .utils import en_scolarite
|
||||
from .views_search import *
|
||||
|
||||
#
|
||||
# LECTURE
|
||||
#
|
||||
|
||||
|
||||
# Page d'accueil
|
||||
def index(request):
|
||||
num_stages = Stage.objects.filter(public=True).count()
|
||||
|
@ -233,8 +236,7 @@ def save_lieu(request):
|
|||
# On regarde si les stages associés à ce lieu "appartiennent" tous à l'utilisateur
|
||||
not_same_user = lieu.stages.exclude(auteur=normalien).count()
|
||||
|
||||
# Si d'autres personnes ont un stage à cet endroit,
|
||||
# on crée un nouveau lieu, un peu à côté
|
||||
# Si d'autres personnes ont un stage à cet endroit, on crée un nouveau lieu, un peu à côté
|
||||
if not_same_user > 0:
|
||||
lieu = Lieu()
|
||||
# Servira à bouger un peu le lieu
|
||||
|
@ -512,7 +514,7 @@ class ConfirmeAdresse(LoginRequiredMixin, View):
|
|||
email = EmailAddress.objects.confirm(
|
||||
self.kwargs["key"], self.request.user, True
|
||||
)
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
raise Http404()
|
||||
messages.add_message(
|
||||
self.request,
|
||||
|
@ -544,10 +546,9 @@ class EnvoieLienMotDePasse(LoginRequiredMixin, View):
|
|||
messages.add_message(
|
||||
self.request,
|
||||
messages.INFO,
|
||||
(
|
||||
"Un mail a été envoyé à {email}. Merci de vérifier vos indésirables "
|
||||
"si vous ne le recevez pas bientôt"
|
||||
).format(email=self.request.user.email),
|
||||
"Un mail a été envoyé à {email}. Merci de vérifier vos indésirables si vous ne le recevez pas bientôt".format(
|
||||
email=self.request.user.email
|
||||
),
|
||||
)
|
||||
return redirect(reverse("avisstage:parametres"))
|
||||
|
||||
|
|
|
@ -6,10 +6,10 @@ from django import forms
|
|||
from django.conf import settings
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.core.cache import cache
|
||||
from django.core.paginator import InvalidPage, Paginator
|
||||
from django.core.paginator import Paginator
|
||||
from django.db.models import Case, Q, When
|
||||
from django.http import HttpResponseBadRequest, JsonResponse
|
||||
from django.shortcuts import render
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
|
||||
USE_ELASTICSEARCH = getattr(settings, "USE_ELASTICSEARCH", True)
|
||||
|
||||
|
@ -22,13 +22,12 @@ from .statics import NIVEAU_SCOL_OPTIONS, TYPE_LIEU_OPTIONS, TYPE_STAGE_OPTIONS
|
|||
|
||||
logger = logging.getLogger("recherche")
|
||||
|
||||
|
||||
# Recherche
|
||||
class SearchForm(forms.Form):
|
||||
generique = forms.CharField(required=False)
|
||||
sujet = forms.CharField(label="À propos de", required=False)
|
||||
contexte = forms.CharField(
|
||||
label="Contexte (lieu, encadrant·e·s, structure)", required=False
|
||||
label="Contexte (lieu, encadrant⋅e⋅s, structure)", required=False
|
||||
)
|
||||
|
||||
apres_annee = forms.IntegerField(label="Après cette année", required=False)
|
||||
|
@ -80,20 +79,7 @@ def cherche(**kwargs):
|
|||
if field_relevant("generique"):
|
||||
# print("Filtre generique", kwargs['generique'])
|
||||
dsl = dsl.query(
|
||||
"multi_match",
|
||||
query=kwargs["generique"],
|
||||
fuzziness="auto",
|
||||
fields=[
|
||||
"sujet^3",
|
||||
"encadrants",
|
||||
"type_stage",
|
||||
"niveau_scol",
|
||||
"structure",
|
||||
"lieux.*^2",
|
||||
"auteur.nom^2",
|
||||
"thematiques^2",
|
||||
"matieres",
|
||||
],
|
||||
"match", _all={"query": kwargs["generique"], "fuzziness": "auto"}
|
||||
)
|
||||
use_dsl = True
|
||||
|
||||
|
@ -147,11 +133,11 @@ def cherche(**kwargs):
|
|||
|
||||
# Dates
|
||||
if field_relevant("avant_annee", False):
|
||||
dte = date(min(2100, kwargs["avant_annee"]) + 1, 1, 1)
|
||||
dte = date(kwargs["avant_annee"] + 1, 1, 1)
|
||||
filtres &= Q(date_fin__lt=dte)
|
||||
|
||||
if field_relevant("apres_annee", False):
|
||||
dte = date(max(2000, kwargs["apres_annee"]), 1, 1)
|
||||
dte = date(kwargs["apres_annee"], 1, 1)
|
||||
filtres &= Q(date_debut__gte=dte)
|
||||
|
||||
# Type de stage
|
||||
|
@ -165,29 +151,19 @@ def cherche(**kwargs):
|
|||
if field_relevant("type_lieu"):
|
||||
filtres &= Q(lieux__type_lieu=kwargs["type_lieu"])
|
||||
|
||||
# Tri
|
||||
# Application
|
||||
if USE_ELASTICSEARCH and use_dsl:
|
||||
filtres &= Q(id__in=[s.meta.id for s in dsl.scan()])
|
||||
|
||||
# print(filtres)
|
||||
resultat = Stage.objects.filter(filtres)
|
||||
tri = "pertinence"
|
||||
|
||||
if not use_dsl:
|
||||
kwargs["tri"] = "-date_maj"
|
||||
|
||||
if field_relevant("tri") and kwargs["tri"] in ["-date_maj"]:
|
||||
tri = kwargs["tri"]
|
||||
|
||||
if not use_dsl:
|
||||
tri = "-date_maj"
|
||||
|
||||
# Application
|
||||
resultat = Stage.objects.filter(filtres).distinct()
|
||||
|
||||
if USE_ELASTICSEARCH and use_dsl:
|
||||
dsl_res = [s.meta.id for s in dsl.scan()]
|
||||
resultat = resultat.filter(id__in=dsl_res)
|
||||
|
||||
if tri == "pertinence":
|
||||
resultat = resultat.order_by(
|
||||
Case(*[When(pk=pk, then=pos) for pos, pk in enumerate(dsl_res)])
|
||||
)
|
||||
else:
|
||||
resultat = resultat.order_by(tri)
|
||||
else:
|
||||
resultat = resultat.order_by(tri)
|
||||
|
||||
return resultat, tri
|
||||
|
|
94
default.nix
94
default.nix
|
@ -1,94 +0,0 @@
|
|||
{
|
||||
sources ? import ./npins,
|
||||
pkgs ? import sources.nixpkgs { },
|
||||
}:
|
||||
|
||||
let
|
||||
nix-pkgs = import sources.nix-pkgs { inherit pkgs; };
|
||||
|
||||
check = (import sources.git-hooks).run {
|
||||
src = ./.;
|
||||
|
||||
hooks = {
|
||||
# Python hooks
|
||||
black = {
|
||||
enable = true;
|
||||
stages = [ "pre-push" ];
|
||||
};
|
||||
|
||||
isort = {
|
||||
enable = true;
|
||||
stages = [ "pre-push" ];
|
||||
};
|
||||
|
||||
ruff = {
|
||||
enable = true;
|
||||
stages = [ "pre-push" ];
|
||||
};
|
||||
|
||||
# Misc Hooks
|
||||
commitizen.enable = true;
|
||||
};
|
||||
};
|
||||
|
||||
python3 = pkgs.python3.override {
|
||||
packageOverrides = _: _: {
|
||||
inherit (nix-pkgs)
|
||||
authens
|
||||
django-braces
|
||||
django-elasticsearch-dsl
|
||||
django-simple-email-confirmation
|
||||
django-taggit-autosuggest
|
||||
django-tinymce
|
||||
loadcredential
|
||||
spatialite
|
||||
;
|
||||
};
|
||||
};
|
||||
in
|
||||
|
||||
{
|
||||
devShell = pkgs.mkShell {
|
||||
name = "annuaire.dev";
|
||||
|
||||
packages = [
|
||||
(python3.withPackages (ps: [
|
||||
ps.authens
|
||||
ps.django
|
||||
ps.django-braces
|
||||
ps.django-elasticsearch-dsl
|
||||
ps.django-simple-email-confirmation
|
||||
ps.django-taggit
|
||||
ps.django-taggit-autosuggest
|
||||
ps.django-tastypie
|
||||
ps.django-tinymce
|
||||
ps.loadcredential
|
||||
|
||||
# Dev packages
|
||||
ps.django-debug-toolbar
|
||||
ps.django-stubs
|
||||
ps.spatialite
|
||||
]))
|
||||
];
|
||||
|
||||
env = {
|
||||
DJANGO_SETTINGS_MODULE = "app.settings";
|
||||
|
||||
CREDENTIALS_DIRECTORY = builtins.toString ./.credentials;
|
||||
|
||||
EXPERIENS_DEBUG = builtins.toJSON true;
|
||||
EXPERIENS_STATIC_ROOT = builtins.toString ./.static;
|
||||
|
||||
EXPERIENS_GDAL_LIBRARY_PATH = "${pkgs.gdal}/lib/libgdal.so";
|
||||
EXPERIENS_GEOS_LIBRARY_PATH = "${pkgs.geos}/lib/libgeos_c.so";
|
||||
};
|
||||
|
||||
shellHook = ''
|
||||
${check.shellHook}
|
||||
|
||||
if [ ! -d .static ]; then
|
||||
mkdir .static
|
||||
fi
|
||||
'';
|
||||
};
|
||||
}
|
143
experiENS/settings_base.py
Normal file
143
experiENS/settings_base.py
Normal file
|
@ -0,0 +1,143 @@
|
|||
"""
|
||||
Django settings for experiENS project.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/1.7/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/1.7/ref/settings/
|
||||
"""
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
import os
|
||||
|
||||
from django.urls import reverse_lazy
|
||||
|
||||
from .secrets import GOOGLE_API_KEY, MAPBOX_API_KEY, SECRET_KEY
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/
|
||||
|
||||
ALLOWED_HOSTS = []
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
"django.contrib.admin",
|
||||
"django.contrib.auth",
|
||||
"django.contrib.contenttypes",
|
||||
"django.contrib.sessions",
|
||||
"django.contrib.messages",
|
||||
"django.contrib.staticfiles",
|
||||
"django.contrib.gis",
|
||||
"django.contrib.sites",
|
||||
"django_elasticsearch_dsl",
|
||||
#'allauth', # Uncomment that part when you
|
||||
#'allauth.account', # apply migration
|
||||
#'allauth.socialaccount', # Allauth -> AuthENS
|
||||
"simple_email_confirmation",
|
||||
"authens",
|
||||
"tastypie",
|
||||
"braces",
|
||||
"tinymce",
|
||||
"taggit",
|
||||
"taggit_autosuggest",
|
||||
"avisstage",
|
||||
]
|
||||
|
||||
MIDDLEWARE = (
|
||||
"django.middleware.security.SecurityMiddleware",
|
||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
"django.middleware.csrf.CsrfViewMiddleware",
|
||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||
"django.contrib.messages.middleware.MessageMiddleware",
|
||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||
)
|
||||
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||
"DIRS": [
|
||||
# insert your TEMPLATE_DIRS here
|
||||
],
|
||||
"APP_DIRS": True,
|
||||
"OPTIONS": {
|
||||
"context_processors": [
|
||||
"django.contrib.auth.context_processors.auth",
|
||||
"django.template.context_processors.debug",
|
||||
"django.template.context_processors.i18n",
|
||||
"django.template.context_processors.media",
|
||||
"django.template.context_processors.static",
|
||||
"django.template.context_processors.tz",
|
||||
"django.template.context_processors.request",
|
||||
"django.contrib.messages.context_processors.messages",
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
ROOT_URLCONF = "experiENS.urls"
|
||||
|
||||
WSGI_APPLICATION = "experiENS.wsgi.application"
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/1.7/ref/settings/#databases
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/1.7/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = "fr"
|
||||
|
||||
TIME_ZONE = "Europe/Paris"
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
SITE_ID = 1
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/1.7/howto/static-files/
|
||||
|
||||
STATIC_URL = "/static/"
|
||||
|
||||
AUTHENTICATION_BACKENDS = (
|
||||
"django.contrib.auth.backends.ModelBackend",
|
||||
"experiENS.auth.ENSCASBackend",
|
||||
)
|
||||
|
||||
CAS_SERVER_URL = "https://cas.eleves.ens.fr/" # SPI CAS
|
||||
|
||||
AUTHENS_USE_OLDCAS = False
|
||||
|
||||
LOGIN_URL = reverse_lazy("authens:login")
|
||||
LOGOUT_URL = reverse_lazy("authens:logout")
|
||||
LOGIN_REDIRECT_URL = reverse_lazy("avisstage:perso")
|
||||
LOGOUT_REDIRECT_URL = reverse_lazy("avisstage:index")
|
||||
|
||||
LOGGING = {
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
"handlers": {
|
||||
"file": {
|
||||
"level": "INFO",
|
||||
"class": "logging.FileHandler",
|
||||
"filename": os.path.join(BASE_DIR, "recherche.log"),
|
||||
},
|
||||
},
|
||||
"loggers": {
|
||||
"recherche": {
|
||||
"handlers": ["file"],
|
||||
"level": "INFO",
|
||||
"propagate": True,
|
||||
},
|
||||
},
|
||||
}
|
42
experiENS/settings_dev.py
Normal file
42
experiENS/settings_dev.py
Normal file
|
@ -0,0 +1,42 @@
|
|||
from .settings_base import *
|
||||
|
||||
DEBUG = True
|
||||
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django.contrib.gis.db.backends.spatialite",
|
||||
"NAME": os.path.join(BASE_DIR, "db.sqlite3"),
|
||||
}
|
||||
}
|
||||
|
||||
USE_DEBUG_TOOLBAR = False
|
||||
|
||||
if USE_DEBUG_TOOLBAR:
|
||||
INSTALLED_APPS += [
|
||||
"debug_toolbar",
|
||||
]
|
||||
|
||||
MIDDLEWARE = ("debug_toolbar.middleware.DebugToolbarMiddleware",) + MIDDLEWARE
|
||||
|
||||
INTERNAL_IPS = ["127.0.0.1"]
|
||||
|
||||
SPATIALITE_LIBRARY_PATH = "mod_spatialite"
|
||||
|
||||
STATIC_ROOT = "/home/evarin/Bureau/experiENS/static/"
|
||||
|
||||
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
||||
|
||||
STATIC_URL = "/experiens/static/"
|
||||
|
||||
ELASTICSEARCH_DSL = {
|
||||
"default": {"hosts": "localhost:9200"},
|
||||
}
|
||||
|
||||
|
||||
CLIPPER_LDAP_SERVER = "ldaps://localhost:636"
|
||||
|
||||
# Changer à True pour développer avec ES
|
||||
USE_ELASTICSEARCH = False
|
||||
|
||||
if not USE_ELASTICSEARCH:
|
||||
INSTALLED_APPS.remove("django_elasticsearch_dsl")
|
52
experiENS/settings_prod.py
Normal file
52
experiENS/settings_prod.py
Normal file
|
@ -0,0 +1,52 @@
|
|||
import os
|
||||
import sys
|
||||
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
|
||||
from .settings_base import *
|
||||
|
||||
PROJECT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
BASE_DIR = os.path.dirname(PROJECT_DIR)
|
||||
|
||||
DEBUG = False
|
||||
|
||||
ALLOWED_HOSTS = ["www.eleves.ens.fr"]
|
||||
|
||||
ADMINS = (("Robin Champenois", "champeno@clipper.ens.fr"),)
|
||||
|
||||
ADMIN_LOGINS = [
|
||||
"champeno",
|
||||
]
|
||||
|
||||
SERVER_EMAIL = "experiens@www.eleves.ens.fr"
|
||||
|
||||
ROOT_URL = "/experiens/"
|
||||
|
||||
WSGI_APPLICATION = "experiENS.wsgi.application"
|
||||
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django.contrib.gis.db.backends.postgis",
|
||||
"NAME": "experiens",
|
||||
"USER": "experiens",
|
||||
"PASSWORD": "",
|
||||
"HOST": "",
|
||||
"PORT": "5432",
|
||||
}
|
||||
}
|
||||
|
||||
STATIC_URL = ROOT_URL + "static/"
|
||||
MEDIA_URL = ROOT_URL + "media/"
|
||||
|
||||
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
|
||||
|
||||
EMAIL_HOST = "nef.ens.fr"
|
||||
|
||||
|
||||
ELASTICSEARCH_DSL = {
|
||||
"default": {"hosts": "127.0.0.1:9200"},
|
||||
}
|
||||
|
||||
|
||||
CLIPPER_LDAP_SERVER = "ldaps://ldap.spi.ens.fr:636"
|
||||
DEFAULT_FROM_EMAIL = "experiens-no-reply@www.eleves.ens.fr"
|
|
@ -9,8 +9,8 @@ https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/
|
|||
|
||||
import os
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "experiENS.settings")
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.settings")
|
||||
|
||||
application = get_wsgi_application()
|
0
manage.py
Executable file → Normal file
0
manage.py
Executable file → Normal file
|
@ -1,80 +0,0 @@
|
|||
# Generated by npins. Do not modify; will be overwritten regularly
|
||||
let
|
||||
data = builtins.fromJSON (builtins.readFile ./sources.json);
|
||||
version = data.version;
|
||||
|
||||
mkSource =
|
||||
spec:
|
||||
assert spec ? type;
|
||||
let
|
||||
path =
|
||||
if spec.type == "Git" then
|
||||
mkGitSource spec
|
||||
else if spec.type == "GitRelease" then
|
||||
mkGitSource spec
|
||||
else if spec.type == "PyPi" then
|
||||
mkPyPiSource spec
|
||||
else if spec.type == "Channel" then
|
||||
mkChannelSource spec
|
||||
else
|
||||
builtins.throw "Unknown source type ${spec.type}";
|
||||
in
|
||||
spec // { outPath = path; };
|
||||
|
||||
mkGitSource =
|
||||
{
|
||||
repository,
|
||||
revision,
|
||||
url ? null,
|
||||
hash,
|
||||
branch ? null,
|
||||
...
|
||||
}:
|
||||
assert repository ? type;
|
||||
# At the moment, either it is a plain git repository (which has an url), or it is a GitHub/GitLab repository
|
||||
# In the latter case, there we will always be an url to the tarball
|
||||
if url != null then
|
||||
(builtins.fetchTarball {
|
||||
inherit url;
|
||||
sha256 = hash; # FIXME: check nix version & use SRI hashes
|
||||
})
|
||||
else
|
||||
assert repository.type == "Git";
|
||||
let
|
||||
urlToName =
|
||||
url: rev:
|
||||
let
|
||||
matched = builtins.match "^.*/([^/]*)(\\.git)?$" repository.url;
|
||||
|
||||
short = builtins.substring 0 7 rev;
|
||||
|
||||
appendShort = if (builtins.match "[a-f0-9]*" rev) != null then "-${short}" else "";
|
||||
in
|
||||
"${if matched == null then "source" else builtins.head matched}${appendShort}";
|
||||
name = urlToName repository.url revision;
|
||||
in
|
||||
builtins.fetchGit {
|
||||
url = repository.url;
|
||||
rev = revision;
|
||||
inherit name;
|
||||
# hash = hash;
|
||||
};
|
||||
|
||||
mkPyPiSource =
|
||||
{ url, hash, ... }:
|
||||
builtins.fetchurl {
|
||||
inherit url;
|
||||
sha256 = hash;
|
||||
};
|
||||
|
||||
mkChannelSource =
|
||||
{ url, hash, ... }:
|
||||
builtins.fetchTarball {
|
||||
inherit url;
|
||||
sha256 = hash;
|
||||
};
|
||||
in
|
||||
if version == 3 then
|
||||
builtins.mapAttrs (_: mkSource) data.pins
|
||||
else
|
||||
throw "Unsupported format version ${toString version} in sources.json. Try running `npins upgrade`"
|
|
@ -1,34 +0,0 @@
|
|||
{
|
||||
"pins": {
|
||||
"git-hooks": {
|
||||
"type": "Git",
|
||||
"repository": {
|
||||
"type": "GitHub",
|
||||
"owner": "cachix",
|
||||
"repo": "git-hooks.nix"
|
||||
},
|
||||
"branch": "master",
|
||||
"revision": "3c3e88f0f544d6bb54329832616af7eb971b6be6",
|
||||
"url": "https://github.com/cachix/git-hooks.nix/archive/3c3e88f0f544d6bb54329832616af7eb971b6be6.tar.gz",
|
||||
"hash": "04pwjz423iq2nkazkys905gvsm5j39722ngavrnx42b8msr5k555"
|
||||
},
|
||||
"nix-pkgs": {
|
||||
"type": "Git",
|
||||
"repository": {
|
||||
"type": "Git",
|
||||
"url": "https://git.hubrecht.ovh/hubrecht/nix-pkgs"
|
||||
},
|
||||
"branch": "main",
|
||||
"revision": "024f0d09d4ff1a62e11f5fdd74f2d00d0a77da5c",
|
||||
"url": null,
|
||||
"hash": "0abpyf4pclslg24wmwl3q6y8x5fmhq9winpgkpbb99yw2815j2iz"
|
||||
},
|
||||
"nixpkgs": {
|
||||
"type": "Channel",
|
||||
"name": "nixpkgs-unstable",
|
||||
"url": "https://releases.nixos.org/nixpkgs/nixpkgs-24.11pre694416.ccc0c2126893/nixexprs.tar.xz",
|
||||
"hash": "0cn1z4wzps8nfqxzr6l5mbn81adcqy2cy2ic70z13fhzicmxfsbx"
|
||||
}
|
||||
},
|
||||
"version": 3
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
[flake8]
|
||||
max-line-length = 99
|
||||
exclude = .git, *.pyc, __pycache__, migrations
|
||||
extend-ignore = E231, E203, E402
|
||||
extend-ignore = E231, E203
|
||||
|
||||
[isort]
|
||||
profile = black
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
(import ./. { }).devShell
|
Loading…
Add table
Reference in a new issue