From 3ec7b207d954b5d4786ca0bd6d400c544cd284f8 Mon Sep 17 00:00:00 2001 From: maxime Date: Tue, 24 Mar 2026 23:06:07 +0100 Subject: [PATCH] 1.1 --- README.md | 2 +- flask/__pycache__/add_user.cpython-311.pyc | Bin 0 -> 3018 bytes flask/__pycache__/auth.cpython-311.pyc | Bin 2906 -> 4729 bytes flask/__pycache__/led.cpython-311.pyc | Bin 0 -> 619 bytes flask/__pycache__/log.cpython-311.pyc | Bin 0 -> 1152 bytes flask/add_user.py | 29 +- flask/auth.py | 32 +- flask/bouton.py | 22 - flask/led.py | 22 + flask/log.py | 23 +- flask/main.py | 69 ++- flask/templates/admin.html | 497 +++++++++++++++++++++ flask/templates/dashboard.html | 39 +- flask/templates/index.html | 6 +- flask/templates/log.html | 471 +++++++++++++++++++ run_flask.sh | 2 + 16 files changed, 1128 insertions(+), 86 deletions(-) create mode 100644 flask/__pycache__/add_user.cpython-311.pyc create mode 100644 flask/__pycache__/led.cpython-311.pyc create mode 100644 flask/__pycache__/log.cpython-311.pyc delete mode 100644 flask/bouton.py create mode 100644 flask/led.py create mode 100644 flask/templates/admin.html create mode 100644 flask/templates/log.html diff --git a/README.md b/README.md index d6c6405..961bc41 100644 --- a/README.md +++ b/README.md @@ -1 +1 @@ -# loustique-home +Toujours run "run_flasj.sh par facilité et pour que script rende $SUDO_USERS ou $USER propriétaire du fichier log diff --git a/flask/__pycache__/add_user.cpython-311.pyc b/flask/__pycache__/add_user.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dc320a38bcd83484160114052af44068eb7c6c19 GIT binary patch literal 3018 zcmb_eO>7fK6rS~Zz3bn^#14TFx&l%#NpSc}=wG6cI3iM;pg2$wsYM&_lGv=hVRqd7 z$Z6e*gF%sKQ7WP$)SS{Fdg!4&RHBChz4T;DK3FTIqN+HwCs(u*<RDxynQqK=Ci-@dR++QAK`v{kVEJ<+Ofp8ZahwaaRbRnW>hq~)-t1v*|&|_ptY%N z(mrZu=p3tZNp6%gZANvBI$+GM@=1P_XOImk_GR#P$9e|>9CsOw3bF&VQ)Z$l#Q#ob z2SbeERy9dJFKa|eeE?lSmWV>)Nd;_H)y88LFJQRgVc~iFGee_wA_A=?iHc2NmzE?b z-V~XUZOgFVJJy~NaawZ-J!cIo+pE_s!&~nB-LOEUt#lH|rke$_We(hRzK&0@j z$sEd{DB6pNH2`g*a!!c~ZXd$O<``150h8Ss<|evjtB!*~#J_<_R8I1F=yQ-abIga3 zQPFj4ikU*w>^U^Wggk==-*@u-siEk|tn=`Z&O_}`4x3}AhlWSue|QiwduO7NVZ#m3 z(>>AXyFw zrD563HEB%J6@!mWNLW|MY<&b{C5=T{5o1~^rA)`Ql=!+BavA*OOmarQqym;s#E4Tz&c3&M8hGQVW(aUM$u_DisIAm z@Pw9B!bxcwazEUs#nMS7MfC7^oJ^$0!m5_mN&He;(c4Vi1y#~7h9y}(Pxo|aa>lU7 zQ*nYt@J4Tm{wt^~D%*TqV6~=x{-afY-NKH=*Oo38{6~uZBdh+v=fex<7H3xW6@uYn zFkJAr7ya$)sDi(_=x<&PZU@9%A=p+7wykw$3c*k@7+MX~FAOZID+7f!A}nycp644bu4jv|}ZCn}tgVU{+HgV%KdZmDL5O{j$3LRG)3 z`o_-LohZXDRqmv>wByzm9%O*AA!@kH&&pQ+5XTGQWZq=8of{q# zKFdy2SPWRLcT3E*7D^Uq%+K=MxtAX+WR=BvdtbVD%X7#%*gwkw1Gb%*9T^w|#vBm` z21ka(o-~;d4^X~HNlB$uw0N*p?AKB;%2;}<7{dzu0L$kk5)#k$ynQAT6%RDS_{I~O z^`0SdHLe2=m~#ItyC1yLqzQ>qLQ9kTw?}5TZ-xMi>O@KrN~C_1q727a49`pw!!aT0 z6O&VhLrKLn8HjjXN$HXb6R|YbfjoI-T8X8Jg6SPH*pvp?n3hZe*O`P0w0A)>xR|QJ zz5;;3J1EdMkRr-Bj*}UagYhmJ9&ZTN?lJxGGVEAW72HHkGZ00_uhI^W6`)$8=sfhq zHNmgY8Ns4ld>FdatKJXyK8se}HCH<3JFn(-`leAIGuwFA`JgHS-16Q;X(_nRVtjyNw=0 zADN%?sqkh}lhdlwg*#x3{;kumgDSHO!<3LOYnDxhH*1y>+MTbiCDfF!t|jEmnx%y5 i^40Yra%bHidoP2pvb~0ZU&e~s6JX%bpH=ucg!M1p<%`4s literal 0 HcmV?d00001 diff --git a/flask/__pycache__/auth.cpython-311.pyc b/flask/__pycache__/auth.cpython-311.pyc index 27b1fccd596268c78ffe9b06f3cabc1b0d9a5888..eb54ede43e415d1327e38fef23d48b3be71ba3d4 100644 GIT binary patch literal 4729 zcmcIoUu+Y}8K2$t+G~4l$FWTUG~htMIE4H`DO`ag%HINa2S=RhE-45Z?XZ z5X%9#;=!Ou^bl1dm6M`-;Bw+r-CNb_Dj~w1PJP;~R;smn~j{2ZHpieJ%cH8$$oYg=!)z$_oyZCBz|)NT7-GotPku zGC4uQolH=(mI(_{Zlfn?sG}0rS?h$AKqTTVk6?ty)o~HnS#F~V8%Kj=I4ejyM?_HA z_8i-s4->jGAw;<=oFMbbUqO*d2vae$KPXQ4QSf{5R|5NHM>5>2X~xuLx>|?O47N8C zM{wjLnBC**43TWFwjs1dABwZo_jv?QdHlbgL~qN=x-Bc)wyYS=Uhn7Ejz?DT6n^Ej zfU+op_9MAk0rwd*PBW%m8xngL2-#CJ9({y`QGf+-mq1-Obe2%TT+4uGA;3<&ZMG} zG$)9h&TvsVdNnHXx-B*x6(wHI>=+hBJ}m}0J{S{{N&ZG$NCr;?!w%h+nxCDQt|!12 zH^gL}6eQg`#pA`QQ}Lv%Q@kkZ4Hr_p7?q)4Gy#JNqE4qoXca9GE}aGwK@5|+1&^W= zyo6U{F!=gp*R(Lpcg;p`#Njq1#L}~TQkJ@=;_`I*YF9!?OLF{rnwO3kc9V&ybge6z zmZv*Y^SULTjLYI)7zyud=^r3+s6@JGf6=pJ@mA66d$4o)XDioK?@`TrwCMH!ZuG(U z^89L>8tBpjU8=WR^LAIPRPO=Jd!QI-0*eJTa6}6nDHrC|Kv)Zei~b!C&Mqfb&#L}o zn*UhIWovN!8-e%_7I{ml0X6vZ&R0ce%ryU^2J{=t3J)6Vc< z3$@llgB~;YI2hrzZJ@>&fUWAACP}K+4bn{zu*u z@s3P4f*3S$TwMDqElF`cjiKYs>R?I$x zCxW~r2W3%61(WGS#$I8O6TytDqDC%$h%S3qu|@Q)OWv6^|fifwmegC`bx-V-}$-qp?l@Vm$$yS_060b>eE7fPnv&deYX4W z{gJ=*N0hN&s{NO={!41}Wv%(L(WA(EmBxcA8`9X2!iI{hXYq^@IPnbw0 zd$QnbD*2J!bC12t-f=Iw^X>w}-gDe_++i2lym7tsAy=c)cvxjSG`2%wJ1T>nR@pv{ z?Nivkg0H#6zI~8aFI|ZBnT!{}j8_)GczI#DH811^mD!^)dlY6*h3*clv?`4UAgjzl zjX9_=2aSm4)A{s|5WcNlHi*y#PcRh6+g!s`*$pr7!9e@aakLiR5AxY@|44}X&KVxr zM}6088EHq~@1vpS`w)fo_V%CqsTlMz6Fw*!6nY4@)mtePj+r@f3J!SysAyXhN&ua0 zN}n9D5v0L#JJd;Xxj7!&!Z z%yUrY(_#1P}#i%&r;p($8WmqQD%U^rAe*FcG=mDYa|LJL`Isb5SS^^p3E zTs#EdpB95Fp5q5U#|tq`iD9_u7Ews>x})YL{v?%Te0nE4yLBR6IlCKp`Py+R5trnc zFq=A^X@ReTD|pIM=c$AcizcMgpj4aRhry*@5ILlH#>@GK=<>zo>kr3PdsZ)g-TN2m zNzapu&wBqf|Lwfea2DsP;S1=8GQJ9{n9ni3Q4DS|U|!q@Ruxi-CKBQyC~jm5ycf!J zVOhrywBdG{6R-tlgfb!6&4-C6py8+Rlc-He!JD_2NXJG}DD#2RbXH}~Y0No=Iag@d zvE;e$Q5#ydhSoe?D9a_qI!1Premvk? z^?Dn`8o26&@eGC87Qps112lR{`v=>or#qVm_fk)L2&^Bq42IC!UK;eZHVW&Z_8~77 zb{KC&w?SO-(MD{8i0anzzaJvTIWd5R@t*Lvox#OM?7u?daa@6k`ZaTER^ZYJ{STK SYa)Q>OwsGc#W#iF@P7f#Khg>S delta 1025 zcmZ`&O-vI(6rSyNccB%-tPNm=FQK0^Sw8Jnu=Av zm#XSTARj+{9=|Cp`9j?7rATLs3mNVeFu!GUW#LegpGSAaq#IC5aziL8EG<@6j~*>x ztqjV8?mmCNdXMAksqSi_wri!)sRiryiv>MFh~W@DY3QS7CSy#Fn;E@Vk7C-zU!!w; zpt>u5-%K0v^vL8mG=t`-lQuH8ML+P(-g-F118RMvTm1a>U$VAvr65O2$Rz|%;0IRo zzK&O&0Pt_%cmc=rIKJr*=ofcTmHDq7+JMNfio$?Qx7^jP7*DS%4YWpB z2~We^r9sb&xYh)PB5fHgCcHVC7E zu$+?yfTBc|;r|C4WFqrCc8U1(VcNtDrr(HoHm|FCjpjT||lhLe8-|3H^aLbC~piSgi#gc~Q`EbP+u=9|o$_wjqbc{4lvJsOQ5kVAZ^ z+z%l1hdZ8t@5lXB&?z(Bn5WR5)L4W_aT08i2=P7knnSq6aMkY!ipaUL%5n} zpD<@KKzp+8+Y;Uf`@r|Nk%{)a9z3|a8ZF*B=XRyN8n^F4Jd_k@$8F=bZn}J&(18n> zc(2>bwytIeBj$YvTM?dZcAO9+iI`|PgYs}ktr;Py(&}qkKKgp-An{u zt9!u-tJS)0D6i{uE1BOAwY*xDVP3^1!P~kwIwtBXhEk?EJw1^g9jl1GsnQLqw)kbL z>!J+6f)m=LT4{^c{>- znmdX2u{Z=?+VMpeU$mY!NzXCqKO+6R12!39WTZhxfa#bdj!5FOY?BltsRl_k`v$E7 zBfTfdA(qVkh}g*~mYlMR&AY=^k&(eBxpPcXM-$BVwO8jNetgUMZQX- QVBAvPmv%~)z=z9s0jog-i~s-t literal 0 HcmV?d00001 diff --git a/flask/add_user.py b/flask/add_user.py index de0bdda..0b5753d 100644 --- a/flask/add_user.py +++ b/flask/add_user.py @@ -4,6 +4,7 @@ import bcrypt from dotenv import load_dotenv from datetime import datetime import os +from log import log load_dotenv() @@ -20,32 +21,28 @@ def init(): return conn except pymysql.err.OperationalError as e: - print(f"❌ Erreur de connexion : {e}") + print(f"Erreur de connexion : {e}") + log.error(f"Erreur de connexion : {e}") return None -def add(): +def add_user(username, password, role): conn = init() if conn is None: return False - - username = input("Quel est l'username du nouvel utilisateur : ") - password = getpass.getpass("Quel est le password : ") - - # Hashage du mot de passe avec bcrypt + hashed = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()) + try: cursor = conn.cursor() - requete = "INSERT INTO Auth (username, password, created_at) VALUES (%s, %s, %s)" - cursor.execute(requete, (username, hashed, datetime.now())) + requete = "INSERT INTO Auth (username, password, Fonctions, created_at) VALUES (%s, %s, %s, %s)" + cursor.execute(requete, (username, hashed, role, datetime.now())) conn.commit() - print(f"✅ Utilisateur '{username}' ajouté avec succès !") - + log.info(f"Utilisateur '{username}' ({role}) ajouté") + return True except pymysql.err.IntegrityError: - print("❌ Cet utilisateur existe déjà") - + log.error(f"Utilisateur existant : {username}") + return False finally: cursor.close() - conn.close() - -add() + conn.close() \ No newline at end of file diff --git a/flask/auth.py b/flask/auth.py index 2f50de8..9fddf47 100644 --- a/flask/auth.py +++ b/flask/auth.py @@ -3,6 +3,7 @@ import getpass import bcrypt from dotenv import load_dotenv import os +from log import log load_dotenv() @@ -17,19 +18,16 @@ def init(): charset=os.getenv("DB_CHARSET", "utf8mb4") ) return conn - except pymysql.err.OperationalError as e: - print(f"❌ Erreur de connexion : {e}") + print(f"Erreur de connexion : {e}") + log.error(f"Erreur de connexion : {e}") return None -def login(username,password): - #username = input("Username : ") - #password = getpass.getpass("Mot de passe : ") +def login(username, password): conn = init() if conn is None: return False - try: cursor = conn.cursor() requete = "SELECT password FROM Auth WHERE username = %s" @@ -37,17 +35,33 @@ def login(username,password): resultat = cursor.fetchone() if resultat and bcrypt.checkpw(password.encode('utf-8'), resultat[0].encode('utf-8')): print("Connexion réussie") + log.info(f"Connexion réussie pour {username}") return True else: - print(" Identifiants incorrects") + print("Identifiants incorrects") + log.info("Identifiants incorrects,il est trop nul") return False - except pymysql.err.OperationalError as e: print(f"Erreur : {e}") + log.error(f"Erreur SQL : {e}") return False - finally: cursor.close() conn.close() +def get_users(): + conn = init() + if conn is None: + return [] + try: + cursor = conn.cursor() + cursor.execute("SELECT username, Fonctions, created_at FROM Auth") + users = cursor.fetchall() + return [{"username": u[0], "role": u[1], "created_at": str(u[2])} for u in users] + except pymysql.err.OperationalError as e: + log.error(f"Erreur get_users : {e}") + return [] + finally: + cursor.close() + conn.close() \ No newline at end of file diff --git a/flask/bouton.py b/flask/bouton.py deleted file mode 100644 index 0c1f546..0000000 --- a/flask/bouton.py +++ /dev/null @@ -1,22 +0,0 @@ -from time import * -from gpiozero import * -from signal import pause - -def led (): - print ('led allumé') - """ - print("One button to turn on or off") - - led = LED(17) - btn = Button(20, bounce_time=None) - - while True: - print('turn on') - led.on() - sleep(0.2) # to avoid bouncing - btn.wait_for_press() - print('turn off') - led.off() - sleep(0.2) # to avoid bouncing - btn.wait_for_press() - """ diff --git a/flask/led.py b/flask/led.py new file mode 100644 index 0000000..ef06c41 --- /dev/null +++ b/flask/led.py @@ -0,0 +1,22 @@ +from time import * +from gpiozero import * +from signal import pause +from log import log + +def led(utilisateur): + print('led allumé') + log.info(f'led allumé par {utilisateur}') + """ + print("One button to turn on or off") + led = LED(17) + btn = Button(20, bounce_time=None) + while True: + print('turn on') + led.on() + sleep(0.2) # to avoid bouncing + btn.wait_for_press() + print('turn off') + led.off() + sleep(0.2) # to avoid bouncing + btn.wait_for_press() + """ \ No newline at end of file diff --git a/flask/log.py b/flask/log.py index 80964c8..9e4a755 100644 --- a/flask/log.py +++ b/flask/log.py @@ -1,10 +1,19 @@ -import logging - -logging.basicConfig( -filename='/var/log/loustique.log', -filemode='a', -format='%(asctime)s - %(name)s - %(levelname)/s - %(message)/s', -level=logging.DEBUG) +import logging +def setup_log(): + logger = logging.getLogger("loustique") + logger.setLevel(logging.DEBUG) + + handler = logging.FileHandler('/var/log/loustique.log') + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + handler.setFormatter(formatter) + logger.addHandler(handler) + logger.propagate = False + werkzeug_logger = logging.getLogger('werkzeug') + werkzeug_logger.handlers = [] + werkzeug_logger.addHandler(handler) + werkzeug_logger.propagate = False + return logger +log = setup_log() \ No newline at end of file diff --git a/flask/main.py b/flask/main.py index 12acce6..77757f3 100644 --- a/flask/main.py +++ b/flask/main.py @@ -1,30 +1,71 @@ -from flask import Flask,render_template,request, jsonify -from bouton import led -import time +from flask import Flask, render_template, request, jsonify +from led import led import os -import auth +from add_user import add_user +import auth +import re + app = Flask(__name__) + +current_user = None + @app.route("/") def index(): - return render_template("index.html") + return render_template("index.html") @app.route("/login", methods=["POST"]) def login(): + global current_user data = request.get_json() succes = auth.login(data["username"], data["password"]) if succes: - return jsonify({"success": True, "message": "Connexion réussie"}) - + current_user = data["username"] + return jsonify({"success": True}) else: - return jsonify({"success": False, "message": "Identifiants incorrects"}) + return jsonify({"success": False}) + @app.route("/dashboard") def dashboard(): - return render_template("dashboard.html") + return render_template("dashboard.html") -@app.route("/led") +@app.route("/led", methods=["POST"]) def call_led(): - led() - return "import bouton réussi" -if __name__ == "__main__": - app.run(host="0.0.0.0", port=5000) + led(current_user) + return jsonify({"success": True}) +@app.route("/admin") +def admin_page(): + return render_template("admin.html") + +@app.route("/admin/logs") +def logs_page(): + return render_template("log.html") + + +@app.route("/admin/logs/data") +def get_logs(): + try: + with open('/var/log/loustique.log', 'r') as f: + lines = f.readlines() + ansi_escape = re.compile(r'\x1b\[[0-9;]*m') + lines = [ansi_escape.sub('', line) for line in lines[-200:]] + return jsonify({"success": True, "logs": lines}) + except Exception as e: + return jsonify({"success": False, "message": str(e)}) + +@app.route("/admin/add_user",methods=["POST"]) +@app.route("/admin/add_user", methods=["POST"]) +def create_user(): + data = request.get_json() + succes = add_user(data["username"], data["password"], data["role"]) + if succes: + return jsonify({"success": True}) + else: + return jsonify({"success": False, "message": "Utilisateur déjà existant"}) +@app.route("/admin/get_users") +def get_users(): + users = auth.get_users() + return jsonify({"success": True, "users": users}) + +if __name__ == "__main__": + app.run(host="0.0.0.0", port=5000) \ No newline at end of file diff --git a/flask/templates/admin.html b/flask/templates/admin.html new file mode 100644 index 0000000..6e91f6b --- /dev/null +++ b/flask/templates/admin.html @@ -0,0 +1,497 @@ + + + + + + Admin — Loustiques + + + + + + + +
+ + +
+
Créer un utilisateur
+
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+
+
+ +
+
+ +
+
Comptes existants
+
+
+
MA
+ + admin + +
+
+
+
+ +
+ + + + + \ No newline at end of file diff --git a/flask/templates/dashboard.html b/flask/templates/dashboard.html index dc22954..4b07254 100644 --- a/flask/templates/dashboard.html +++ b/flask/templates/dashboard.html @@ -156,16 +156,17 @@ animation: fadeUp 0.5s 0.45s ease both; } - .action-btn { - background: var(--panel); - border: 1px solid var(--border); - border-radius: 2px; - padding: 18px 20px; - cursor: pointer; - text-align: left; - transition: border-color 0.2s, background 0.2s, transform 0.1s; - position: relative; overflow: hidden; - } + .action-btn { + background: var(--panel); + border: 1px solid var(--border); + border-radius: 2px; + padding: 18px 20px; + cursor: pointer; + text-align: left; + transition: border-color 0.2s, background 0.2s, transform 0.1s; + position: relative; overflow: hidden; + color: var(--text); /* ← ajouter ça */ +} .action-btn:hover { border-color: var(--accent); background: rgba(124,106,255,0.05); } .action-btn:active { transform: scale(0.98); } @@ -261,6 +262,11 @@ État de la connexion + @@ -270,7 +276,7 @@ + + \ No newline at end of file diff --git a/run_flask.sh b/run_flask.sh index 4f9be13..2ba6893 100755 --- a/run_flask.sh +++ b/run_flask.sh @@ -47,4 +47,6 @@ Lancement du serveur FLASK EOF sleep 1 +touch /var/log/loustique.log +chown ${SUDO_USER}:${SUDO_USER} /var/log/loustique.log venv/bin/python ./flask/main.py