forked from ScoDoc/ScoDoc
Liste des saisies de notes sur le user_board
This commit is contained in:
parent
d7f4209a5a
commit
2642a25cf7
@ -122,6 +122,7 @@ from app.api import (
|
|||||||
justificatifs,
|
justificatifs,
|
||||||
logos,
|
logos,
|
||||||
moduleimpl,
|
moduleimpl,
|
||||||
|
operations,
|
||||||
partitions,
|
partitions,
|
||||||
semset,
|
semset,
|
||||||
users,
|
users,
|
||||||
|
100
app/api/operations.py
Normal file
100
app/api/operations.py
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
##############################################################################
|
||||||
|
# ScoDoc
|
||||||
|
# Copyright (c) 1999 - 2024 Emmanuel Viennet. All rights reserved.
|
||||||
|
# See LICENSE
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
"""
|
||||||
|
ScoDoc 9 API : liste opérations effectuées par un utilisateur
|
||||||
|
|
||||||
|
CATEGORY
|
||||||
|
--------
|
||||||
|
Operations
|
||||||
|
"""
|
||||||
|
|
||||||
|
from flask import url_for
|
||||||
|
from flask_json import as_json
|
||||||
|
from flask_login import login_required
|
||||||
|
|
||||||
|
import app
|
||||||
|
from app import db
|
||||||
|
from app.api import api_bp as bp, api_web_bp
|
||||||
|
from app.api import api_permission_required as permission_required
|
||||||
|
from app.decorators import scodoc
|
||||||
|
from app.models import NotesNotes
|
||||||
|
from app.scodoc.sco_permissions import Permission
|
||||||
|
from app.scodoc import sco_utils as scu
|
||||||
|
|
||||||
|
MAX_QUERY_LENGTH = 10000
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/operations/user/<int:uid>/notes")
|
||||||
|
@api_web_bp.route("/operations/user/<int:uid>/notes")
|
||||||
|
@login_required
|
||||||
|
@scodoc
|
||||||
|
@permission_required(Permission.ScoView)
|
||||||
|
@as_json
|
||||||
|
def operations_user_notes(uid: int):
|
||||||
|
"""Liste les opérations de saisie de notes effectuées par utilisateur.
|
||||||
|
|
||||||
|
QUERY
|
||||||
|
-----
|
||||||
|
start: indice de début de la liste
|
||||||
|
length: nombre d'éléments à retourner
|
||||||
|
draw: numéro de la requête (pour pagination, renvoyé tel quel)
|
||||||
|
order[dir]: desc ou asc
|
||||||
|
search[value]: chaîne à chercher (dans évaluation et étudiant)
|
||||||
|
PARAMS
|
||||||
|
-----
|
||||||
|
uid: l'id de l'utilisateur
|
||||||
|
"""
|
||||||
|
start = int(app.request.args.get("start", 0))
|
||||||
|
length = min(int(app.request.args.get("length", 10)), MAX_QUERY_LENGTH)
|
||||||
|
order = app.request.args.get("order[dir]", "desc")
|
||||||
|
draw = int(app.request.args.get("draw", 1))
|
||||||
|
search = app.request.args.get("search[value]", "")
|
||||||
|
query = db.session.query(NotesNotes).filter(NotesNotes.uid == uid)
|
||||||
|
if order == "asc":
|
||||||
|
query = query.order_by(NotesNotes.date.asc())
|
||||||
|
else:
|
||||||
|
query = query.order_by(NotesNotes.date.desc())
|
||||||
|
|
||||||
|
# Pour l'efficacité, limite si pas de recherche en python
|
||||||
|
limited_query = query.offset(start).limit(length) if not search else query
|
||||||
|
|
||||||
|
data = []
|
||||||
|
for note in limited_query:
|
||||||
|
obj = {
|
||||||
|
"date": note.date.isoformat(),
|
||||||
|
"date_dmy": note.date.strftime(scu.DATEATIME_FMT),
|
||||||
|
"operation": "Saisie de note",
|
||||||
|
"value": scu.fmt_note(note.value),
|
||||||
|
"id": note.id,
|
||||||
|
"uid": note.uid,
|
||||||
|
"etudiant": note.etudiant.to_dict_short(),
|
||||||
|
"etudiant_link": note.etudiant.html_link_fiche(),
|
||||||
|
"evaluation": note.evaluation.to_dict_api(),
|
||||||
|
"evaluation_link": f"""<a href="{
|
||||||
|
url_for('notes.evaluation_listenotes',
|
||||||
|
scodoc_dept=note.evaluation.moduleimpl.formsemestre.departement.acronym,
|
||||||
|
evaluation_id=note.evaluation_id)
|
||||||
|
}">{note.evaluation.descr()}</a>""",
|
||||||
|
}
|
||||||
|
if search:
|
||||||
|
search = search.lower()
|
||||||
|
if (
|
||||||
|
search not in note.etudiant.nomprenom.lower()
|
||||||
|
and search not in note.evaluation.descr().lower()
|
||||||
|
and search not in obj["date_dmy"]
|
||||||
|
):
|
||||||
|
continue # skip
|
||||||
|
|
||||||
|
data.append(obj)
|
||||||
|
|
||||||
|
result = data[start : start + length] if search else data
|
||||||
|
return {
|
||||||
|
"draw": draw,
|
||||||
|
"recordsTotal": query.count(), # unfiltered
|
||||||
|
"recordsFiltered": len(data) if search else query.count(),
|
||||||
|
"data": result,
|
||||||
|
}
|
@ -121,6 +121,12 @@ class Identite(models.ScoDocModel):
|
|||||||
cascade="all, delete-orphan",
|
cascade="all, delete-orphan",
|
||||||
lazy="dynamic",
|
lazy="dynamic",
|
||||||
)
|
)
|
||||||
|
notes = db.relationship(
|
||||||
|
"NotesNotes",
|
||||||
|
backref="etudiant",
|
||||||
|
cascade="all, delete-orphan",
|
||||||
|
lazy="dynamic",
|
||||||
|
)
|
||||||
# Relations avec les assiduites et les justificatifs
|
# Relations avec les assiduites et les justificatifs
|
||||||
assiduites = db.relationship(
|
assiduites = db.relationship(
|
||||||
"Assiduite", back_populates="etudiant", lazy="dynamic", cascade="all, delete"
|
"Assiduite", back_populates="etudiant", lazy="dynamic", cascade="all, delete"
|
||||||
|
@ -58,6 +58,12 @@ class Evaluation(models.ScoDocModel):
|
|||||||
# ordre de presentation (par défaut, le plus petit numero
|
# ordre de presentation (par défaut, le plus petit numero
|
||||||
# est la plus ancienne eval):
|
# est la plus ancienne eval):
|
||||||
numero = db.Column(db.Integer, nullable=False, default=0)
|
numero = db.Column(db.Integer, nullable=False, default=0)
|
||||||
|
notes = db.relationship(
|
||||||
|
"NotesNotes",
|
||||||
|
backref="evaluation",
|
||||||
|
cascade="all, delete-orphan",
|
||||||
|
lazy="dynamic",
|
||||||
|
)
|
||||||
ues = db.relationship("UniteEns", secondary="evaluation_ue_poids", viewonly=True)
|
ues = db.relationship("UniteEns", secondary="evaluation_ue_poids", viewonly=True)
|
||||||
|
|
||||||
_sco_dept_relations = ("ModuleImpl", "FormSemestre") # accès au dept_id
|
_sco_dept_relations = ("ModuleImpl", "FormSemestre") # accès au dept_id
|
||||||
@ -380,6 +386,13 @@ class Evaluation(models.ScoDocModel):
|
|||||||
return f"""du {self.date_debut.strftime('%d/%m/%Y')} à {
|
return f"""du {self.date_debut.strftime('%d/%m/%Y')} à {
|
||||||
_h(self.date_debut)} au {self.date_fin.strftime('%d/%m/%Y')} à {_h(self.date_fin)}"""
|
_h(self.date_debut)} au {self.date_fin.strftime('%d/%m/%Y')} à {_h(self.date_fin)}"""
|
||||||
|
|
||||||
|
def descr(self) -> str:
|
||||||
|
"Description de l'évaluation pour affichage (avec module et semestre)"
|
||||||
|
return f"""{self.description} {self.descr_date()} en {
|
||||||
|
self.moduleimpl.module.titre_str()} du {
|
||||||
|
self.moduleimpl.formsemestre.titre_formation(with_sem_idx=True)
|
||||||
|
}"""
|
||||||
|
|
||||||
def heure_debut(self) -> str:
|
def heure_debut(self) -> str:
|
||||||
"""L'heure de début (sans la date), en ISO.
|
"""L'heure de début (sans la date), en ISO.
|
||||||
Chaine vide si non renseignée."""
|
Chaine vide si non renseignée."""
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
{# Tableau de bord utilisateur #}
|
{# Tableau de bord utilisateur #}
|
||||||
|
|
||||||
{% extends "base.j2" %}
|
{% extends "base.j2" %}
|
||||||
|
{% block styles %}
|
||||||
{% block app_content %}
|
{{super()}}
|
||||||
|
<link type="text/css" rel="stylesheet" href="{{scu.STATIC_DIR}}/libjs/qtip/jquery.qtip-3.0.3.min.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{scu.STATIC_DIR}}/DataTables/datatables.min.css" />
|
||||||
<style>
|
<style>
|
||||||
.ub-formsemestres {
|
.ub-formsemestres {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -60,7 +62,14 @@
|
|||||||
color: black;
|
color: black;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.scobox.saisies-notes {
|
||||||
|
background-color: rgb(243, 255, 255);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block app_content %}
|
||||||
|
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<h2>{{user.get_nomcomplet()}}</h2>
|
<h2>{{user.get_nomcomplet()}}</h2>
|
||||||
@ -105,6 +114,61 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
|
||||||
|
<div class="scobox saisies-notes">
|
||||||
|
<div class="scobox-title">
|
||||||
|
Dernières saisies de notes par {{user.get_prenomnom()}}
|
||||||
|
</div>
|
||||||
|
<table id="saisies-notes" class="display" style="width:100%">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Date</th>
|
||||||
|
<th>Évaluation</th>
|
||||||
|
<th>Étudiant</th>
|
||||||
|
<th>Note</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<!-- Data will be loaded dynamically via JavaScript -->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% endblock app_content %}
|
{% endblock app_content %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block scripts %}
|
||||||
|
{{ super() }}
|
||||||
|
<script src="{{scu.STATIC_DIR}}/js/etud_info.js"></script>
|
||||||
|
<script src="{{scu.STATIC_DIR}}/DataTables/datatables.min.js"></script>
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$('#saisies-notes').DataTable({
|
||||||
|
"processing": true,
|
||||||
|
"serverSide": true,
|
||||||
|
"ajax": {
|
||||||
|
"url": "{{ url_for('apiweb.operations_user_notes',
|
||||||
|
scodoc_dept=current_user.dept or g.scodoc_dept or fallback_dept.acronym,
|
||||||
|
uid=user.id) }}",
|
||||||
|
"type": "GET"
|
||||||
|
},
|
||||||
|
"columns": [
|
||||||
|
{ "data": "date_dmy", "orderable": false },
|
||||||
|
{ "data": "evaluation_link", "orderable": false },
|
||||||
|
{ "data": "etudiant_link", "orderable": false },
|
||||||
|
{ "data": "value", "orderable": false }
|
||||||
|
],
|
||||||
|
"language": {
|
||||||
|
search: "Chercher (date, titre, étudiant) :", // Change the "Search:" label
|
||||||
|
lengthMenu: "Show _MENU_ records per page"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
@ -14,6 +14,7 @@ from app.decorators import (
|
|||||||
permission_required,
|
permission_required,
|
||||||
)
|
)
|
||||||
from app.models import Departement, FormSemestre
|
from app.models import Departement, FormSemestre
|
||||||
|
from app.scodoc.sco_exceptions import ScoValueError
|
||||||
from app.scodoc.sco_permissions import Permission
|
from app.scodoc.sco_permissions import Permission
|
||||||
from app.scodoc import sco_preferences
|
from app.scodoc import sco_preferences
|
||||||
from app.views import scodoc_bp as bp
|
from app.views import scodoc_bp as bp
|
||||||
@ -25,6 +26,9 @@ from app.views import ScoData
|
|||||||
@login_required
|
@login_required
|
||||||
def user_board(user_name: str):
|
def user_board(user_name: str):
|
||||||
"""Tableau de bord utilisateur: liens vers ses objets"""
|
"""Tableau de bord utilisateur: liens vers ses objets"""
|
||||||
|
fallback_dept = db.session.query(Departement).first()
|
||||||
|
if not fallback_dept:
|
||||||
|
raise ScoValueError("Aucun département existant")
|
||||||
user = User.query.filter_by(user_name=user_name).first_or_404()
|
user = User.query.filter_by(user_name=user_name).first_or_404()
|
||||||
(
|
(
|
||||||
formsemestres_by_dept,
|
formsemestres_by_dept,
|
||||||
@ -47,6 +51,7 @@ def user_board(user_name: str):
|
|||||||
"user_board/user_board.j2",
|
"user_board/user_board.j2",
|
||||||
depts=depts,
|
depts=depts,
|
||||||
dept_names=dept_names_sorted,
|
dept_names=dept_names_sorted,
|
||||||
|
fallback_dept=fallback_dept,
|
||||||
formsemestres_by_dept=formsemestres_by_dept,
|
formsemestres_by_dept=formsemestres_by_dept,
|
||||||
modimpls_by_formsemestre=modimpls_by_formsemestre,
|
modimpls_by_formsemestre=modimpls_by_formsemestre,
|
||||||
sco=ScoData(),
|
sco=ScoData(),
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
"Infos sur version ScoDoc"
|
"Infos sur version ScoDoc"
|
||||||
|
|
||||||
SCOVERSION = "9.7.37"
|
SCOVERSION = "9.7.38"
|
||||||
|
|
||||||
SCONAME = "ScoDoc"
|
SCONAME = "ScoDoc"
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user