v1.0.161: cgi.FieldStorage for UTF-8 filenames

This commit is contained in:
2026-06-23 21:09:27 +04:00
parent e4cbc59f7e
commit 740f75a791
+19 -18
View File
@@ -1,6 +1,5 @@
"""Upload service — accept file, store to DB, parse.""" """Upload service — accept file, store to DB, parse."""
import uuid, base64, json import uuid, base64, json, io, cgi
from email.parser import BytesParser
from db import documents, contracts, supplements from db import documents, contracts, supplements
from .parse import parse_file from .parse import parse_file
@@ -9,23 +8,28 @@ def handle_upload(rfile, content_type, content_length):
"""Parse multipart upload, store in DB, return result dict.""" """Parse multipart upload, store in DB, return result dict."""
body = rfile.read(content_length) body = rfile.read(content_length)
msg = BytesParser().parsebytes( environ = {
b"Content-Type: " + content_type.encode() + b"\r\n\r\n" + body "REQUEST_METHOD": "POST",
) "CONTENT_TYPE": content_type,
"CONTENT_LENGTH": str(content_length),
}
fs = cgi.FieldStorage(fp=io.BytesIO(body), environ=environ, keep_blank_values=True)
filename = None filename = None
file_data = None file_data = None
contract_id = "" contract_id = ""
if msg.is_multipart(): if "files" in fs:
for part in msg.get_payload(): item = fs["files"]
fn = part.get_filename() if isinstance(item, list):
if fn: item = item[0]
filename = fn filename = item.filename
file_data = part.get_payload(decode=True) file_data = item.file.read() if hasattr(item, "file") else item.value
else: if isinstance(file_data, str):
disp = part.get("Content-Disposition", "") file_data = file_data.encode("utf-8")
if 'name="contract_id"' in disp:
contract_id = part.get_payload(decode=True).decode("utf-8", errors="ignore").strip() if "contract_id" in fs:
contract_id = fs.getfirst("contract_id", "")
if not filename or not file_data: if not filename or not file_data:
return {"ok": False, "error": "no file in request"} return {"ok": False, "error": "no file in request"}
@@ -33,13 +37,11 @@ def handle_upload(rfile, content_type, content_length):
mime = _mime_for(filename) mime = _mime_for(filename)
b64 = base64.b64encode(file_data).decode() b64 = base64.b64encode(file_data).decode()
# Удалить старый файл с тем же именем в этом контракте
if contract_id: if contract_id:
supplements.delete_by_document(contract_id, filename) supplements.delete_by_document(contract_id, filename)
doc = documents.insert(filename, mime, b64) doc = documents.insert(filename, mime, b64)
# Создать контракт если нет
if not contract_id: if not contract_id:
from datetime import datetime from datetime import datetime
now = datetime.now() now = datetime.now()
@@ -51,7 +53,6 @@ def handle_upload(rfile, content_type, content_length):
supplements.insert(contract_id, doc["id"], supp_type) supplements.insert(contract_id, doc["id"], supp_type)
# Парсинг на VM
parsed = parse_file(filename, file_data) parsed = parse_file(filename, file_data)
if parsed and parsed.get("status") == "parsed": if parsed and parsed.get("status") == "parsed":
documents.set_parsed(doc["id"], parsed["elements"]) documents.set_parsed(doc["id"], parsed["elements"])