Download app.py from vsmdvic/md: direct link, hf CLI and curl.
- Browser
- Download file 22 kB
-
https://huggingface.co/spaces/vsmdvic/md/resolve/main/app.py
- Command line
-
hf download hf://spaces/vsmdvic/md/app.py
-
curl -L -o app.py https://huggingface.co/spaces/vsmdvic/md/resolve/main/app.py
22 kB
| from flask import Flask, send_from_directory, request, jsonify, Response | |
| import requests, time, threading, json, os, datetime | |
| try: | |
| import jwt as pyjwt | |
| except ImportError: | |
| pyjwt = None | |
| app = Flask(__name__, static_folder='static') | |
| # ββ Firebase ββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| FIREBASE_API_KEY = "AIzaSyB9--Onx3-_YjD-YzblhZjaWSVVqTQJ1lU" | |
| FIRESTORE_BASE = "https://firestore.googleapis.com/v1/projects/vservers1/databases/(default)/documents" | |
| # ββ Google Drive ββββββββββββββββββββββββββββββββββββββββββββββ | |
| DRIVE_FOLDER_ID = "10c-8bQnYWCz-XgZZT4DfF67cQRsHipNo" | |
| DRIVE_SA = { | |
| "type": "service_account", | |
| "project_id": "vservers-40", | |
| "private_key_id": "f6cf589fcc62e4bab8e557032d3b6b483d12dc8d", | |
| "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCyrlnxR+n8hSkE\nYym7ewU6mUezQnUtBRuxWb/AupzIygJqHmMG7r4BztRkZ/dmBQXWmb9VhUpPmEvR\nP1tvXyz2Hh2wY7T/BdzYLOB3uQCXgRuNHFD104kRyPoQQPPuL7ctAHryrFh69614\n6xZ/4i+i8hbOwqjfe9tkHjuaKNrk7w9bCth1fmEPGyavTIy+8OL9RYIppapscFbn\nxOg9tP2VEaKH3GxvQ/Iafi9xQG1gmXT0rGES1+AoJ/O1eL/5SJO9zaZWSBQvq/eg\n0m+V4S2liXdnuvlivHEP1ucIqTc8jUtJ93fuDVhfqNgy/1pahWBNqypkLrnRIvhn\n8CwBWEQbAgMBAAECggEAGNtSXdNwRJXNr/OPkao6fv1l0RU0sc+dG53tpAUR3Ijl\nrxeNFSDPQ/ce6tzfuMyIFGOND3uca9g26+QRdzvZSF/GJ4ynWDbbkyMjEuSkpW7r\ng0TmKlyEG/pGd05h4Me4hsUjVXEOWgTsl/60QZQYpmVhMOA5l+VmDtZ52idG1EQF\nyQR2pydQRG1QPK14s/Se5L4aTe44bH7ri0uLbyw7y01pCyneBsIhzn2cj3rn78Om\n2ZZkv4rx0iySDhlL2KqwuxnNK+UFk3veFYkCJFVO/7rkg98qnSUUIT0jj6skF1Bq\nCF9xDWBrVEukDRyEi3gTtClGusb7XBxOvOWSYEGZ6QKBgQDlyv2nZXDzb0wANzYg\ngL6pITP42fR7E/fkfhU1F40eaQteV+ZVaKxO3oiz1l2L23XTp2qqgkrqYHome9U3\nYFZkDH4YfGuo1MZTIRmHKdbOmc41ZKH6lVyDkEhTe9dI+GuDwpLbDPDxi0Bt7dbe\n2aRzif60VnrtghctzvodTz8TJwKBgQDHDxqYQ+qDgWID2PERB26oOsfMa49sbSCV\n18+wmgx+ydM1UTW2aj3hRbDTxZT6GUw3Ngc23HxpPTyF20g4i0jM1LQ2DiOzI9Ij\ntyYBZzK9ec5J7+Z3gcP3irJpS8S2SoUWKD8kl50nbzXj+SjF26uDUci9fG10jtoR\nJ8Os3zHP7QKBgQDMCugayM93yT7R/jR4vfkOUuZENLyKwRtf77jDEOuEsj+fASwM\ncMp3qc/26ATel/tS+hiT2OfOn+Y238RezJNJeXJKKciq/GwyCnUReMw9XYMmE/pk\neFXSmL4wKwnpyHQnZhFiomYcBMssEYG3FciZs1HQLe4vkVElouCiP+jBBwKBgQCD\nfXOo3zwbUC0Js5VSFWHAWMvAOdDM460hriQwWSIl4nXVA2cCr11e4GU1DpAhQPK6\nicLsN2srLVs8ZKRpTYByZZMBHgfw/pmCJCpDxQKcbMiayJCpoptrej/uFDHF5KXT\nBBTpvAkAkpK7m8uWH0xFe5GpsXawBuj/ag/0sp655QKBgG3xU85qag5+89t5Wn8h\nn84B7ES734nbx6ya9/gDAWRIEvs8BHzgHaelXtfaXu+tm3cjqNsQtbprZZnNE7O6\nJoHIwiYFqlkgA9qGQnMyIT/vYCcJTtnokIoVdTN9IpMU7Lyo2rsxy0I0Q/rtUekg\nBOjMnuzHdt91ngSyg3BCbhKn\n-----END PRIVATE KEY-----\n", | |
| "client_email": "vservers-uploader@vservers-40.iam.gserviceaccount.com", | |
| "token_uri": "https://oauth2.googleapis.com/token", | |
| } | |
| _drive_token = None | |
| _drive_token_exp = 0 | |
| def get_drive_token(): | |
| global _drive_token, _drive_token_exp | |
| now = time.time() | |
| if _drive_token and now < _drive_token_exp - 60: | |
| return _drive_token | |
| if pyjwt is None: | |
| raise RuntimeError("PyJWT nu este instalat! AdaugΔ PyJWT==2.8.0 in requirements.txt") | |
| private_key = DRIVE_SA["private_key"] | |
| claim = { | |
| "iss": DRIVE_SA["client_email"], | |
| "scope": "https://www.googleapis.com/auth/drive", | |
| "aud": DRIVE_SA["token_uri"], | |
| "iat": int(now), "exp": int(now) + 3600, | |
| } | |
| signed = pyjwt.encode(claim, private_key, algorithm="RS256") | |
| if isinstance(signed, bytes): signed = signed.decode("utf-8") | |
| r = requests.post(DRIVE_SA["token_uri"], data={ | |
| "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer", | |
| "assertion": signed, | |
| }, timeout=15) | |
| if r.status_code != 200: | |
| raise RuntimeError(f"OAuth2 error {r.status_code}: {r.text}") | |
| _drive_token = r.json()["access_token"] | |
| _drive_token_exp = now + 3600 | |
| print(f"[DRIVE TOKEN] OK β obtinut token nou") | |
| return _drive_token | |
| def drive_test(): | |
| """Endpoint de diagnostic β verifica conexiunea Drive""" | |
| try: | |
| token = get_drive_token() | |
| r = requests.get( | |
| f"https://www.googleapis.com/drive/v3/files/{DRIVE_FOLDER_ID}", | |
| params={"fields": "id,name"}, | |
| headers={"Authorization": f"Bearer {token}"}, | |
| timeout=10 | |
| ) | |
| return jsonify({"ok": True, "token_ok": True, "folder": r.json(), "status": r.status_code}) | |
| except Exception as e: | |
| import traceback | |
| return jsonify({"ok": False, "error": str(e), "trace": traceback.format_exc()}), 500 | |
| def drive_headers(): | |
| return {"Authorization": f"Bearer {get_drive_token()}"} | |
| def get_or_create_folder(name, parent_id): | |
| safe_name = name.strip().replace("/", "-").replace("\\", "-") or "general" | |
| q = f"name='{safe_name}' and '{parent_id}' in parents and mimeType='application/vnd.google-apps.folder' and trashed=false" | |
| r = requests.get("https://www.googleapis.com/drive/v3/files", | |
| params={"q": q, "fields": "files(id,name)", "supportsAllDrives": "true", "includeItemsFromAllDrives": "true"}, | |
| headers=drive_headers(), timeout=15) | |
| files = r.json().get("files", []) | |
| if files: | |
| print(f"[FOLDER] Found '{safe_name}' β {files[0]['id']}") | |
| return files[0]["id"] | |
| r2 = requests.post("https://www.googleapis.com/drive/v3/files", | |
| params={"supportsAllDrives": "true"}, | |
| headers={**drive_headers(), "Content-Type": "application/json"}, | |
| json={"name": safe_name, "mimeType": "application/vnd.google-apps.folder", "parents": [parent_id]}, | |
| timeout=15) | |
| r2_data = r2.json() | |
| if "id" not in r2_data: | |
| raise Exception(f"Nu pot crea folderul '{safe_name}': {r2_data}") | |
| print(f"[FOLDER] Created '{safe_name}' β {r2_data['id']}") | |
| return r2_data["id"] | |
| # ββ Drive upload ββββββββββββββββββββββββββββββββββββββββββββββ | |
| def drive_upload(): | |
| try: | |
| elev_vpass = request.form.get("elevId", "unknown") | |
| materie = request.form.get("materieId", "general") | |
| f = request.files.get("file") | |
| if not f: | |
| return jsonify({"error": "no file"}), 400 | |
| # Citeste fisierul complet in memorie β fix pentru gunicorn multi-worker | |
| file_bytes = f.read() | |
| file_name = f.filename or "fisier" | |
| file_mimetype = f.content_type or f.mimetype or "application/octet-stream" | |
| print(f"[DRIVE UPLOAD] {elev_vpass}/{materie}/{file_name} ({len(file_bytes)} bytes)") | |
| # Creeaza folderele RV-0022 / Matematica / ... | |
| elev_folder = get_or_create_folder(elev_vpass, DRIVE_FOLDER_ID) | |
| materie_folder = get_or_create_folder(materie, elev_folder) | |
| print(f"[DRIVE UPLOAD] Folder elev: {elev_folder}, folder materie: {materie_folder}") | |
| # Construieste multipart/related manual | |
| boundary = "sge_boundary_" + str(int(time.time())) | |
| metadata_json = json.dumps({ | |
| "name": file_name, | |
| "parents": [materie_folder], | |
| "description": f"uploaded:{int(time.time())}" | |
| }) | |
| part1 = ( | |
| f"--{boundary}\r\n" | |
| f"Content-Type: application/json; charset=UTF-8\r\n\r\n" | |
| f"{metadata_json}\r\n" | |
| ).encode("utf-8") | |
| part2_header = ( | |
| f"--{boundary}\r\n" | |
| f"Content-Type: {file_mimetype}\r\n\r\n" | |
| ).encode("utf-8") | |
| part2_end = f"\r\n--{boundary}--\r\n".encode("utf-8") | |
| body = part1 + part2_header + file_bytes + part2_end | |
| token = get_drive_token() | |
| r = requests.post( | |
| "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&fields=id,name,size&supportsAllDrives=true", | |
| headers={ | |
| "Authorization": f"Bearer {token}", | |
| "Content-Type": f"multipart/related; boundary={boundary}", | |
| }, | |
| data=body, | |
| timeout=180 | |
| ) | |
| print(f"[DRIVE UPLOAD] Response {r.status_code}: {r.text[:200]}") | |
| if r.status_code not in (200, 201): | |
| return jsonify({"error": f"Drive HTTP {r.status_code}: {r.text[:200]}"}), 500 | |
| data = r.json() | |
| if "id" not in data: | |
| return jsonify({"error": f"Drive no ID: {data}"}), 500 | |
| _fs_log("upload", {"elevVpass": elev_vpass, "materie": materie, | |
| "fisier": file_name, "fileId": data.get("id","")}) | |
| return jsonify({"fileId": data.get("id"), "name": data.get("name"), "size": data.get("size","")}) | |
| except Exception as e: | |
| import traceback; traceback.print_exc() | |
| return jsonify({"error": str(e)}), 500 | |
| # ββ Drive list ββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def drive_list(): | |
| try: | |
| elev_vpass = request.args.get("elevId", "") | |
| materie = request.args.get("materieId", "") | |
| PARAMS_BASE = {"supportsAllDrives": "true", "includeItemsFromAllDrives": "true"} | |
| q_elev = f"name='{elev_vpass}' and '{DRIVE_FOLDER_ID}' in parents and mimeType='application/vnd.google-apps.folder' and trashed=false" | |
| r1 = requests.get("https://www.googleapis.com/drive/v3/files", | |
| params={**PARAMS_BASE, "q": q_elev, "fields": "files(id)"}, headers=drive_headers(), timeout=15) | |
| ef = r1.json().get("files", []) | |
| if not ef: return jsonify({"files": []}) | |
| q_mat = f"name='{materie}' and '{ef[0]['id']}' in parents and mimeType='application/vnd.google-apps.folder' and trashed=false" | |
| r2 = requests.get("https://www.googleapis.com/drive/v3/files", | |
| params={**PARAMS_BASE, "q": q_mat, "fields": "files(id)"}, headers=drive_headers(), timeout=15) | |
| mf = r2.json().get("files", []) | |
| if not mf: return jsonify({"files": []}) | |
| q_files = f"'{mf[0]['id']}' in parents and trashed=false" | |
| r3 = requests.get("https://www.googleapis.com/drive/v3/files", | |
| params={**PARAMS_BASE, "q": q_files, "fields": "files(id,name,size,mimeType,createdTime,description)"}, | |
| headers=drive_headers(), timeout=15) | |
| return jsonify({"files": r3.json().get("files", [])}) | |
| except Exception as e: | |
| print(f"[DRIVE LIST ERROR] {e}") | |
| return jsonify({"error": str(e)}), 500 | |
| # ββ Drive download ββββββββββββββββββββββββββββββββββββββββββββ | |
| def drive_download(file_id): | |
| try: | |
| r_meta = requests.get(f"https://www.googleapis.com/drive/v3/files/{file_id}", | |
| params={"fields": "name,mimeType", "supportsAllDrives": "true"}, | |
| headers=drive_headers(), timeout=15) | |
| meta = r_meta.json() | |
| r_file = requests.get(f"https://www.googleapis.com/drive/v3/files/{file_id}?alt=media&supportsAllDrives=true", | |
| headers=drive_headers(), timeout=120, stream=True) | |
| headers = { | |
| "Content-Disposition": f"attachment; filename=\"{meta.get('name','file')}\"", | |
| "Content-Type": meta.get("mimeType", "application/octet-stream"), | |
| } | |
| return Response(r_file.iter_content(chunk_size=8192), headers=headers) | |
| except Exception as e: | |
| return jsonify({"error": str(e)}), 500 | |
| # ββ Drive delete ββββββββββββββββββββββββββββββββββββββββββββββ | |
| def drive_delete(file_id): | |
| try: | |
| r = requests.delete(f"https://www.googleapis.com/drive/v3/files/{file_id}", | |
| params={"supportsAllDrives": "true"}, | |
| headers=drive_headers(), timeout=30) | |
| if r.status_code in (200, 204, 404): | |
| return jsonify({"ok": True}) | |
| return jsonify({"error": "delete failed", "status": r.status_code}), 500 | |
| except Exception as e: | |
| return jsonify({"error": str(e)}), 500 | |
| # ββ Firestore helpers βββββββββββββββββββββββββββββββββββββββββ | |
| def _to_fields(data): | |
| fields = {} | |
| for k, v in data.items(): | |
| if v is None: fields[k] = {"nullValue": None} | |
| elif isinstance(v, bool): fields[k] = {"booleanValue": v} | |
| elif isinstance(v, int): fields[k] = {"integerValue": str(v)} | |
| else: fields[k] = {"stringValue": str(v)} | |
| return fields | |
| def _fs_add(col, data): | |
| r = requests.post(f"{FIRESTORE_BASE}/{col}?key={FIREBASE_API_KEY}", | |
| json={"fields": _to_fields(data)}, timeout=15) | |
| return r.status_code == 200 | |
| def _fs_log(tip, extra={}): | |
| """Scrie un log entry in Firestore colectia 'loguri'""" | |
| try: | |
| payload = {"tip": tip, "ts": int(time.time()), **extra} | |
| _fs_add("loguri", payload) | |
| except: pass | |
| # ββ Ruta log β apelata din frontend la login/erori ββββββββββββ | |
| def api_log(): | |
| try: | |
| data = request.get_json(silent=True) or {} | |
| _fs_log(data.get("tip","event"), {k:v for k,v in data.items() if k!="tip"}) | |
| return jsonify({"ok": True}) | |
| except Exception as e: | |
| return jsonify({"error": str(e)}), 500 | |
| # ββ Ruta loguri β citeste pentru admin βββββββββββββββββββββββ | |
| def api_logs(): | |
| try: | |
| r = requests.get(f"{FIRESTORE_BASE}/loguri?key={FIREBASE_API_KEY}&pageSize=200", | |
| timeout=15) | |
| docs = r.json().get("documents", []) | |
| logs = [] | |
| for d in docs: | |
| f = d.get("fields", {}) | |
| entry = {} | |
| for k, v in f.items(): | |
| entry[k] = v.get("stringValue") or v.get("integerValue") or v.get("booleanValue") or v.get("nullValue","") | |
| entry["_id"] = d["name"].split("/")[-1] | |
| logs.append(entry) | |
| logs.sort(key=lambda x: int(x.get("ts",0)), reverse=True) | |
| return jsonify({"logs": logs[:150]}) | |
| except Exception as e: | |
| return jsonify({"error": str(e), "logs": []}), 500 | |
| # ββ Utilizatori online β server-side ping ββββββββββββββββββββ | |
| _online = {} # { "vpass_role": timestamp } | |
| def api_ping(): | |
| data = request.get_json(silent=True) or {} | |
| key = f"{data.get('vpass','?')}_{data.get('role','?')}" | |
| _online[key] = {"ts": time.time(), "vpass": data.get("vpass","?"), | |
| "role": data.get("role","?"), "name": data.get("name","")} | |
| # Curata cei inactivi >2min | |
| now = time.time() | |
| expired = [k for k,v in _online.items() if now - v["ts"] > 120] | |
| for k in expired: del _online[k] | |
| return jsonify({"ok": True}) | |
| def api_online(): | |
| now = time.time() | |
| active = {k:v for k,v in _online.items() if now - v["ts"] <= 120} | |
| elevi = [v for v in active.values() if v["role"]=="elev"] | |
| profesori= [v for v in active.values() if v["role"]=="profesor"] | |
| return jsonify({"total": len(active), "elevi": elevi, "profesori": profesori}) | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # CLEANUP AUTOMAT β sterge fisierele mai vechi de 7 zile | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def cleanup_old_files(): | |
| """Ruleaza o data pe zi β sterge din Drive fisierele > 7 zile""" | |
| while True: | |
| try: | |
| time.sleep(3600) # verifica la fiecare ora | |
| print("[CLEANUP] Verificare fisiere vechi...") | |
| limit_ts = time.time() - 7 * 24 * 3600 # 7 zile in urma | |
| # Lista toate fisierele din folderul SGE recursiv | |
| r = requests.get("https://www.googleapis.com/drive/v3/files", | |
| params={ | |
| "q": f"'{DRIVE_FOLDER_ID}' in parents or '{DRIVE_FOLDER_ID}' in ancestors", | |
| "fields": "files(id,name,createdTime,mimeType,description)", | |
| "pageSize": 1000 | |
| }, headers=drive_headers(), timeout=30) | |
| files = r.json().get("files", []) | |
| deleted = 0 | |
| for f in files: | |
| if f.get("mimeType") == "application/vnd.google-apps.folder": | |
| continue | |
| # Incearca sa citeasca timestamp din description | |
| desc = f.get("description", "") | |
| upload_ts = None | |
| if desc.startswith("uploaded:"): | |
| try: upload_ts = int(desc.split(":")[1]) | |
| except: pass | |
| # Fallback: data crearii din Drive | |
| if not upload_ts: | |
| ct = f.get("createdTime", "") | |
| if ct: | |
| try: | |
| from datetime import datetime, timezone | |
| dt = datetime.fromisoformat(ct.replace("Z", "+00:00")) | |
| upload_ts = int(dt.timestamp()) | |
| except: pass | |
| if upload_ts and upload_ts < limit_ts: | |
| try: | |
| rd = requests.delete( | |
| f"https://www.googleapis.com/drive/v3/files/{f['id']}", | |
| headers=drive_headers(), timeout=20) | |
| if rd.status_code in (200, 204): | |
| deleted += 1 | |
| print(f"[CLEANUP] β Sters: {f['name']}") | |
| _fs_log("cleanup_delete", {"fisier": f["name"], "fileId": f["id"]}) | |
| except Exception as ex: | |
| print(f"[CLEANUP] Eroare stergere {f['name']}: {ex}") | |
| if deleted > 0: | |
| print(f"[CLEANUP] Gata: {deleted} fisiere sterse.") | |
| else: | |
| print("[CLEANUP] Niciun fisier expirat.") | |
| except Exception as ex: | |
| print(f"[CLEANUP] Eroare generala: {ex}") | |
| time.sleep(300) | |
| # ββ Seed Firestore ββββββββββββββββββββββββββββββββββββββββββββ | |
| ELEVI = [ | |
| {"pozitie":1,"nume":"Andronic Aniela","vpassId":"AA-0001"}, | |
| {"pozitie":2,"nume":"Badan Alexandra","vpassId":"BA-0002"}, | |
| {"pozitie":3,"nume":"Bunescu Lavinia","vpassId":"BL-0003"}, | |
| {"pozitie":4,"nume":"Bunescu Lorena","vpassId":"BL-0004"}, | |
| {"pozitie":5,"nume":"Burdujan Damian","vpassId":"BD-0005"}, | |
| {"pozitie":6,"nume":"Ceban Madalina","vpassId":"CM-0006"}, | |
| {"pozitie":7,"nume":"Ceban Valeria","vpassId":"CV-0007"}, | |
| {"pozitie":8,"nume":"Cebanu Nichita","vpassId":"CN-0008"}, | |
| {"pozitie":9,"nume":"Chele Ilinca","vpassId":"CI-0009"}, | |
| {"pozitie":10,"nume":"Chihai Mirela","vpassId":"CM-0010"}, | |
| {"pozitie":11,"nume":"Cojocari Ciprian","vpassId":"CC-0011"}, | |
| {"pozitie":12,"nume":"Creciun Leonard","vpassId":"CL-0012"}, | |
| {"pozitie":13,"nume":"Lozovan Sanda","vpassId":"LS-0013"}, | |
| {"pozitie":14,"nume":"Lungu Sergiu","vpassId":"LS-0014"}, | |
| {"pozitie":15,"nume":"Mahnea Adelina","vpassId":"MA-0015"}, | |
| {"pozitie":16,"nume":"Morcan Ina","vpassId":"MI-0016"}, | |
| {"pozitie":17,"nume":"Morcan Ion","vpassId":"MI-0017"}, | |
| {"pozitie":18,"nume":"Popa Cristina","vpassId":"PC-0018"}, | |
| {"pozitie":19,"nume":"Pricob Adelina","vpassId":"PA-0019"}, | |
| {"pozitie":20,"nume":"Prinos Catalina","vpassId":"PC-0020"}, | |
| {"pozitie":21,"nume":"Radu Daniela","vpassId":"RD-0021"}, | |
| {"pozitie":22,"nume":"Rosca Victor","vpassId":"RV-0022"}, | |
| {"pozitie":23,"nume":"Rotari Cristian","vpassId":"RC-0023"}, | |
| {"pozitie":24,"nume":"Rotaru Camelia","vpassId":"RC-0024"}, | |
| {"pozitie":25,"nume":"Sambris Stanislav","vpassId":"SS-0025"}, | |
| {"pozitie":26,"nume":"Sirbu Delia","vpassId":"SD-0026"}, | |
| {"pozitie":27,"nume":"Soltoian Elena","vpassId":"SE-0027"}, | |
| {"pozitie":28,"nume":"Tabuncic Chiril","vpassId":"TC-0028"}, | |
| {"pozitie":29,"nume":"Turcan Gabriel","vpassId":"TG-0029"}, | |
| {"pozitie":30,"nume":"Turcan Mihai","vpassId":"TM-0030"}, | |
| {"pozitie":31,"nume":"Turcanu Ilie","vpassId":"TI-0031"}, | |
| {"pozitie":32,"nume":"Virlan Daniela","vpassId":"VD-0032"}, | |
| ] | |
| def auto_seed(): | |
| time.sleep(4) | |
| try: | |
| r = requests.get(f"{FIRESTORE_BASE}/elevi?key={FIREBASE_API_KEY}&pageSize=1", timeout=15) | |
| if r.json().get("documents"): | |
| print("[SGE] DB populat β seed omis."); return | |
| print("[SGE] Seed automat pornit...") | |
| ok = 0 | |
| for e in ELEVI: | |
| if _fs_add("elevi", {"nume":e["nume"],"vpassId":e["vpassId"], | |
| "pozitie":e["pozitie"],"pin":None,"confirmed":False}): | |
| ok += 1; print(f"[SGE] β {e['vpassId']}") | |
| time.sleep(0.12) | |
| print(f"[SGE] Seed gata: {ok}/{len(ELEVI)}") | |
| except Exception as ex: print(f"[SGE] Seed eroare: {ex}") | |
| threading.Thread(target=auto_seed, daemon=True).start() | |
| threading.Thread(target=cleanup_old_files, daemon=True).start() | |
| def index(): return send_from_directory("static","index.html") | |
| def not_found(e): return send_from_directory("static","404.html"), 404 | |
| def serve_files(filename): | |
| try: return send_from_directory("static", filename) | |
| except: return send_from_directory("static","404.html"), 404 | |
| if __name__ == "__main__": app.run(host="0.0.0.0", port=7860, debug=False) | |