forked from ScoDoc/ScoDoc
Update opolka/ScoDoc from ScoDoc/ScoDoc #2
@ -41,50 +41,58 @@ from app.scodoc.sco_exceptions import ScoValueError
|
||||
import app.scodoc.sco_utils as scu
|
||||
|
||||
|
||||
def formsemestre_load_calendar(
|
||||
formsemestre: FormSemestre,
|
||||
) -> icalendar.cal.Calendar | None:
|
||||
"""Load ics data, return calendar or None if not configured or not available"""
|
||||
edt_id = formsemestre.get_edt_id()
|
||||
if not edt_id:
|
||||
flash(
|
||||
"accès aux emplois du temps non configuré pour ce semestre (pas d'edt_id)"
|
||||
)
|
||||
return None
|
||||
def get_ics_filename(edt_id: str) -> str:
|
||||
"Le chemin vers l'ics de cet edt_id"
|
||||
edt_ics_path = ScoDocSiteConfig.get("edt_ics_path")
|
||||
if not edt_ics_path.strip():
|
||||
return None
|
||||
ics_filename = edt_ics_path.format(edt_id=edt_id)
|
||||
return edt_ics_path.format(edt_id=edt_id)
|
||||
|
||||
|
||||
def formsemestre_load_calendar(
|
||||
formsemestre: FormSemestre = None, edt_id: str = None
|
||||
) -> tuple[bytes, icalendar.cal.Calendar]:
|
||||
"""Load ics data, return raw ics and decoded calendar.
|
||||
Raises ScoValueError if not configured or not available or invalid format.
|
||||
"""
|
||||
if edt_id is None and formsemestre:
|
||||
edt_id = formsemestre.get_edt_id()
|
||||
if not edt_id:
|
||||
raise ScoValueError(
|
||||
"accès aux emplois du temps non configuré pour ce semestre (pas d'edt_id)"
|
||||
)
|
||||
ics_filename = get_ics_filename(edt_id)
|
||||
try:
|
||||
with open(ics_filename, "rb") as file:
|
||||
log(f"Loading edt from {ics_filename}")
|
||||
data = file.read()
|
||||
try:
|
||||
calendar = icalendar.Calendar.from_ical(file.read())
|
||||
calendar = icalendar.Calendar.from_ical(data)
|
||||
except ValueError as exc:
|
||||
log(
|
||||
f"""formsemestre_load_calendar: error importing ics for {
|
||||
formsemestre}\npath='{ics_filename}'"""
|
||||
formsemestre or ''}\npath='{ics_filename}'"""
|
||||
)
|
||||
raise ScoValueError(
|
||||
f"calendrier ics illisible (edt_id={edt_id})"
|
||||
) from exc
|
||||
except FileNotFoundError as exc:
|
||||
log(
|
||||
f"formsemestre_load_calendar: ics not found for {formsemestre}\npath='{ics_filename}'"
|
||||
f"formsemestre_load_calendar: ics not found for {formsemestre or ''}\npath='{ics_filename}'"
|
||||
)
|
||||
raise ScoValueError(
|
||||
f"Fichier ics introuvable (filename={ics_filename})"
|
||||
) from exc
|
||||
except PermissionError as exc:
|
||||
log(
|
||||
f"""formsemestre_load_calendar: permission denied for {formsemestre
|
||||
f"""formsemestre_load_calendar: permission denied for {formsemestre or ''
|
||||
}\npath='{ics_filename}'"""
|
||||
)
|
||||
raise ScoValueError(
|
||||
f"Fichier ics inaccessible: vérifier permissions (filename={ics_filename})"
|
||||
) from exc
|
||||
|
||||
return calendar
|
||||
return data, calendar
|
||||
|
||||
|
||||
# --- Couleurs des évènements emploi du temps
|
||||
@ -178,7 +186,7 @@ def formsemestre_edt_dict(formsemestre: FormSemestre) -> list[dict]:
|
||||
def _load_and_convert_ics(formsemestre: FormSemestre) -> list[dict]:
|
||||
"chargement fichier, filtrage et extraction des identifiants."
|
||||
# Chargement du calendier ics
|
||||
calendar = formsemestre_load_calendar(formsemestre)
|
||||
_, calendar = formsemestre_load_calendar(formsemestre)
|
||||
if not calendar:
|
||||
return []
|
||||
# --- Paramètres d'extraction
|
||||
@ -236,7 +244,8 @@ def _load_and_convert_ics(formsemestre: FormSemestre) -> list[dict]:
|
||||
edt_group = extract_event_data(
|
||||
event, edt_ics_group_field, edt_ics_group_pattern
|
||||
)
|
||||
# si pas de groupe dans l'event, oi si groupe non reconnu, prend toute la promo ("tous")
|
||||
# si pas de groupe dans l'event, ou si groupe non reconnu,
|
||||
# prend toute la promo ("tous")
|
||||
group: GroupDescr = (
|
||||
edt2group.get(edt_group, default_group)
|
||||
if edt_group
|
||||
|
@ -10,9 +10,50 @@ div.config-section {
|
||||
margin-right: -15px;
|
||||
margin-left: -15px;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
#zone-test {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
#raw-ics-sample-zone {
|
||||
display: none;
|
||||
}
|
||||
#raw-ics-sample-zone>div {
|
||||
font-style: italic;
|
||||
}
|
||||
#test_load_ics:disabled {
|
||||
background-color: gray;
|
||||
color: white; /* Optional: change text color if needed */
|
||||
cursor: not-allowed;
|
||||
}
|
||||
</style>
|
||||
{% endblock styles %}
|
||||
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
|
||||
<script>
|
||||
function update_test_button_state() {
|
||||
var inputValue = document.getElementById('test_edt_id').value;
|
||||
document.getElementById('test_load_ics').disabled = inputValue.length === 0;
|
||||
}
|
||||
|
||||
async function load_ics_sample() {
|
||||
var edt_id = document.getElementById('test_edt_id').value;
|
||||
try {
|
||||
const response = await fetch(`${SCO_URL}/../ics_raw_sample/${edt_id}`);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const data = await response.text();
|
||||
document.getElementById('raw-ics-sample').value = data;
|
||||
document.getElementById('raw-ics-sample-zone').style.display = 'block';
|
||||
} catch (error) {
|
||||
console.error('Error fetching data: ', error);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{% endblock scripts %}
|
||||
|
||||
{% block app_content %}
|
||||
<div class="row">
|
||||
@ -46,6 +87,18 @@ affectent notamment les comptages d'absences de tous les bulletins des
|
||||
{{ wtf.form_field(form.edt_ics_path) }}
|
||||
</div>
|
||||
|
||||
<div id="zone-test">
|
||||
Pour essayer, indiquer un <tt>edt_id</tt> :
|
||||
<input type="text" id="test_edt_id" oninput="update_test_button_state()" size="12" />
|
||||
<button id="test_load_ics" type="button" onclick="load_ics_sample()" disabled>
|
||||
Essayer de charger l'ics</button>
|
||||
<div id="raw-ics-sample-zone">
|
||||
<div>Voici un évènement chargé au milieu de ce calendrier:
|
||||
</div>
|
||||
<textarea id="raw-ics-sample" rows="13" cols="90">
|
||||
</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="config-section">Extraction des identifiants depuis les calendriers</div>
|
||||
<div class="help">
|
||||
Indiquer ici comment récupérer les informations (titre, groupe, module)
|
||||
|
@ -81,7 +81,7 @@ from app.models import (
|
||||
from app.models import departements
|
||||
from app.models.config import PersonalizedLink
|
||||
|
||||
|
||||
from app.scodoc import sco_edt_cal
|
||||
from app.scodoc import sco_find_etud
|
||||
from app.scodoc import sco_logos
|
||||
from app.scodoc import sco_utils as scu
|
||||
@ -376,6 +376,24 @@ def config_assiduites():
|
||||
)
|
||||
|
||||
|
||||
@bp.route("/ScoDoc/ics_raw_sample/<string:edt_id>")
|
||||
@admin_required
|
||||
def ics_raw_sample(edt_id: str):
|
||||
"Renvoie un extrait de l'ics brut, pour aider à configurer les extractions"
|
||||
try:
|
||||
raw_ics, _ = sco_edt_cal.formsemestre_load_calendar(edt_id=edt_id)
|
||||
except ScoValueError as exc:
|
||||
return exc.args[0]
|
||||
try:
|
||||
ics = raw_ics.decode(scu.SCO_ENCODING)
|
||||
except SyntaxError:
|
||||
return f"Erreur lors de la conversion vers {scu.SCO_ENCODING}"
|
||||
evs = ics.split("BEGIN:VEVENT")
|
||||
if len(evs) < 1:
|
||||
return "pas d'évènements VEVENT détectés dans ce fichier"
|
||||
return "BEGIN:VEVENT" + evs[len(evs) // 2]
|
||||
|
||||
|
||||
@bp.route("/ScoDoc/config_codes_decisions", methods=["GET", "POST"])
|
||||
@admin_required
|
||||
def config_codes_decisions():
|
||||
|
Loading…
Reference in New Issue
Block a user