From e6e87732f20d8aca4be46fe085cbe352df072cff Mon Sep 17 00:00:00 2001 From: Mylloon Date: Fri, 19 Nov 2021 21:14:14 +0100 Subject: [PATCH] leave pdoc for classic latex documentation --- .gitignore | 4 + README.md | 6 - documentation/GesMag/db.html | 275 -------------------- documentation/GesMag/index.html | 70 ------ documentation/GesMag/main.html | 430 -------------------------------- documentation/GesMag/users.html | 357 -------------------------- documentation/documentation.tex | 180 +++++++++++++ 7 files changed, 184 insertions(+), 1138 deletions(-) delete mode 100644 documentation/GesMag/db.html delete mode 100644 documentation/GesMag/index.html delete mode 100644 documentation/GesMag/main.html delete mode 100644 documentation/GesMag/users.html create mode 100644 documentation/documentation.tex diff --git a/.gitignore b/.gitignore index 59c84bf..c0dc590 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,8 @@ __pycache__/ +documentation/* *.pdf *.sqlite3 + +!documentation/documentation.pdf +!documentation/documentation.tex diff --git a/README.md b/README.md index f19b5eb..e5be94c 100644 --- a/README.md +++ b/README.md @@ -52,9 +52,3 @@ A savoir : - [ ] Exporter le ticket de caisse en format image - [x] Lisibilité du code - [x] Toutes les fonctions sont nommés et typés (j'utilises `Python 3.9.7`) - -### Crédit pour la documentation -Pour générer la documentation présente [ici](doc/) vous aurez besoin de [pdoc](https://pdoc3.github.io/pdoc/), ainsi pour la générer, vous devez lancez cette commande : -``` -python3 -m pdoc --html -fc "html_lang='fr'" -o ./documentation . -``` diff --git a/documentation/GesMag/db.html b/documentation/GesMag/db.html deleted file mode 100644 index ad84a6f..0000000 --- a/documentation/GesMag/db.html +++ /dev/null @@ -1,275 +0,0 @@ - - - - - - -GesMag.db API documentation - - - - - - - - - - - -
-
-
-

Module GesMag.db

-
-
-
- -Expand source code - -
import sqlite3
-from sqlite3.dbapi2 import Cursor
-
-class BaseDeDonnees:
-    """Gère la base de donnée."""
-    def __init__(self, urlBaseDeDonnee: str):
-        self.connexion = self.creerConnexion(urlBaseDeDonnee)
-
-    def creerConnexion(self, path: str):
-        """Connexion à une base de donnée SQLite."""
-        if not self.fichierExiste(path): # si l base de donnée n'existe pas
-            open(path, "x") # on la créer
-        try:
-            connnexion = sqlite3.connect(path)
-        except sqlite3.Error as e:
-            print(e) # on affiche l'erreur
-            connnexion = None # et renvoie None
-        return connnexion
-
-    def fichierExiste(self, path: str) -> bool:
-        """Vérifie qu'un fichier existe."""
-        try: # on essaie d'ouvrir le fichier
-            open(path, "r")
-        except FileNotFoundError: # si le fichier n'existe pas
-            return False
-        else: # si le fichier existe
-            return True
-
-    def requete(self, requete: str, valeurs = None):
-        """Envois une requête vers la base de données."""
-        try:
-            curseur = self.connexion.cursor()
-            if valeurs: # s'il y a des valeurs alors on lance la commande `execute` avec ses dernières
-                if type(valeurs) not in [list, tuple]: # si la valeur c'est juste une chaîne de charactère (par exemple), alors la converti en liste
-                    valeurs = [valeurs]
-                curseur.execute(requete, valeurs)
-            else: # sinon on lance juste la requête
-                curseur.execute(requete)
-            self.connexion.commit() # applique les changements à la base de donnée
-            return (curseur, curseur.lastrowid) # renvoie le curseur et l'ID de l'élément modifié
-        except sqlite3.Error as e: # s'il y a eu une erreur SQLite
-            print(e)
-
-    def affichageResultat(self, curseur: Cursor) -> list:
-        """Affiche le résultat d'une requête."""
-        tableau = []
-        if curseur == None: # si le curseur est vide il n'y a rien a affiché (tableau vide)
-            return tableau
-        lignes = curseur[0].fetchall() # sinon on récupère les éléments
-        for ligne in lignes:
-            tableau.append(ligne) # on les ajoute au tableau
-        return tableau # on le renvoie
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class BaseDeDonnees -(urlBaseDeDonnee: str) -
-
-

Gère la base de donnée.

-
- -Expand source code - -
class BaseDeDonnees:
-    """Gère la base de donnée."""
-    def __init__(self, urlBaseDeDonnee: str):
-        self.connexion = self.creerConnexion(urlBaseDeDonnee)
-
-    def creerConnexion(self, path: str):
-        """Connexion à une base de donnée SQLite."""
-        if not self.fichierExiste(path): # si l base de donnée n'existe pas
-            open(path, "x") # on la créer
-        try:
-            connnexion = sqlite3.connect(path)
-        except sqlite3.Error as e:
-            print(e) # on affiche l'erreur
-            connnexion = None # et renvoie None
-        return connnexion
-
-    def fichierExiste(self, path: str) -> bool:
-        """Vérifie qu'un fichier existe."""
-        try: # on essaie d'ouvrir le fichier
-            open(path, "r")
-        except FileNotFoundError: # si le fichier n'existe pas
-            return False
-        else: # si le fichier existe
-            return True
-
-    def requete(self, requete: str, valeurs = None):
-        """Envois une requête vers la base de données."""
-        try:
-            curseur = self.connexion.cursor()
-            if valeurs: # s'il y a des valeurs alors on lance la commande `execute` avec ses dernières
-                if type(valeurs) not in [list, tuple]: # si la valeur c'est juste une chaîne de charactère (par exemple), alors la converti en liste
-                    valeurs = [valeurs]
-                curseur.execute(requete, valeurs)
-            else: # sinon on lance juste la requête
-                curseur.execute(requete)
-            self.connexion.commit() # applique les changements à la base de donnée
-            return (curseur, curseur.lastrowid) # renvoie le curseur et l'ID de l'élément modifié
-        except sqlite3.Error as e: # s'il y a eu une erreur SQLite
-            print(e)
-
-    def affichageResultat(self, curseur: Cursor) -> list:
-        """Affiche le résultat d'une requête."""
-        tableau = []
-        if curseur == None: # si le curseur est vide il n'y a rien a affiché (tableau vide)
-            return tableau
-        lignes = curseur[0].fetchall() # sinon on récupère les éléments
-        for ligne in lignes:
-            tableau.append(ligne) # on les ajoute au tableau
-        return tableau # on le renvoie
-
-

Methods

-
-
-def affichageResultat(self, curseur: sqlite3.Cursor) ‑> list -
-
-

Affiche le résultat d'une requête.

-
- -Expand source code - -
def affichageResultat(self, curseur: Cursor) -> list:
-    """Affiche le résultat d'une requête."""
-    tableau = []
-    if curseur == None: # si le curseur est vide il n'y a rien a affiché (tableau vide)
-        return tableau
-    lignes = curseur[0].fetchall() # sinon on récupère les éléments
-    for ligne in lignes:
-        tableau.append(ligne) # on les ajoute au tableau
-    return tableau # on le renvoie
-
-
-
-def creerConnexion(self, path: str) -
-
-

Connexion à une base de donnée SQLite.

-
- -Expand source code - -
def creerConnexion(self, path: str):
-    """Connexion à une base de donnée SQLite."""
-    if not self.fichierExiste(path): # si l base de donnée n'existe pas
-        open(path, "x") # on la créer
-    try:
-        connnexion = sqlite3.connect(path)
-    except sqlite3.Error as e:
-        print(e) # on affiche l'erreur
-        connnexion = None # et renvoie None
-    return connnexion
-
-
-
-def fichierExiste(self, path: str) ‑> bool -
-
-

Vérifie qu'un fichier existe.

-
- -Expand source code - -
def fichierExiste(self, path: str) -> bool:
-    """Vérifie qu'un fichier existe."""
-    try: # on essaie d'ouvrir le fichier
-        open(path, "r")
-    except FileNotFoundError: # si le fichier n'existe pas
-        return False
-    else: # si le fichier existe
-        return True
-
-
-
-def requete(self, requete: str, valeurs=None) -
-
-

Envois une requête vers la base de données.

-
- -Expand source code - -
def requete(self, requete: str, valeurs = None):
-    """Envois une requête vers la base de données."""
-    try:
-        curseur = self.connexion.cursor()
-        if valeurs: # s'il y a des valeurs alors on lance la commande `execute` avec ses dernières
-            if type(valeurs) not in [list, tuple]: # si la valeur c'est juste une chaîne de charactère (par exemple), alors la converti en liste
-                valeurs = [valeurs]
-            curseur.execute(requete, valeurs)
-        else: # sinon on lance juste la requête
-            curseur.execute(requete)
-        self.connexion.commit() # applique les changements à la base de donnée
-        return (curseur, curseur.lastrowid) # renvoie le curseur et l'ID de l'élément modifié
-    except sqlite3.Error as e: # s'il y a eu une erreur SQLite
-        print(e)
-
-
-
-
-
-
-
- -
- - - \ No newline at end of file diff --git a/documentation/GesMag/index.html b/documentation/GesMag/index.html deleted file mode 100644 index 4b2bf16..0000000 --- a/documentation/GesMag/index.html +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - -GesMag API documentation - - - - - - - - - - - -
- - -
- - - \ No newline at end of file diff --git a/documentation/GesMag/main.html b/documentation/GesMag/main.html deleted file mode 100644 index 1e8e6fc..0000000 --- a/documentation/GesMag/main.html +++ /dev/null @@ -1,430 +0,0 @@ - - - - - - -GesMag.main API documentation - - - - - - - - - - - -
-
-
-

Module GesMag.main

-
-
-
- -Expand source code - -
import tkinter.messagebox as messagebox
-
-from tkinter import *
-from re import sub
-
-from users import Utilisateurs # import de mon fichier pour gérer la base de donnée
-
-def dimensionsFenetre(fenetre, taille: tuple):
-    """Permet de définir une fenetre centrer sur l'écran"""
-    largeur = fenetre.winfo_screenwidth()
-    hauteur = fenetre.winfo_screenheight()
-
-    x = (largeur // 2) - (taille[0] // 2)
-    y = (hauteur // 2) - (taille[1] // 2)
-
-    fenetre.geometry(f"{taille[0]}x{taille[1]}+{x}+{y}")
-
-class GesMag:
-    """Programme de Gestion d'une caise de magasin."""
-    def demarrer(self) -> None:
-        """Lance le programme GesMag."""
-        print("Lancement de l'interface de gestion d'une caisse d'un magasin...")
-        self.font = ("Comfortaa", 14) # police par défaut
-        Utilisateurs().creationTable() # on créer la base de donnée si elle n'existe pas déjà
-        self.parent = Tk() # on créer notre fenêtre principale
-
-        self._interfaceConnexion() # on créer la variable `self.f` qui est la frame a affiché
-        self.f.grid() # on affiche la frame
-
-        self.parent.mainloop() # on affiche la fenêtre
-
-    def motDePasseCorrect(self, motDPasse: str) -> tuple:
-        """Détermine si un mot de passe suit la politique du programme ou non."""
-        if len(motDPasse) == 0: # si le champs est vide
-            return (False, "Mot de passe incorrect.")
-        if len(motDPasse) < 8: # si le mot de passe est plus petit que 8 caractères
-            return (False, "Un mot de passe doit faire 8 caractères minimum.")
-        """
-        Pour le regex, je réfléchie comme dans la fonction `self.connexion`.
-        J'utilises pas `match` parce que je suis plus à l'aise avec `sub`.
-        """
-        if not sub(r"[A-Z]", '', motDPasse) != motDPasse:
-            return (False, "Un mot de passe doit au moins contenir une lettre majuscule.")
-        if not sub(r"[a-z]", '', motDPasse) != motDPasse:
-            return (False, "Un mot de passe doit au moins contenir une lettre minuscule.")
-        if not sub(r" *?[^\w\s]+", '', motDPasse) != motDPasse:
-            return (False, "Un mot de passe doit au moins contenir un caractère spécial.")
-
-        return (True,) # si aucun des tests précédents n'est valide, alors le mot de passe est valide
-
-    def connexion(self, utilisateur: str, motDePasse: str):
-        """Gère la connexion aux différentes interfaces de l'application."""
-        """
-        Vérification nom d'utilisateur / mot de passe correctement entré
-        -> Pour le nom d'utilisateur on vérifie si le champs n'est pas vide
-           et si il y a bien que des lettres et des chiffres (le regex élimine tout
-           ce qui n'est pas ça, alors si la fonction `sub` renvoie pas exactement
-           la même chaîne de charactère alors c'est qu'il y avait un charactère
-           interdit dans le nom d'utilisateur).
-        -> Pour le mot de passe on demande à la fonction `motDePasseCorrect` pour
-           éviter de faire tout les tests ici.
-        """
-        if len(utilisateur) == 0 or sub(r" *?[^\w\s]+", '', utilisateur) != utilisateur:
-            messagebox.showerror("Erreur", "Utilisateur incorrect.")
-            return
-        mdpOk = self.motDePasseCorrect(motDePasse)
-        if not mdpOk[0]:
-            messagebox.showerror("Erreur", mdpOk[1])
-            return
-
-        # Redirection vers la bonne interface
-        if Utilisateurs().verificationIdentifiants(utilisateur, motDePasse):
-            print("Bienvenue mon pote")
-        else:
-            print(f"Bah nan frérot c'est pas bon, ça c'est la liste des utilisateurs : {Utilisateurs().listUtilisateurs()}")
-
-    def _interfaceConnexion(self):
-        """Affiche la fenêtre de connexion."""
-        # Paramètres de la fenêtre
-        dimensionsFenetre(self.parent, (400, 600))
-        self.parent.title("Fenêtre de connexion")
-
-        # Instanciation de la Frame, on va donc ajouter tout nos widgets à cet Frame
-        self.f = Frame(self.parent)
-
-        # Affichage des labels et boutons
-        tentativeDeConnexion = lambda _ = None: self.connexion(utilisateur.get(), motDpasse.get()) # lambda pour envoyer les informations entrés dans le formulaire
-        ecart = 80 # écart pour avoir un affichage centré
-        Label(self.f).grid(row=0, pady=50) # utilisé pour du padding (meilleur affichage)
-
-        Label(self.f, text="Utilisateur", font=self.font).grid(column=0, row=1, columnspan=2, padx=ecart - 20, pady=20, sticky=W)
-        utilisateur = Entry(self.f, font=self.font, width=18)
-        utilisateur.grid(column=1, row=2, columnspan=2, padx=ecart)
-
-        Label(self.f, text="Mot de passe", font=self.font).grid(column=0, row=3, columnspan=2, padx=ecart - 20, pady=20, sticky=W)
-        motDpasse = Entry(self.f, font=self.font, show='⁎', width=18)
-        motDpasse.grid(column=1, row=4, columnspan=2, padx=ecart)
-        motDpasse.bind("<Return>", tentativeDeConnexion)
-
-        def __afficherMDP(self):
-            """Permet de gérer l'affichage du mot de passe dans le champs sur la page de connexion."""
-            if self.mdpVisible == False: # si mot de passe caché, alors on l'affiche
-                self.mdpVisible = True
-                motDpasse.config(show='')
-                bouttonAffichageMDP.config(font=("Arial", 10, "overstrike"))
-
-            else: # inversement
-                self.mdpVisible = False
-                motDpasse.config(show='⁎')
-                bouttonAffichageMDP.config(font=("Arial", 10))
-
-        bouttonAffichageMDP = Button(self.f, text='👁', command=lambda: __afficherMDP(self))
-        bouttonAffichageMDP.grid(column=2, row=4, columnspan=2)
-        self.mdpVisible = False
-
-        bouton = Button(self.f, text="Se connecter", font=self.font, command=tentativeDeConnexion)
-        bouton.grid(column=0, row=5, columnspan=3, padx=ecart, pady=20)
-        bouton.bind("<Return>", tentativeDeConnexion)
-
-        Button(self.f, text="Quitter", font=self.font, command=quit).grid(column=0, row=6, columnspan=4, pady=20)
-
-if __name__ == "__main__":
-    """"Application "GesMag" pour le module de Programmation d'interfaces (2021-2022)"""
-    print("--  Compte par défaut --\nNom d'utilisateur: admin\nMot de passe: P@ssword\n")
-    GesMag().demarrer()
-
-
-
-
-
-
-
-

Functions

-
-
-def dimensionsFenetre(fenetre, taille: tuple) -
-
-

Permet de définir une fenetre centrer sur l'écran

-
- -Expand source code - -
def dimensionsFenetre(fenetre, taille: tuple):
-    """Permet de définir une fenetre centrer sur l'écran"""
-    largeur = fenetre.winfo_screenwidth()
-    hauteur = fenetre.winfo_screenheight()
-
-    x = (largeur // 2) - (taille[0] // 2)
-    y = (hauteur // 2) - (taille[1] // 2)
-
-    fenetre.geometry(f"{taille[0]}x{taille[1]}+{x}+{y}")
-
-
-
-
-
-

Classes

-
-
-class GesMag -
-
-

Programme de Gestion d'une caise de magasin.

-
- -Expand source code - -
class GesMag:
-    """Programme de Gestion d'une caise de magasin."""
-    def demarrer(self) -> None:
-        """Lance le programme GesMag."""
-        print("Lancement de l'interface de gestion d'une caisse d'un magasin...")
-        self.font = ("Comfortaa", 14) # police par défaut
-        Utilisateurs().creationTable() # on créer la base de donnée si elle n'existe pas déjà
-        self.parent = Tk() # on créer notre fenêtre principale
-
-        self._interfaceConnexion() # on créer la variable `self.f` qui est la frame a affiché
-        self.f.grid() # on affiche la frame
-
-        self.parent.mainloop() # on affiche la fenêtre
-
-    def motDePasseCorrect(self, motDPasse: str) -> tuple:
-        """Détermine si un mot de passe suit la politique du programme ou non."""
-        if len(motDPasse) == 0: # si le champs est vide
-            return (False, "Mot de passe incorrect.")
-        if len(motDPasse) < 8: # si le mot de passe est plus petit que 8 caractères
-            return (False, "Un mot de passe doit faire 8 caractères minimum.")
-        """
-        Pour le regex, je réfléchie comme dans la fonction `self.connexion`.
-        J'utilises pas `match` parce que je suis plus à l'aise avec `sub`.
-        """
-        if not sub(r"[A-Z]", '', motDPasse) != motDPasse:
-            return (False, "Un mot de passe doit au moins contenir une lettre majuscule.")
-        if not sub(r"[a-z]", '', motDPasse) != motDPasse:
-            return (False, "Un mot de passe doit au moins contenir une lettre minuscule.")
-        if not sub(r" *?[^\w\s]+", '', motDPasse) != motDPasse:
-            return (False, "Un mot de passe doit au moins contenir un caractère spécial.")
-
-        return (True,) # si aucun des tests précédents n'est valide, alors le mot de passe est valide
-
-    def connexion(self, utilisateur: str, motDePasse: str):
-        """Gère la connexion aux différentes interfaces de l'application."""
-        """
-        Vérification nom d'utilisateur / mot de passe correctement entré
-        -> Pour le nom d'utilisateur on vérifie si le champs n'est pas vide
-           et si il y a bien que des lettres et des chiffres (le regex élimine tout
-           ce qui n'est pas ça, alors si la fonction `sub` renvoie pas exactement
-           la même chaîne de charactère alors c'est qu'il y avait un charactère
-           interdit dans le nom d'utilisateur).
-        -> Pour le mot de passe on demande à la fonction `motDePasseCorrect` pour
-           éviter de faire tout les tests ici.
-        """
-        if len(utilisateur) == 0 or sub(r" *?[^\w\s]+", '', utilisateur) != utilisateur:
-            messagebox.showerror("Erreur", "Utilisateur incorrect.")
-            return
-        mdpOk = self.motDePasseCorrect(motDePasse)
-        if not mdpOk[0]:
-            messagebox.showerror("Erreur", mdpOk[1])
-            return
-
-        # Redirection vers la bonne interface
-        if Utilisateurs().verificationIdentifiants(utilisateur, motDePasse):
-            print("Bienvenue mon pote")
-        else:
-            print(f"Bah nan frérot c'est pas bon, ça c'est la liste des utilisateurs : {Utilisateurs().listUtilisateurs()}")
-
-    def _interfaceConnexion(self):
-        """Affiche la fenêtre de connexion."""
-        # Paramètres de la fenêtre
-        dimensionsFenetre(self.parent, (400, 600))
-        self.parent.title("Fenêtre de connexion")
-
-        # Instanciation de la Frame, on va donc ajouter tout nos widgets à cet Frame
-        self.f = Frame(self.parent)
-
-        # Affichage des labels et boutons
-        tentativeDeConnexion = lambda _ = None: self.connexion(utilisateur.get(), motDpasse.get()) # lambda pour envoyer les informations entrés dans le formulaire
-        ecart = 80 # écart pour avoir un affichage centré
-        Label(self.f).grid(row=0, pady=50) # utilisé pour du padding (meilleur affichage)
-
-        Label(self.f, text="Utilisateur", font=self.font).grid(column=0, row=1, columnspan=2, padx=ecart - 20, pady=20, sticky=W)
-        utilisateur = Entry(self.f, font=self.font, width=18)
-        utilisateur.grid(column=1, row=2, columnspan=2, padx=ecart)
-
-        Label(self.f, text="Mot de passe", font=self.font).grid(column=0, row=3, columnspan=2, padx=ecart - 20, pady=20, sticky=W)
-        motDpasse = Entry(self.f, font=self.font, show='⁎', width=18)
-        motDpasse.grid(column=1, row=4, columnspan=2, padx=ecart)
-        motDpasse.bind("<Return>", tentativeDeConnexion)
-
-        def __afficherMDP(self):
-            """Permet de gérer l'affichage du mot de passe dans le champs sur la page de connexion."""
-            if self.mdpVisible == False: # si mot de passe caché, alors on l'affiche
-                self.mdpVisible = True
-                motDpasse.config(show='')
-                bouttonAffichageMDP.config(font=("Arial", 10, "overstrike"))
-
-            else: # inversement
-                self.mdpVisible = False
-                motDpasse.config(show='⁎')
-                bouttonAffichageMDP.config(font=("Arial", 10))
-
-        bouttonAffichageMDP = Button(self.f, text='👁', command=lambda: __afficherMDP(self))
-        bouttonAffichageMDP.grid(column=2, row=4, columnspan=2)
-        self.mdpVisible = False
-
-        bouton = Button(self.f, text="Se connecter", font=self.font, command=tentativeDeConnexion)
-        bouton.grid(column=0, row=5, columnspan=3, padx=ecart, pady=20)
-        bouton.bind("<Return>", tentativeDeConnexion)
-
-        Button(self.f, text="Quitter", font=self.font, command=quit).grid(column=0, row=6, columnspan=4, pady=20)
-
-

Methods

-
-
-def connexion(self, utilisateur: str, motDePasse: str) -
-
-

Gère la connexion aux différentes interfaces de l'application.

-
- -Expand source code - -
def connexion(self, utilisateur: str, motDePasse: str):
-    """Gère la connexion aux différentes interfaces de l'application."""
-    """
-    Vérification nom d'utilisateur / mot de passe correctement entré
-    -> Pour le nom d'utilisateur on vérifie si le champs n'est pas vide
-       et si il y a bien que des lettres et des chiffres (le regex élimine tout
-       ce qui n'est pas ça, alors si la fonction `sub` renvoie pas exactement
-       la même chaîne de charactère alors c'est qu'il y avait un charactère
-       interdit dans le nom d'utilisateur).
-    -> Pour le mot de passe on demande à la fonction `motDePasseCorrect` pour
-       éviter de faire tout les tests ici.
-    """
-    if len(utilisateur) == 0 or sub(r" *?[^\w\s]+", '', utilisateur) != utilisateur:
-        messagebox.showerror("Erreur", "Utilisateur incorrect.")
-        return
-    mdpOk = self.motDePasseCorrect(motDePasse)
-    if not mdpOk[0]:
-        messagebox.showerror("Erreur", mdpOk[1])
-        return
-
-    # Redirection vers la bonne interface
-    if Utilisateurs().verificationIdentifiants(utilisateur, motDePasse):
-        print("Bienvenue mon pote")
-    else:
-        print(f"Bah nan frérot c'est pas bon, ça c'est la liste des utilisateurs : {Utilisateurs().listUtilisateurs()}")
-
-
-
-def demarrer(self) ‑> None -
-
-

Lance le programme GesMag.

-
- -Expand source code - -
def demarrer(self) -> None:
-    """Lance le programme GesMag."""
-    print("Lancement de l'interface de gestion d'une caisse d'un magasin...")
-    self.font = ("Comfortaa", 14) # police par défaut
-    Utilisateurs().creationTable() # on créer la base de donnée si elle n'existe pas déjà
-    self.parent = Tk() # on créer notre fenêtre principale
-
-    self._interfaceConnexion() # on créer la variable `self.f` qui est la frame a affiché
-    self.f.grid() # on affiche la frame
-
-    self.parent.mainloop() # on affiche la fenêtre
-
-
-
-def motDePasseCorrect(self, motDPasse: str) ‑> tuple -
-
-

Détermine si un mot de passe suit la politique du programme ou non.

-
- -Expand source code - -
def motDePasseCorrect(self, motDPasse: str) -> tuple:
-    """Détermine si un mot de passe suit la politique du programme ou non."""
-    if len(motDPasse) == 0: # si le champs est vide
-        return (False, "Mot de passe incorrect.")
-    if len(motDPasse) < 8: # si le mot de passe est plus petit que 8 caractères
-        return (False, "Un mot de passe doit faire 8 caractères minimum.")
-    """
-    Pour le regex, je réfléchie comme dans la fonction `self.connexion`.
-    J'utilises pas `match` parce que je suis plus à l'aise avec `sub`.
-    """
-    if not sub(r"[A-Z]", '', motDPasse) != motDPasse:
-        return (False, "Un mot de passe doit au moins contenir une lettre majuscule.")
-    if not sub(r"[a-z]", '', motDPasse) != motDPasse:
-        return (False, "Un mot de passe doit au moins contenir une lettre minuscule.")
-    if not sub(r" *?[^\w\s]+", '', motDPasse) != motDPasse:
-        return (False, "Un mot de passe doit au moins contenir un caractère spécial.")
-
-    return (True,) # si aucun des tests précédents n'est valide, alors le mot de passe est valide
-
-
-
-
-
-
-
- -
- - - \ No newline at end of file diff --git a/documentation/GesMag/users.html b/documentation/GesMag/users.html deleted file mode 100644 index 06e83d4..0000000 --- a/documentation/GesMag/users.html +++ /dev/null @@ -1,357 +0,0 @@ - - - - - - -GesMag.users API documentation - - - - - - - - - - - -
-
-
-

Module GesMag.users

-
-
-
- -Expand source code - -
from db import BaseDeDonnees
-
-class Utilisateurs(BaseDeDonnees):
-    """Gère une table "utilisateurs" pour une base de donnée donné."""
-    def __init__(self):
-        super().__init__(r"utilisateurs.sqlite3")
-
-    def creationTable(self) -> None:
-        """Créer la table qui stocker les utilisateurs."""
-        requete = """
-                  CREATE TABLE IF NOT EXISTS utilisateurs (
-                      id INTEGER PRIMARY KEY,
-                      pseudo TEXT,
-                      passe TEXT,
-                      metier INTEGER,
-                      nom TEXT,
-                      prenom TEXT,
-                      naissance TEXT,
-                      adresse TEXT,
-                      postal INTEGER
-                  );
-                  """
-        self.requete(requete)
-        # Ajout d'un utilisateur par défaut si aucun utilisateur n'existe dans la base de donnée
-        if len(self.listUtilisateurs()) == 0:
-            self.ajoutUtilisateurs(
-                pseudo="admin",
-                passe="P@ssword",
-                metier=0,
-                nom="Admin",
-                prenom="Admin",
-                naissance="2000/10/09",
-                adresse="12 Rue de Montmartre",
-                postal=46800
-            )
-
-    def ajoutUtilisateurs(self, pseudo: str, passe: str, metier: int, nom: str, prenom: str, naissance: str, adresse: str, postal: str) -> list:
-        """Ajoute un utilisateur et retourne l'ID de ce dernier."""
-        requete = """
-                  INSERT INTO utilisateurs (
-                      pseudo, passe, metier, nom, prenom, naissance, adresse, postal
-                  ) VALUES (
-                      ?, ?, ?, ?, ?, ?, ?, ?
-                  );
-                  """
-        self.requete(requete, [pseudo, passe, metier, nom, prenom, naissance, adresse, postal])
-        return self.affichageResultat(self.requete("SELECT last_insert_rowid();"))
-
-    def suppressionUtilisateurs(self, pseudo: str) -> None:
-        """Supprime un utilisateur."""
-        requete = """
-                  DELETE FROM utilisateurs
-                  WHERE pseudo = ?
-                  """
-        self.requete(requete, pseudo)
-
-    def verificationIdentifiants(self, pseudo: str, motDePasse: str) -> bool:
-        """Renvoie vrai ou faux si les identifiants données sont bons."""
-        requete = """
-                  SELECT EXISTS (
-                      SELECT 1 FROM utilisateurs
-                      WHERE pseudo = ? AND passe = ?
-                  )
-                  """
-        # Vrai si le premier élément que renvoie la requête au dessus est 1
-        return True if self.affichageResultat(self.requete(requete, [pseudo, motDePasse]))[0][0] == 1 else False
-
-    def listUtilisateurs(self) -> list:
-        """Retourne la liste des nom d'utilisateurs."""
-        requete = """
-                  SELECT pseudo FROM utilisateurs
-                  """
-        # i[0] parce que sinon ça renvoie des Tuple qui ressemble à ça : `(Utilisateur,)`
-        return [i[0] for i in self.affichageResultat(self.requete(requete))]
-
-
-
-
-
-
-
-
-
-

Classes

-
-
-class Utilisateurs -
-
-

Gère une table "utilisateurs" pour une base de donnée donné.

-
- -Expand source code - -
class Utilisateurs(BaseDeDonnees):
-    """Gère une table "utilisateurs" pour une base de donnée donné."""
-    def __init__(self):
-        super().__init__(r"utilisateurs.sqlite3")
-
-    def creationTable(self) -> None:
-        """Créer la table qui stocker les utilisateurs."""
-        requete = """
-                  CREATE TABLE IF NOT EXISTS utilisateurs (
-                      id INTEGER PRIMARY KEY,
-                      pseudo TEXT,
-                      passe TEXT,
-                      metier INTEGER,
-                      nom TEXT,
-                      prenom TEXT,
-                      naissance TEXT,
-                      adresse TEXT,
-                      postal INTEGER
-                  );
-                  """
-        self.requete(requete)
-        # Ajout d'un utilisateur par défaut si aucun utilisateur n'existe dans la base de donnée
-        if len(self.listUtilisateurs()) == 0:
-            self.ajoutUtilisateurs(
-                pseudo="admin",
-                passe="P@ssword",
-                metier=0,
-                nom="Admin",
-                prenom="Admin",
-                naissance="2000/10/09",
-                adresse="12 Rue de Montmartre",
-                postal=46800
-            )
-
-    def ajoutUtilisateurs(self, pseudo: str, passe: str, metier: int, nom: str, prenom: str, naissance: str, adresse: str, postal: str) -> list:
-        """Ajoute un utilisateur et retourne l'ID de ce dernier."""
-        requete = """
-                  INSERT INTO utilisateurs (
-                      pseudo, passe, metier, nom, prenom, naissance, adresse, postal
-                  ) VALUES (
-                      ?, ?, ?, ?, ?, ?, ?, ?
-                  );
-                  """
-        self.requete(requete, [pseudo, passe, metier, nom, prenom, naissance, adresse, postal])
-        return self.affichageResultat(self.requete("SELECT last_insert_rowid();"))
-
-    def suppressionUtilisateurs(self, pseudo: str) -> None:
-        """Supprime un utilisateur."""
-        requete = """
-                  DELETE FROM utilisateurs
-                  WHERE pseudo = ?
-                  """
-        self.requete(requete, pseudo)
-
-    def verificationIdentifiants(self, pseudo: str, motDePasse: str) -> bool:
-        """Renvoie vrai ou faux si les identifiants données sont bons."""
-        requete = """
-                  SELECT EXISTS (
-                      SELECT 1 FROM utilisateurs
-                      WHERE pseudo = ? AND passe = ?
-                  )
-                  """
-        # Vrai si le premier élément que renvoie la requête au dessus est 1
-        return True if self.affichageResultat(self.requete(requete, [pseudo, motDePasse]))[0][0] == 1 else False
-
-    def listUtilisateurs(self) -> list:
-        """Retourne la liste des nom d'utilisateurs."""
-        requete = """
-                  SELECT pseudo FROM utilisateurs
-                  """
-        # i[0] parce que sinon ça renvoie des Tuple qui ressemble à ça : `(Utilisateur,)`
-        return [i[0] for i in self.affichageResultat(self.requete(requete))]
-
-

Ancestors

-
    -
  • db.BaseDeDonnees
  • -
-

Methods

-
-
-def ajoutUtilisateurs(self, pseudo: str, passe: str, metier: int, nom: str, prenom: str, naissance: str, adresse: str, postal: str) ‑> list -
-
-

Ajoute un utilisateur et retourne l'ID de ce dernier.

-
- -Expand source code - -
def ajoutUtilisateurs(self, pseudo: str, passe: str, metier: int, nom: str, prenom: str, naissance: str, adresse: str, postal: str) -> list:
-    """Ajoute un utilisateur et retourne l'ID de ce dernier."""
-    requete = """
-              INSERT INTO utilisateurs (
-                  pseudo, passe, metier, nom, prenom, naissance, adresse, postal
-              ) VALUES (
-                  ?, ?, ?, ?, ?, ?, ?, ?
-              );
-              """
-    self.requete(requete, [pseudo, passe, metier, nom, prenom, naissance, adresse, postal])
-    return self.affichageResultat(self.requete("SELECT last_insert_rowid();"))
-
-
-
-def creationTable(self) ‑> None -
-
-

Créer la table qui stocker les utilisateurs.

-
- -Expand source code - -
def creationTable(self) -> None:
-    """Créer la table qui stocker les utilisateurs."""
-    requete = """
-              CREATE TABLE IF NOT EXISTS utilisateurs (
-                  id INTEGER PRIMARY KEY,
-                  pseudo TEXT,
-                  passe TEXT,
-                  metier INTEGER,
-                  nom TEXT,
-                  prenom TEXT,
-                  naissance TEXT,
-                  adresse TEXT,
-                  postal INTEGER
-              );
-              """
-    self.requete(requete)
-    # Ajout d'un utilisateur par défaut si aucun utilisateur n'existe dans la base de donnée
-    if len(self.listUtilisateurs()) == 0:
-        self.ajoutUtilisateurs(
-            pseudo="admin",
-            passe="P@ssword",
-            metier=0,
-            nom="Admin",
-            prenom="Admin",
-            naissance="2000/10/09",
-            adresse="12 Rue de Montmartre",
-            postal=46800
-        )
-
-
-
-def listUtilisateurs(self) ‑> list -
-
-

Retourne la liste des nom d'utilisateurs.

-
- -Expand source code - -
def listUtilisateurs(self) -> list:
-    """Retourne la liste des nom d'utilisateurs."""
-    requete = """
-              SELECT pseudo FROM utilisateurs
-              """
-    # i[0] parce que sinon ça renvoie des Tuple qui ressemble à ça : `(Utilisateur,)`
-    return [i[0] for i in self.affichageResultat(self.requete(requete))]
-
-
-
-def suppressionUtilisateurs(self, pseudo: str) ‑> None -
-
-

Supprime un utilisateur.

-
- -Expand source code - -
def suppressionUtilisateurs(self, pseudo: str) -> None:
-    """Supprime un utilisateur."""
-    requete = """
-              DELETE FROM utilisateurs
-              WHERE pseudo = ?
-              """
-    self.requete(requete, pseudo)
-
-
-
-def verificationIdentifiants(self, pseudo: str, motDePasse: str) ‑> bool -
-
-

Renvoie vrai ou faux si les identifiants données sont bons.

-
- -Expand source code - -
def verificationIdentifiants(self, pseudo: str, motDePasse: str) -> bool:
-    """Renvoie vrai ou faux si les identifiants données sont bons."""
-    requete = """
-              SELECT EXISTS (
-                  SELECT 1 FROM utilisateurs
-                  WHERE pseudo = ? AND passe = ?
-              )
-              """
-    # Vrai si le premier élément que renvoie la requête au dessus est 1
-    return True if self.affichageResultat(self.requete(requete, [pseudo, motDePasse]))[0][0] == 1 else False
-
-
-
-
-
-
-
- -
- - - \ No newline at end of file diff --git a/documentation/documentation.tex b/documentation/documentation.tex new file mode 100644 index 0000000..b4dcf2b --- /dev/null +++ b/documentation/documentation.tex @@ -0,0 +1,180 @@ +\documentclass{article} + +\usepackage[french]{babel} % français +\usepackage[T1]{fontenc} % encodage +\usepackage[hidelinks]{hyperref} % liens cliquable dans la table des matières +\usepackage{graphicx} % images +\usepackage{listingsutf8} % intégration code +\usepackage{xcolor} % couleurs personnalisés +\usepackage{geometry} % change les dimensions de la page +\usepackage{enumitem} % liste personnalisée +\usepackage{amssymb, pifont} % police (todolist) + +\geometry{ % définition taille pages + a4paper, + left=20mm, + top=20mm +} + +% définition de la liste de choses à faire/faites (https://tex.stackexchange.com/q/247681/) +\newlist{todolist}{itemize}{3} +\setlist[todolist]{label=$\square$} +\newcommand{\fait}{\rlap{\raisebox{0.3ex}{\hspace{0.4ex}\scriptsize \ding{56}}}$\square$} + +% définition blocs de codes +\lstset{ + breaklines=true, + extendedchars=true, + inputencoding=utf8/latin1 +} + +% Python definition (c) 1998 Michael Weber +% Additional definitions (2013) Alexis Dimitriadis +% modified by https://tex.stackexchange.com/questions/235783/listings-recognize-numbers-and-1e-3 +\definecolor{maroon}{cmyk}{0, 0.87, 0.68, 0.32} +\definecolor{halfgray}{gray}{0.55} +\definecolor{ipython_frame}{RGB}{207, 207, 207} +\definecolor{ipython_bg}{RGB}{247, 247, 247} +\definecolor{ipython_red}{RGB}{186, 33, 33} +\definecolor{ipython_green}{RGB}{0, 128, 0} +\definecolor{ipython_cyan}{RGB}{64, 128, 128} +\definecolor{ipython_purple}{RGB}{170, 34, 255} +\lstdefinelanguage{iPython}{ + morekeywords={access,and,break,class,continue,def,del,elif,else,except,exec,finally,for,from,global,if,import,in,is,lambda,not,or,pass,print,raise,return,try,while}, + morekeywords=[2]{abs,all,any,basestring,bin,bool,bytearray,callable,chr,classmethod,cmp,compile,complex,delattr,dict,dir,divmod,enumerate,eval,execfile,file,filter,float,format,frozenset,getattr,globals,hasattr,hash,help,hex,id,input,int,isinstance,issubclass,iter,len,list,locals,long,map,max,memoryview,min,next,object,oct,open,ord,pow,property,range,raw_input,reduce,reload,repr,reversed,round,set,setattr,slice,sorted,staticmethod,str,sum,super,tuple,type,unichr,unicode,vars,xrange,zip,apply,buffer,coerce,intern}, + sensitive=true, + morecomment=[l]\#, + morestring=[b]', + morestring=[b]", + morecomment=[s]{"""}{"""}, + morestring=[s]{'''}{'''}, + morestring=[s]{r'}{'}, + morestring=[s]{r"}{"}, + morestring=[s]{r'''}{'''}, + morestring=[s]{r"""}{"""}, + morestring=[s]{u'}{'}, + morestring=[s]{u"}{"}, + morestring=[s]{u'''}{'''}, + morestring=[s]{u"""}{"""}, + literate= + *{+}{{{\color{ipython_purple}+}}}1 + {-}{{{\color{ipython_purple}-}}}1 + {*}{{{\color{ipython_purple}$^\ast$}}}1 + {/}{{{\color{ipython_purple}/}}}1 + {^}{{{\color{ipython_purple}\^{}}}}1 + {?}{{{\color{ipython_purple}?}}}1 + {!}{{{\color{ipython_purple}!}}}1 + {\%}{{{\color{ipython_purple}\%}}}1 + {<}{{{\color{ipython_purple}<}}}1 + {>}{{{\color{ipython_purple}>}}}1 + {|}{{{\color{ipython_purple}|}}}1 + {\&}{{{\color{ipython_purple}\&}}}1 + {~}{{{\color{ipython_purple}~}}}1 + {==}{{{\color{ipython_purple}==}}}2 + {<=}{{{\color{ipython_purple}<=}}}2 + {>=}{{{\color{ipython_purple}>=}}}2 + {+=}{{{+=}}}2 + {-=}{{{-=}}}2 + {*=}{{{$^\ast$=}}}2 + {/=}{{{/=}}}2, + commentstyle=\color{ipython_cyan}\ttfamily, + stringstyle=\color{ipython_red}\ttfamily, + keepspaces=true, + showspaces=false, + showstringspaces=false, + rulecolor=\color{ipython_frame}, + frame=single, + frameround={t}{t}{t}{t}, + framexleftmargin=6mm, + numbers=left, + numberstyle=\tiny\color{halfgray}, + backgroundcolor=\color{ipython_bg}, + basicstyle=\scriptsize\ttfamily, + keywordstyle=\color{ipython_green}\ttfamily, + escapechar=\¢, + escapebegin=\color{ipython_green}, +} + +\author{Anri Kennel} +\title{Programmation d'interfaces $\cdot$ Projet final} +\date{} + +\begin{document} + \maketitle + \tableofcontents + + \begin{center} + \emph{Les explications sont en commentaire du code.} + \end{center} + \clearpage + + \section{Consigne} + + \begin{todolist} + \item[\fait] Page de login \texttt{/1.5} + \begin{todolist} + \item[\fait] Nom d'utilisateur ne contient que des lettres et des chiffres + \item[\fait] Mot de passe de minimum 8 caractères dont 1 caractère spécial, une majuscule et une minuscule (possibilité d'afficher ou non en clair le mot de passe) + \item[\fait] Un bouton de connexion (possibilité aussi d'utiliser la touche Entrer pour aller plus vite) qui permet de se rendre sur l'interface Caissier ou Manager + \item[\fait] Un bouton pour quitter l'application + \end{todolist} + \item Page de manager (définit par un nom d'utilisateur et un mot de passe) \texttt{/7.5} + \begin{todolist} + \item Peut ajouter et supprimer un caissier + \item Peut voir la liste des caissiers + \item Un suivi des ventes + \item Un bouton pour vider tous les champs de saisie + \item Un bouton pour quitter l'application + \item Un bouton pour se mettre en "mode caissier" + \end{todolist} + \item Page de caissier (définit par un identifiant, un nom d'utilisateur, un mot de passe, un nom, un prenom, une date de naissance, une adresse et une code postal) \texttt{/6} + \begin{todolist} + \item Afficher le stock disponible + \begin{todolist} + \item 4 rayons de chacun au moins 10 articles de votre choix (fruits/légumes, boulangerie, boucherie/poissonnerie ou produits d'entretien) + \item Au clic sur le produit, l'identifiant, le nom, la quantité en stock et le prix s'affichent + \item Possibilité de rajouter des produits en stock + \end{todolist} + \item Affichage d'un ticket de caisse + \begin{todolist} + \item Date de vente + \item ID, nom, quantité, prix des produits achetés + \item Prix total + \item Un bouton pour valider + \end{todolist} + \item Interface d'export des statistiques (stock le montant total de vente par jour) + \end{todolist} + \end{todolist} + + Avec à savoir : + \begin{todolist} + \item Ergonomie \texttt{/2} + \item[\fait] Utilisateurs stockés dans la base de donnée \texttt{/2} + \begin{todolist} + \item[\fait] Possibilité de recréer la base de donnée automatiquement si elle n'existe plus + \end{todolist} + \item Ajout d'autres fonctionnalités \texttt{/1} + \begin{todolist} + \item Heure de connexion stricte pour les caissiers + \item Meilleur caissier (avec le plus de ventes sur la journée/semaine précédente par exemple) + \item Exporter le ticket de caisse en format image + \end{todolist} + \item[\fait] Lisibilité du code + \begin{todolist} + \item[\fait] Toutes les fonctions sont nommés et typés \texttt{(j'utilises Python 3.9.7)} + \end{todolist} + \end{todolist} + + + \clearpage + \section{Code} + \subsection[\texttt{main.py}]{\texttt{main.py}, fichier principale} + \begin{lstinputlisting}[language=iPython]{../main.py}\end{lstinputlisting} + + \subsection[\texttt{db.py}]{\texttt{db.py}, gère la communication avec la base de donnée en sa globalité} + \begin{lstinputlisting}[language=iPython]{../db.py}\end{lstinputlisting} + + \subsection[\texttt{users.py}]{\texttt{users.py}, implante la partie pour les utilisateurs} + \begin{lstinputlisting}[language=iPython]{../users.py}\end{lstinputlisting} + +\end{document}