Aller au contenu

EPIDOCS API — Erreurs courantes

Erreurs d'authentification

Symptôme : L'API retourne 401 Unauthorized alors que l'utilisateur vient de se connecter.

Cause : Le cookie auth_token n'est pas envoyé par le navigateur (problème CORS / SameSite), ou la session a expiré.

Solution :

# Vérifier les sessions actives dans la base
docker compose exec web python manage.py shell -c "
from apps.user.models import UserSession
sessions = UserSession.objects.filter(is_valid=True)
for s in sessions:
    print(f'{s.user or s.student} - expires: {s.expires_at} - valid: {s.is_valid}')
"
  • En production : vérifier que JWT_COOKIE_DOMAIN est bien défini (ex: .epitools.bj)
  • En dev : vérifier que le frontend envoie credentials: 'include' dans les requêtes fetch

Azure AD callback échoue

Symptôme : Après la connexion Microsoft, le callback retourne une erreur ou redirige en boucle.

Cause : CALLBACK_URL ne correspond pas à l'URL enregistrée dans l'App Registration Azure.

Solution :

  1. Vérifier la variable CALLBACK_URL dans le .env
  2. Vérifier que cette URL est enregistrée dans Azure Portal → App Registrations → Redirect URIs
  3. S'assurer que le tenant ID est correct (AZURE_TENANT_ID)

Erreurs de génération de documents

La version EN n'est pas générée pour un document existant

Symptôme : L'étudiant clique "générer" après l'ajout du support multilingue, le document s'affiche comme "terminé" mais X-Has-En retourne false — seule la version FR est disponible.

Cause : Le document avait déjà été généré avant l'ajout du modele_en sur le DocumentType. L'entrée GenDocumentHistory existe avec remote_url_en = NULL. L'API détecte le document existant et le retourne sans vérifier si un template EN est maintenant disponible.

Solution : Depuis la version 621602b, ce cas est géré automatiquement. Lors d'une nouvelle demande de génération, si modele_en est disponible mais remote_url_en est NULL, la version EN est générée et sauvegardée sans toucher au document FR ni au tracking code. Il suffit que l'étudiant reclique "générer".

Pour forcer la mise à jour manuellement :

docker compose exec web python manage.py shell -c "
from apps.document_type.models import GenDocumentHistory, DocumentType
from apps.document_type.utils import generate_en_for_existing

# Trouver les documents sans EN pour un doc_id donné
doc_id = 'certificat_scolarite'
doc = DocumentType.objects.get(doc_id=doc_id)
if not doc.modele_en:
    print('Pas de template EN configuré pour ce document')
else:
    histories = GenDocumentHistory.objects.filter(doc_id=doc_id, remote_url_en__isnull=True)
    print(f'{histories.count()} documents à mettre à jour')
    for h in histories:
        ok = generate_en_for_existing(h, doc.modele_en.path)
        print(f'{h.tracking_code_id}: {\"OK\" if ok else \"ERREUR\"}')
"

X-Has-En: false alors que le template EN est configuré

Symptôme : Le frontend n'affiche pas le bouton de téléchargement EN malgré un modele_en uploadé sur le DocumentType.

Causes possibles :

  1. Le document a été généré avant l'upload du template EN (voir cas ci-dessus)
  2. Le campus de l'étudiant a un CampusDocumentType sans modele_en
  3. La génération EN a échoué silencieusement (voir logs)

Solution :

# Vérifier les logs de génération EN
docker compose logs web --tail 200 | grep -i "EN PDF\|generating EN\|EN version"

# Vérifier le campus override
docker compose exec web python manage.py shell -c "
from apps.campus.models import CampusDocumentType
from apps.student.models import Student
email = 'etudiant@epitech.bj'
s = Student.objects.get(login=email)
if s.campus:
    override = CampusDocumentType.objects.filter(campus=s.campus, document_type__doc_id='certificat_scolarite').first()
    if override:
        print(f'Campus override: modele_en={override.modele_en}')
    else:
        print('Pas de campus override — template global utilisé')
"

Erreur lors de la génération du document (500)

Symptôme : L'API retourne une erreur 500 lors de la génération.

Causes possibles :

  1. Template manquant : le fichier .docx n'existe pas dans media/modeles/
  2. LibreOffice crash : la conversion DOCX → PDF échoue
  3. Attribut manquant : le template contient un placeholder {{attribut}} que le code ne connaît pas

Solution :

# Vérifier que le template existe
docker compose exec web ls -la /epidocs/media/modeles/

# Vérifier les logs de génération
docker compose logs web --tail 100 | grep -i "erreur\|error\|generation"

# Vérifier que LibreOffice fonctionne
docker compose exec web libreoffice --version

Impossible de trouver la valeur de l'attribut xxx

Symptôme : Erreur lors de la génération, un attribut du template Word n'est pas reconnu.

Cause : Le fichier .docx contient un placeholder {{xxx}} qui n'est pas défini dans prepare_attributes() ni dans les champs du modèle Student.

Solution :

  1. Ouvrir le fichier .docx et vérifier les placeholders
  2. Vérifier que l'attribut existe dans apps/document_type/utils.pyprepare_attributes()
  3. Si c'est un champ étudiant, vérifier qu'il existe dans le modèle Student

'User' object has no attribute 'section'

Symptôme : Un admin appelle /documents/available-document-types sans query param.

Cause : L'admin (modèle User) n'a pas d'attribut section, contrairement aux étudiants.

Solution : L'admin doit passer ?studentEmail=xxx ou ?classe=PGE1 en paramètre.


Erreurs de base de données

OperationalError: could not connect to server

Symptôme : L'API ne démarre pas, erreur de connexion PostgreSQL.

Cause : Le conteneur db n'est pas prêt ou POSTGRES_HOST est mal configuré.

Solution :

# Vérifier que le conteneur db tourne
docker compose ps

# Vérifier la connectivité
docker compose exec web python -c "
import psycopg2
conn = psycopg2.connect(host='db', dbname='epidocs_db', user='postgres', password='CHANGE_ME')
print('OK')
conn.close()
"

# Vérifier les logs du conteneur db
docker compose logs db --tail 20

relation "xxx" does not exist

Symptôme : Erreur au démarrage ou lors d'une requête API.

Cause : Les migrations n'ont pas été appliquées.

Solution :

docker compose exec web python manage.py migrate

Erreurs de mode maintenance

Les étudiants ne peuvent plus accéder après désactivation du mode maintenance

Symptôme : Le mode maintenance est désactivé mais les étudiants reçoivent toujours une erreur 503.

Cause : La fenêtre de maintenance planifiée (scheduled_start / scheduled_end) est toujours active.

Solution :

# Vérifier l'état du système
docker compose exec web python manage.py shell -c "
from apps.user.models import SystemStatus
s = SystemStatus.objects.first()
if s:
    print(f'Maintenance: {s.is_maintenance}')
    print(f'Scheduled: {s.scheduled_start} → {s.scheduled_end}')
"

Mettre à jour via l'API : PUT /admin/system-status avec is_maintenance: false et scheduled_start: null, scheduled_end: null.


Erreurs de fichiers statiques

Assets ReDoc / Swagger / admin Django en 404 (page docs cassée)

Symptôme : la page /integrations/v1/docs (ou /redoc/, ou l'admin Django) s'affiche mais reste blanche/sans style. La console montre :

GET /static/drf-yasg/redoc/redoc.min.js  404 (Not Found)
Refused to apply style from '/static/drf-yasg/style.css' because its MIME type ('text/html')...

Cause : en production DEBUG=False, et Gunicorn ne sert pas les fichiers /static/ par défaut. Si aucun middleware (WhiteNoise) ni Nginx ne pointe vers le dossier staticfiles/, toutes les requêtes /static/... tombent sur Django qui renvoie une 404 HTML — d'où l'erreur de MIME type.

Solution : depuis la version d4f7f89, WhiteNoise est activé dans MIDDLEWARE (juste après SecurityMiddleware) et sert les fichiers collectés par collectstatic (exécuté au démarrage du conteneur). Aucune config Nginx supplémentaire n'est requise.

Vérifier que tout est en place :

# WhiteNoise présent dans le middleware
docker compose exec web python -c "from django.conf import settings; print([m for m in settings.MIDDLEWARE if 'white' in m.lower()])"

# Les fichiers statiques ont bien été collectés
docker compose exec web ls /epidocs/staticfiles/drf-yasg/redoc/

# Re-collecter au besoin
docker compose exec web python manage.py collectstatic --noinput

# Tester le serving (doit renvoyer 200 + content-type text/javascript)
curl -s -o /dev/null -w "%{http_code} %{content_type}\n" \
  https://api.mydocs.epitools.bj/static/drf-yasg/redoc/redoc.min.js

Erreurs de déploiement

Volume PostgreSQL introuvable

Symptôme : docker compose up échoue avec une erreur sur le volume externe.

Cause : Le volume epidocs-api_postgres_data n'existe pas sur le VPS.

Solution :

# Créer le volume
docker volume create epidocs-api_postgres_data

# Vérifier
docker volume inspect epidocs-api_postgres_data

Attention

Ne jamais supprimer ce volume en production ! Il contient toutes les données de la base.


Port 7010 déjà utilisé

Symptôme : docker compose up échoue car le port est déjà occupé.

Solution :

# Trouver le processus qui utilise le port
lsof -i :7010

# Arrêter l'ancien conteneur
docker stop epidocs_api && docker rm epidocs_api