Files
gesthub/web/models/annonce_model.py
2026-08-21 09:12:02 +02:00

58 lines
1.8 KiB
Python

"""
annonce_model.py — Accès aux données pour l'entité "annonce".
Toutes les requêtes utilisent des paramètres préparés (%s) : aucune
concaténation de chaîne SQL n'est utilisée dans ce module (OWASP A03:2021 —
Injection). Voir tests de sécurité TS-01 (tests/test_security.py).
"""
class AnnonceNotFoundError(Exception):
"""Exception métier levée quand une annonce n'existe pas.
La couche services/ traduit les erreurs SQL bas niveau en exceptions
métier compréhensibles, afin que les routes n'aient jamais à connaître
les détails de pymysql (cf. C4 — convention de gestion des erreurs).
"""
def insert(db, titre, contenu, auteur_sub, epinglee=False):
query = (
"INSERT INTO annonces (titre, contenu, epinglee, auteur_sub) "
"VALUES (%s, %s, %s, %s)"
)
return db.execute(query, (titre, contenu, int(epinglee), auteur_sub))
def fetch_all(db):
query = (
"SELECT id, titre, contenu, epinglee, auteur_sub, created_at, updated_at "
"FROM annonces ORDER BY epinglee DESC, created_at DESC"
)
return db.fetch_all(query)
def get(db, annonce_id):
query = (
"SELECT id, titre, contenu, epinglee, auteur_sub, created_at, updated_at "
"FROM annonces WHERE id = %s"
)
return db.fetch_one(query, (annonce_id,))
def update(db, annonce_id, titre, contenu, epinglee=False):
query = (
"UPDATE annonces SET titre = %s, contenu = %s, epinglee = %s "
"WHERE id = %s"
)
with db.cursor(commit=True) as cur:
cur.execute(query, (titre, contenu, int(epinglee), annonce_id))
return cur.rowcount
def delete(db, annonce_id):
query = "DELETE FROM annonces WHERE id = %s"
with db.cursor(commit=True) as cur:
cur.execute(query, (annonce_id,))
return cur.rowcount