import tkinter.messagebox as messagebox from tkinter import Scrollbar, Listbox, Tk, Frame, Label, Button, Entry from re import sub from users import Utilisateurs # import de mon fichier pour gérer la base de donnée class GesMag: """Programme de Gestion d'une caise de magasin.""" def __init__(self) -> None: """Instancie quelques variables pour plus de clareté.""" self.parent = Tk() # fenêtre affiché à l'utilisateur self.parent.resizable(False, False) # empêche la fenêtre d'être redimensionnée self.f = Frame(self.parent) # `Frame` affiché à l'écran def demarrer(self) -> None: """Lance le programme GesMag.""" 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._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 utilisateurBaseDeDonnee = Utilisateurs().verificationIdentifiants(utilisateur.lower(), motDePasse) if utilisateurBaseDeDonnee[0] > 0: if utilisateurBaseDeDonnee[1] == 0: # si le métier est "Manager" self._interfaceManager(utilisateurBaseDeDonnee[0]) elif utilisateurBaseDeDonnee[1] == 1: # si le métier est "Caissier" self._interfaceCaissier(utilisateurBaseDeDonnee[0]) else: messagebox.showerror("Erreur", "Une erreur est survenue : métier inconnue.") else: messagebox.showerror("Erreur", "Utilisateur ou mot de passe incorrect.") def dimensionsFenetre(self, nouveauX: int, nouveauY: int): """Permet de changer les dimensions de la fenêtre parent et la place au centre de l'écran.""" largeur = self.parent.winfo_screenwidth() hauteur = self.parent.winfo_screenheight() x = (largeur // 2) - (nouveauX // 2) y = (hauteur // 2) - (nouveauY // 2) self.parent.geometry(f"{nouveauX}x{nouveauY}+{x}+{y}") def _interfaceConnexion(self): """Affiche l'interface de connexion.""" # Paramètres de la fenêtre self.dimensionsFenetre(400, 600) self.parent.title("Fenêtre de connexion") # Suppresssion de la dernière Frame self.f.destroy() # Instanciation d'une nouvelle Frame, on va donc ajouter tout nos widgets à cet Frame self.f = Frame(self.parent) self.f.grid() # 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("", 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("", tentativeDeConnexion) Button(self.f, text="Quitter", font=self.font, command=quit).grid(column=0, row=6, columnspan=4, pady=20) self._interfaceManager(1) # DEBUG: affiche directement l'interface du Manager def _interfaceCaissier(self, id: int): """Affiche l'interface du caissier.""" caissier = Utilisateurs().recuperationUtilisateur(id=id)[0] self.parent.title(f"Caissier {caissier[3]} {caissier[4]}") self.dimensionsFenetre(1280, 720) # Suppresssion de la dernière Frame self.f.destroy() # Instanciation d'une nouvelle Frame, on va donc ajouter tout nos widgets à cet Frame self.f = Frame(self.parent) self.f.grid() def _interfaceManager(self, id: int): """Affiche l'interface du manager.""" manager = Utilisateurs().recuperationUtilisateur(id=id) self.parent.title(f"Manager {manager['nom']} {manager['prenom']}") self.dimensionsFenetre(530, 720) # Suppresssion de la dernière Frame self.f.destroy() # Instanciation d'une nouvelle Frame, on va donc ajouter tout nos widgets à cet Frame self.f = Frame(self.parent) self.f.grid() Label(self.f, text="Interface Manager", font=(self.font[0], 20)).grid(column=0, row=0) Button(self.f, text="Se déconnecter", font=self.font, command=self._interfaceConnexion).grid(column=1, row=0, padx=50) Label(self.f).grid(row = 1, pady=10) # séparateur def __ajouterUtilisateur(metier: int): """Permet de créer un nouvel utilisateur, manager (`metier = 0`) et caissier (`metier = 1`).""" print(f"ajout d'un utilisateur (métier = {metier})") # ouvrir un toplevel? def __retirerUtilisateur(metier: int): """Permet de supprimer un utilisateur existant, manager (`metier = 0`) et caissier (`metier = 1`).""" print(f"retirer un utilisateur (métier = {metier})") # ouvrir un toplevel? def __afficherInformationsUtilisateur(_): """Permet d'afficher les informations d'un utilisateur""" element = listeUtilisateurs.curselection() if len(element) == 0: # si aucun élément n'est selectionné return print(Utilisateurs().recuperationUtilisateur(pseudo=listeUtilisateurs.get(element[0]))) # ouvrir un toplevel? Button(self.f, text="Ajouter un caissier", font=self.font, command=lambda: __ajouterUtilisateur(1)).grid(column=0, row=2) Button(self.f, text="Retirer un caissier", font=self.font, command=lambda: __retirerUtilisateur(1)).grid(column=1, row=2) Label(self.f).grid(row = 3, pady=10) # séparateur # Liste des utilisateurs Label(self.f, text="Liste des utilisateurs", font=self.font).grid(column=0, row=4) # titre # On définit une barre pour pouvoir scroller dans la liste scroll = Scrollbar(self.f, orient="vertical") scroll.grid(column=0, row=5, sticky="nse") # On définit notre liste et on la lie à notre `Scrollbar` listeUtilisateurs = Listbox(self.f, width=25, height=4, yscrollcommand=scroll.set) scroll['command'] = listeUtilisateurs.yview # On ajoute nos utilisateurs à notre liste for idx, utilisateur in enumerate(Utilisateurs().listUtilisateurs()): listeUtilisateurs.insert(idx, utilisateur) listeUtilisateurs.grid(column=0, row=5) listeUtilisateurs.bind('', __afficherInformationsUtilisateur) # on affiche l'utilisateur quand on double-clique dessus 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") GesMag().demarrer()