Utilise nouvelle API. Presentation index. Logo.

This commit is contained in:
Ilona 2025-01-08 16:45:07 +01:00
parent 4f55017b6f
commit 694c21a254
8 changed files with 111 additions and 23 deletions

View File

@ -4,7 +4,6 @@ import time
from flask import current_app, g, render_template, request from flask import current_app, g, render_template, request
from flask import Flask from flask import Flask
from scodoc.api import APIError, ScoDocAuthError
from config import DevConfig from config import DevConfig
@ -48,6 +47,8 @@ def handle_sco_auth_error(exc):
def create_app(config_class=DevConfig): def create_app(config_class=DevConfig):
from scodoc.api import APIError, ScoDocAuthError
app = Flask(__name__, static_url_path="/AutoSco/static", static_folder="static") app = Flask(__name__, static_url_path="/AutoSco/static", static_folder="static")
app.config.from_object(config_class) app.config.from_object(config_class)
app.wsgi_app = ReverseProxied(app.wsgi_app) app.wsgi_app = ReverseProxied(app.wsgi_app)

BIN
app/static/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@ -13,9 +13,27 @@
<style> <style>
body { body {
font-family: Arial, sans-serif; font-family: Arial, sans-serif;
margin: 0; font-size: 14pt;
margin: 8px;
padding: 0; padding: 0;
} }
header {
display: grid;
justify-content: center;
margin-bottom: 16px;
}
div.titre1 {
font-size: 1.5em;
font-weight: bold;
margin-top: 12px;
}
.centered-description {
display: grid;
justify-content: center;
grid-template-columns: 1fr;
text-align: center;
}
</style> </style>
{%- endblock styles %} {%- endblock styles %}
@ -23,6 +41,11 @@
</head> </head>
<body{% block body_attribs %}{% endblock body_attribs %}> <body{% block body_attribs %}{% endblock body_attribs %}>
{% block body -%} {% block body -%}
{%- block app_header %}
<header>
<a href="/"><img src="/AutoSco/static/logo.png" alt="Espace Langues - USPN" height="80px"/></a>
</header>
{%- endblock app_header %}
{% block navbar %} {% block navbar %}
{%- endblock navbar %} {%- endblock navbar %}
{% block content -%} {% block content -%}

View File

@ -5,13 +5,6 @@
{{super()}} {{super()}}
<style> <style>
.centered-description {
display: grid;
justify-content: center;
grid-template-columns: 1fr;
text-align: center;
}
div.titre { div.titre {
font-size: 1.5em; font-size: 1.5em;
font-weight: bold; font-weight: bold;

View File

@ -1,16 +1,64 @@
{# Page accueil #} {# Page accueil #}
{% extends 'base.j2' %} {% extends 'base.j2' %}
{% block styles %}
{{super()}}
<style>
div.sem {
margin-top: 8px;
margin-bottom: 8px;
border-radius: 8px;
padding: 8px;
background-color: blanchedalmond;
}
div.sem.ouvert {
background-color: lightgreen;
}
.sem a, .sem a:visited {
text-decoration: none;
color: #025AA7;
}
.sem a:hover {
text-decoration: underline;
}
.dates, .date-limite {
color:darkolivegreen;
font-size: 80%;
}
.date-limite {
color: red;
}
</style>
{% endblock %}
{% block content %} {% block content %}
<h1>AutoSco - Accueil</h1> <div class="titre1">Cours ouverts</div>
<div> <div>
{% for sem in sems %} {% for sem in sems %}
<div class="sem"> <div class="sem {% if sem.autosco.inscription_autorisee %}ouvert{% else %}ferme{% endif %}">
{{sem.date_debut}} : <a href="{{ <a href="{{
url_for('autosco.formsemestre_description', formsemestre_id=sem.formsemestre_id ) url_for('autosco.formsemestre_description', formsemestre_id=sem.formsemestre_id )
}}">{{sem.titre}}</a> }}">{{sem.titre}}</a>
<span class="dates">cours du {{sem.date_debut}} au {{sem.date_fin}}</span>
{% if sem.descr.date_fin_inscriptions is not none %}
<span class="date-limite">fermeture des inscriptions le {{sem.descr.date_fin_inscriptions|format_date}}</span>
{% endif %}
{% if sem.autosco.inscription_autorisee %}
<div class="inscription">
{% if sem.autosco.nb_dispo is not none %}
<span>{{ sem.autosco.nb_dispo }} places disponibles :</span>
{% endif %}
<a href="{{url_for('autosco.formsemestre_inscription', formsemestre_id=sem.formsemestre_id )}}">
s'inscrire
</a>
</div>
{% endif %}
</div> </div>
{% endfor %} {% endfor %}
</div> </div>

View File

@ -11,17 +11,18 @@ from scodoc import api
@bp.route("/") @bp.route("/")
def index(): def index():
annee_scolaire = scu.annee_scolaire() annee_scolaire = scu.annee_scolaire()
sems = api.get(f"/formsemestres/query?annee_scolaire={annee_scolaire}") sems = api.get(f"/formsemestres/with_description/query?annee_scolaire={annee_scolaire}")
# nb: l'utilisaton de l'API départementale permet de n'avoir # nb: l'utilisation de l'API départementale permet de n'avoir
# que les semestres du département configuré. # que les semestres du département configuré.
# Ne retient que les semestres ayant une description et étant visibles
sems = [ s for s in sems if s["autosco"] and s["autosco"]["visible"] ]
return render_template("index.j2", sems=sems) return render_template("index.j2", sems=sems)
@bp.route("/formdescription/<int:formsemestre_id>") @bp.route("/formdescription/<int:formsemestre_id>")
def formsemestre_description(formsemestre_id:int): def formsemestre_description(formsemestre_id:int):
"""Page description d'un formsemestre (=d'un cours)""" """Page description d'un formsemestre (=d'un cours)"""
sem = api.get(f"/formsemestre/{formsemestre_id}") sem = api.get(f"/formsemestre/{formsemestre_id}/with_description")
sem["descr"] = api.get(f"/formsemestre/{formsemestre_id}/description")
return render_template("formsemestre_description.j2", sem=sem) return render_template("formsemestre_description.j2", sem=sem)
@bp.route("/formsemestre/<int:formsemestre_id>/description/photo_ens") @bp.route("/formsemestre/<int:formsemestre_id>/description/photo_ens")
@ -38,3 +39,8 @@ def formsemestre_get_photo_ens(formsemestre_id: int):
r = make_response(response.content) r = make_response(response.content)
r.headers["Content-Type"] = content_type r.headers["Content-Type"] = content_type
return r return r
@bp.route("/formsemestre/<int:formsemestre_id>/inscription")
def formsemestre_inscription(formsemestre_id: int):
"""Formulaire d'auto-inscription étudiant"""
return "Formulaire d'auto-inscription étudiant" # TODO

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
"""Application Flask: AutoSco""" """Application Flask: AutoSco"""
import os import datetime
from pprint import pprint as pp from pprint import pprint as pp
import click import click
@ -44,6 +44,15 @@ def make_shell_context():
"pp": pp, "pp": pp,
} }
@app.template_filter()
def format_date(value:str|datetime.datetime):
"""Format a date dd/mm/yyyy"""
if isinstance(value, str):
value = datetime.datetime.fromisoformat(value)
return value.strftime("%d/%m/%Y")
# Start using: # Start using:
# flask run -p 5001 --host 0.0.0.0 --debug # flask run -p 5001 --host 0.0.0.0 --debug

View File

@ -3,7 +3,10 @@
import os import os
import requests import requests
from flask import current_app from flask import current_app
from app import log
import config import config
@ -22,12 +25,17 @@ class ScoDocAuthError(APIError):
def get_auth_headers(user: str, password: str, conf: config.Config) -> dict: def get_auth_headers(user: str, password: str, conf: config.Config) -> dict:
"Demande de jeton, dict à utiliser dans les en-têtes de requêtes http" "Demande de jeton, dict à utiliser dans les en-têtes de requêtes http"
ans = requests.post( try:
conf["API_URL"] + "/tokens", ans = requests.post(
auth=(user, password), conf["API_URL"] + "/tokens",
timeout=conf["API_TIMEOUT"], auth=(user, password),
) timeout=conf["API_TIMEOUT"],
)
except requests.exceptions.ConnectionError as exc:
log(f"get_auth_headers: error: user={user}, url='{conf['API_URL']}/tokens'")
raise ScoDocAuthError(f"Impossible de se connecter à ScoDoc: problème de configuration?", exc)
if ans.status_code != 200: if ans.status_code != 200:
log(f"get_auth_headers: error: user={user}, answer status={ans.status_code}")
raise ScoDocAuthError(f"Echec demande jeton par {user}", status_code=ans.status_code) raise ScoDocAuthError(f"Echec demande jeton par {user}", status_code=ans.status_code)
token = ans.json()["token"] token = ans.json()["token"]
return {"Authorization": f"Bearer {token}"} return {"Authorization": f"Bearer {token}"}