Utilise nouvelle API. Presentation index. Logo.
This commit is contained in:
parent
4f55017b6f
commit
694c21a254
@ -4,7 +4,6 @@ import time
|
||||
from flask import current_app, g, render_template, request
|
||||
from flask import Flask
|
||||
|
||||
from scodoc.api import APIError, ScoDocAuthError
|
||||
from config import DevConfig
|
||||
|
||||
|
||||
@ -48,6 +47,8 @@ def handle_sco_auth_error(exc):
|
||||
|
||||
|
||||
def create_app(config_class=DevConfig):
|
||||
from scodoc.api import APIError, ScoDocAuthError
|
||||
|
||||
app = Flask(__name__, static_url_path="/AutoSco/static", static_folder="static")
|
||||
app.config.from_object(config_class)
|
||||
app.wsgi_app = ReverseProxied(app.wsgi_app)
|
||||
|
BIN
app/static/logo.png
Normal file
BIN
app/static/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 43 KiB |
@ -13,9 +13,27 @@
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 0;
|
||||
font-size: 14pt;
|
||||
margin: 8px;
|
||||
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>
|
||||
{%- endblock styles %}
|
||||
|
||||
@ -23,6 +41,11 @@
|
||||
</head>
|
||||
<body{% block body_attribs %}{% endblock body_attribs %}>
|
||||
{% 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 %}
|
||||
{%- endblock navbar %}
|
||||
{% block content -%}
|
||||
|
@ -5,13 +5,6 @@
|
||||
{{super()}}
|
||||
|
||||
<style>
|
||||
.centered-description {
|
||||
display: grid;
|
||||
justify-content: center;
|
||||
grid-template-columns: 1fr;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div.titre {
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
|
@ -1,16 +1,64 @@
|
||||
{# Page accueil #}
|
||||
{% 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 %}
|
||||
|
||||
<h1>AutoSco - Accueil</h1>
|
||||
|
||||
<div class="titre1">Cours ouverts</div>
|
||||
<div>
|
||||
{% for sem in sems %}
|
||||
<div class="sem">
|
||||
{{sem.date_debut}} : <a href="{{
|
||||
<div class="sem {% if sem.autosco.inscription_autorisee %}ouvert{% else %}ferme{% endif %}">
|
||||
<a href="{{
|
||||
url_for('autosco.formsemestre_description', formsemestre_id=sem.formsemestre_id )
|
||||
}}">{{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>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
@ -11,17 +11,18 @@ from scodoc import api
|
||||
@bp.route("/")
|
||||
def index():
|
||||
annee_scolaire = scu.annee_scolaire()
|
||||
sems = api.get(f"/formsemestres/query?annee_scolaire={annee_scolaire}")
|
||||
# nb: l'utilisaton de l'API départementale permet de n'avoir
|
||||
sems = api.get(f"/formsemestres/with_description/query?annee_scolaire={annee_scolaire}")
|
||||
# nb: l'utilisation de l'API départementale permet de n'avoir
|
||||
# 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)
|
||||
|
||||
@bp.route("/formdescription/<int:formsemestre_id>")
|
||||
def formsemestre_description(formsemestre_id:int):
|
||||
"""Page description d'un formsemestre (=d'un cours)"""
|
||||
sem = api.get(f"/formsemestre/{formsemestre_id}")
|
||||
sem["descr"] = api.get(f"/formsemestre/{formsemestre_id}/description")
|
||||
sem = api.get(f"/formsemestre/{formsemestre_id}/with_description")
|
||||
return render_template("formsemestre_description.j2", sem=sem)
|
||||
|
||||
@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.headers["Content-Type"] = content_type
|
||||
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
|
11
autosco.py
11
autosco.py
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
"""Application Flask: AutoSco"""
|
||||
|
||||
import os
|
||||
import datetime
|
||||
from pprint import pprint as pp
|
||||
|
||||
import click
|
||||
@ -44,6 +44,15 @@ def make_shell_context():
|
||||
"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:
|
||||
# flask run -p 5001 --host 0.0.0.0 --debug
|
||||
|
||||
|
@ -3,7 +3,10 @@
|
||||
|
||||
import os
|
||||
import requests
|
||||
|
||||
from flask import current_app
|
||||
|
||||
from app import log
|
||||
import config
|
||||
|
||||
|
||||
@ -22,12 +25,17 @@ class ScoDocAuthError(APIError):
|
||||
|
||||
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"
|
||||
ans = requests.post(
|
||||
conf["API_URL"] + "/tokens",
|
||||
auth=(user, password),
|
||||
timeout=conf["API_TIMEOUT"],
|
||||
)
|
||||
try:
|
||||
ans = requests.post(
|
||||
conf["API_URL"] + "/tokens",
|
||||
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:
|
||||
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)
|
||||
token = ans.json()["token"]
|
||||
return {"Authorization": f"Bearer {token}"}
|
||||
|
Loading…
x
Reference in New Issue
Block a user