vsmdvic / static /app.py
droplyvictor89's picture
Upload app.py
619733e verified
from flask import Flask, send_from_directory, request, jsonify, Response
import requests, time, threading, json, os
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
import jwt as pyjwt
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")
r = requests.post(DRIVE_SA["token_uri"], data={
"grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
"assertion": signed,
}, timeout=15)
r.raise_for_status()
_drive_token = r.json()["access_token"]
_drive_token_exp = now + 3600
return _drive_token
def drive_headers():
return {"Authorization": f"Bearer {get_drive_token()}"}
def get_or_create_folder(name, parent_id):
"""Gฤƒseศ™te sau creeazฤƒ un subfolder รฎn Drive."""
token = get_drive_token()
q = f"name='{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)"},
headers=drive_headers(), timeout=15)
files = r.json().get("files", [])
if files:
return files[0]["id"]
# Creaza folder
r2 = requests.post("https://www.googleapis.com/drive/v3/files",
headers={**drive_headers(), "Content-Type": "application/json"},
json={"name": name, "mimeType": "application/vnd.google-apps.folder", "parents": [parent_id]},
timeout=15)
return r2.json()["id"]
# โ”€โ”€ Ruta upload โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
@app.route("/drive/upload", methods=["POST"])
def drive_upload():
try:
elev_id = 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
# Structura: VSERVERS / elevId / materieId / fisier.ext
elev_folder = get_or_create_folder(elev_id, DRIVE_FOLDER_ID)
materie_folder = get_or_create_folder(materie, elev_folder)
# Upload multipart
metadata = json.dumps({"name": f.filename, "parents": [materie_folder]})
r = requests.post(
"https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&fields=id,name,size",
headers={"Authorization": f"Bearer {get_drive_token()}"},
files={
"metadata": ("metadata", metadata, "application/json"),
"file": (f.filename, f.stream, f.mimetype or "application/octet-stream"),
},
timeout=120
)
data = r.json()
return jsonify({"fileId": data.get("id"), "name": data.get("name"), "size": data.get("size")})
except Exception as e:
print(f"[DRIVE UPLOAD ERROR] {e}")
return jsonify({"error": str(e)}), 500
# โ”€โ”€ Ruta list โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
@app.route("/drive/list", methods=["GET"])
def drive_list():
try:
elev_id = request.args.get("elevId", "")
materie = request.args.get("materieId", "")
# Gaseste folderele
q_elev = f"name='{elev_id}' 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={"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={"q": q_mat, "fields": "files(id)"}, headers=drive_headers(), timeout=15)
mf = r2.json().get("files", [])
if not mf:
return jsonify({"files": []})
# Lista fisiere din folder
q_files = f"'{mf[0]['id']}' in parents and trashed=false"
r3 = requests.get("https://www.googleapis.com/drive/v3/files",
params={"q": q_files, "fields": "files(id,name,size,mimeType,createdTime)"},
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
# โ”€โ”€ Ruta download (proxy) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
@app.route("/drive/download/<file_id>", methods=["GET"])
def drive_download(file_id):
try:
# Metadata
r_meta = requests.get(f"https://www.googleapis.com/drive/v3/files/{file_id}",
params={"fields": "name,mimeType"}, headers=drive_headers(), timeout=15)
meta = r_meta.json()
# Continut
r_file = requests.get(f"https://www.googleapis.com/drive/v3/files/{file_id}?alt=media",
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:
print(f"[DRIVE DOWNLOAD ERROR] {e}")
return jsonify({"error": str(e)}), 500
# โ”€โ”€ 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 fs_add(col, 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)}
r=requests.post(f"{FIRESTORE_BASE}/{col}?key={FIREBASE_API_KEY}",json={"fields":fields},timeout=15)
return r.status_code==200
def auto_seed():
time.sleep(4)
print("[VSERVERS] Verificare DB...")
try:
r=requests.get(f"{FIRESTORE_BASE}/elevi?key={FIREBASE_API_KEY}&pageSize=1",timeout=15)
if r.json().get("documents"):
print("[VSERVERS] DB populat โ€” seed omis."); return
print("[VSERVERS] 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"[VSERVERS] โœ“ {e['vpassId']}")
time.sleep(0.12)
print(f"[VSERVERS] Seed gata: {ok}/{len(ELEVI)}")
except Exception as ex: print(f"[VSERVERS] Seed eroare: {ex}")
threading.Thread(target=auto_seed,daemon=True).start()
@app.route("/")
def index(): return send_from_directory("static","index.html")
@app.errorhandler(404)
def not_found(e): return send_from_directory("static","404.html"),404
@app.route("/<path:filename>")
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)