This repository has been archived on 2022-03-31. You can view files and clone it, but cannot push or open issues or pull requests.
GesMag/main.py

208 lines
10 KiB
Python
Raw Normal View History

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:
2021-11-19 18:52:58 +01:00
"""Programme de Gestion d'une caise de magasin."""
def __init__(self) -> None:
"""Instancie quelques variables pour plus de clareté."""
2021-11-20 00:11:59 +01:00
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
2021-11-19 00:47:01 +01:00
self.parent.mainloop() # on affiche la fenêtre
2021-11-19 00:47:01 +01:00
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):
2021-11-19 00:47:01 +01:00
"""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
2021-11-19 00:47:01 +01:00
# 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):
2021-11-19 20:14:41 +01:00
"""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}")
2021-11-19 00:47:01 +01:00
def _interfaceConnexion(self):
"""Affiche l'interface de connexion."""
# Paramètres de la fenêtre
self.dimensionsFenetre(400, 600)
2021-11-19 00:47:01 +01:00
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
2021-11-19 00:47:01 +01:00
self.f = Frame(self.parent)
self.f.grid()
# Affichage des labels et boutons
2021-11-19 00:47:01 +01:00
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é
2021-11-19 00:47:01 +01:00
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')
2021-11-19 00:47:01 +01:00
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')
2021-11-19 00:47:01 +01:00
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))
2021-11-19 00:47:01 +01:00
bouttonAffichageMDP = Button(self.f, text='👁', command=lambda: __afficherMDP(self))
bouttonAffichageMDP.grid(column=2, row=4, columnspan=2)
self.mdpVisible = False
2021-11-19 00:47:01 +01:00
bouton = Button(self.f, text="Se connecter", font=self.font, command=tentativeDeConnexion)
bouton.grid(column=0, row=5, columnspan=3, padx=ecart, pady=20)
2021-11-19 00:47:01 +01:00
bouton.bind("<Return>", tentativeDeConnexion)
2021-11-19 17:14:15 +01:00
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
2021-11-20 00:11:59 +01:00
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]}")
2021-11-20 00:11:59 +01:00
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('<Double-Button>', __afficherInformationsUtilisateur) # on affiche l'utilisateur quand on double-clique dessus
2021-11-20 00:11:59 +01:00
if __name__ == "__main__":
2021-11-20 00:11:59 +01:00
"""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()