Add support to import with xl file format
This commit is contained in:
parent
e0169b803d
commit
d338722880
@ -1493,6 +1493,32 @@ def _parse_csv_rows(content: bytes) -> list[dict]:
|
||||
return [dict(row) for row in reader]
|
||||
|
||||
|
||||
def _parse_xlsx_rows(content: bytes) -> list[dict]:
|
||||
"""Parse an XLSX (Excel) file and return a list of dicts.
|
||||
Uses the first sheet; first row is treated as the header.
|
||||
"""
|
||||
import openpyxl
|
||||
wb = openpyxl.load_workbook(io.BytesIO(content), read_only=True, data_only=True)
|
||||
ws = wb.active
|
||||
rows = list(ws.iter_rows(values_only=True))
|
||||
wb.close()
|
||||
if not rows:
|
||||
return []
|
||||
# First row = headers; normalise None headers to empty string
|
||||
headers = [str(h).strip() if h is not None else "" for h in rows[0]]
|
||||
result = []
|
||||
for row in rows[1:]:
|
||||
# Skip completely empty rows
|
||||
if all(v is None or str(v).strip() == "" for v in row):
|
||||
continue
|
||||
result.append({
|
||||
headers[i]: (str(v).strip() if v is not None else "")
|
||||
for i, v in enumerate(row)
|
||||
if i < len(headers) and headers[i] # skip header-less columns
|
||||
})
|
||||
return result
|
||||
|
||||
|
||||
def _parse_json_rows(content: bytes) -> list[dict]:
|
||||
"""Parse a JSON file — supports array at root OR {data: [...]}."""
|
||||
payload = json.loads(content.decode("utf-8-sig", errors="replace"))
|
||||
@ -1593,15 +1619,19 @@ async def import_contacts(
|
||||
try:
|
||||
if filename.endswith(".json"):
|
||||
raw_rows = _parse_json_rows(content)
|
||||
elif filename.endswith(".csv") or filename.endswith(".xlsx"):
|
||||
# For XLSX export from our own app, treat as CSV (xlsx export from
|
||||
# GuestList produces proper column headers in English)
|
||||
elif filename.endswith(".xlsx"):
|
||||
raw_rows = _parse_xlsx_rows(content)
|
||||
elif filename.endswith(".csv"):
|
||||
raw_rows = _parse_csv_rows(content)
|
||||
else:
|
||||
# Sniff: try JSON then CSV
|
||||
# Sniff: try JSON → xlsx magic bytes → CSV
|
||||
try:
|
||||
raw_rows = _parse_json_rows(content)
|
||||
except Exception:
|
||||
# XLSX files start with PK (zip magic bytes 50 4B)
|
||||
if content[:2] == b'PK':
|
||||
raw_rows = _parse_xlsx_rows(content)
|
||||
else:
|
||||
raw_rows = _parse_csv_rows(content)
|
||||
except Exception as exc:
|
||||
raise HTTPException(status_code=422, detail=f"Cannot parse file: {exc}")
|
||||
|
||||
@ -6,3 +6,4 @@ pydantic[email]>=2.5.0
|
||||
httpx>=0.25.2
|
||||
python-dotenv>=1.0.0
|
||||
python-multipart>=0.0.7
|
||||
openpyxl>=3.1.2
|
||||
|
||||
@ -118,7 +118,7 @@ function ImportContacts({ eventId, onImportComplete }) {
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
type="file"
|
||||
accept=".csv,.json"
|
||||
accept=".csv,.json,.xlsx"
|
||||
style={{ display: 'none' }}
|
||||
onChange={handleFileChange}
|
||||
/>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user