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 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
BIN
app/static/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 43 KiB |
@ -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 -%}
|
||||||
|
@ -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;
|
||||||
|
@ -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>
|
||||||
|
@ -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
|
11
autosco.py
11
autosco.py
@ -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
|
||||||
|
|
||||||
|
@ -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"
|
||||||
|
try:
|
||||||
ans = requests.post(
|
ans = requests.post(
|
||||||
conf["API_URL"] + "/tokens",
|
conf["API_URL"] + "/tokens",
|
||||||
auth=(user, password),
|
auth=(user, password),
|
||||||
timeout=conf["API_TIMEOUT"],
|
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}"}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user