80 lines
2.6 KiB
Python
80 lines
2.6 KiB
Python
"""Upload service — accept file, store to DB, parse."""
|
||
import uuid, base64, json
|
||
from email.parser import BytesParser
|
||
from db import documents, contracts, supplements
|
||
from .parse import parse_file
|
||
|
||
|
||
def handle_upload(rfile, content_type, content_length):
|
||
"""Parse multipart upload, store in DB, return result dict."""
|
||
body = rfile.read(content_length)
|
||
|
||
msg = BytesParser().parsebytes(
|
||
b"Content-Type: " + content_type.encode() + b"\r\n\r\n" + body
|
||
)
|
||
filename = None
|
||
file_data = None
|
||
contract_id = ""
|
||
|
||
if msg.is_multipart():
|
||
for part in msg.get_payload():
|
||
fn = part.get_filename()
|
||
if fn:
|
||
filename = fn
|
||
file_data = part.get_payload(decode=True)
|
||
else:
|
||
disp = part.get("Content-Disposition", "")
|
||
if 'name="contract_id"' in disp:
|
||
contract_id = part.get_payload(decode=True).decode("utf-8", errors="ignore").strip()
|
||
|
||
if not filename or not file_data:
|
||
return {"ok": False, "error": "no file in request"}
|
||
|
||
mime = _mime_for(filename)
|
||
b64 = base64.b64encode(file_data).decode()
|
||
|
||
# Удалить старый файл с тем же именем в этом контракте
|
||
if contract_id:
|
||
supplements.delete_by_document(contract_id, filename)
|
||
|
||
doc = documents.insert(filename, mime, b64)
|
||
|
||
# Создать контракт если нет
|
||
if not contract_id:
|
||
from datetime import datetime
|
||
now = datetime.now()
|
||
c = contracts.insert(f"б/н {now.strftime('%Y%m%d')}-{now.strftime('%H%M')}")
|
||
contract_id = c["id"]
|
||
supp_type = "initial"
|
||
else:
|
||
supp_type = "additional"
|
||
|
||
supplements.insert(contract_id, doc["id"], supp_type)
|
||
|
||
# Парсинг на VM
|
||
parsed = parse_file(filename, file_data)
|
||
if parsed and parsed.get("status") == "parsed":
|
||
documents.set_parsed(doc["id"], parsed["elements"])
|
||
elif parsed and parsed.get("status") == "error":
|
||
documents.set_error(doc["id"], parsed.get("error", "parse failed"))
|
||
|
||
return {
|
||
"ok": True,
|
||
"doc_id": doc["id"],
|
||
"contract_id": contract_id,
|
||
"filename": filename,
|
||
"size": len(file_data),
|
||
"parsed": parsed,
|
||
}
|
||
|
||
|
||
def _mime_for(filename):
|
||
ext = filename.rsplit(".", 1)[-1].lower() if "." in filename else ""
|
||
mime_map = {
|
||
"pdf": "application/pdf",
|
||
"docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||
"doc": "application/msword",
|
||
"zip": "application/zip",
|
||
}
|
||
return mime_map.get(ext, "application/octet-stream")
|