Initial commit

This commit is contained in:
kamaji
2026-01-26 04:57:20 -06:00
commit bbd720e2a2
8 changed files with 336 additions and 0 deletions

10
backend/Dockerfile Normal file
View File

@@ -0,0 +1,10 @@
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY main.py .
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

110
backend/main.py Normal file
View File

@@ -0,0 +1,110 @@
# main.py
from fastapi import FastAPI, Form, UploadFile, File
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from filelock import FileLock
import aiofiles
import httpx
import os
from datetime import datetime
import openpyxl
# -------------------------
# Configuration
# -------------------------
NEXTCLOUD_BASE_URL = "https://nextcloud.sdanywhere.com/remote.php/webdav/APs"
NEXTCLOUD_USER = "kamaji"
NEXTCLOUD_PASSWORD = "DvB0U2Uj3tOJaD"
EXCEL_FILENAME = "ap_data.xlsx"
LOCK_FILENAME = f"{EXCEL_FILENAME}.lock"
app = FastAPI()
# Allow CORS for frontend (if needed)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
# -------------------------
# Utility: Upload file to Nextcloud
# -------------------------
async def upload_to_nextcloud(local_path, remote_name):
url = f"{NEXTCLOUD_BASE_URL}/{remote_name}"
async with httpx.AsyncClient() as client:
with open(local_path, "rb") as f:
r = await client.put(url, content=f, auth=(NEXTCLOUD_USER, NEXTCLOUD_PASSWORD))
r.raise_for_status()
# -------------------------
# Utility: Save Excel safely
# -------------------------
def append_to_excel(data_row):
lock = FileLock(LOCK_FILENAME)
with lock:
if not os.path.exists(EXCEL_FILENAME):
wb = openpyxl.Workbook()
ws = wb.active
ws.append(["Timestamp", "Site ID", "AP Location", "Cable Length", "Serial Number"])
wb.save(EXCEL_FILENAME)
wb = openpyxl.load_workbook(EXCEL_FILENAME)
ws = wb.active
ws.append(data_row)
wb.save(EXCEL_FILENAME)
# -------------------------
# Endpoint
# -------------------------
@app.post("/api/ap/submit")
async def submit_ap(
site_id: str = Form(...),
ap_location: str = Form(...),
cable_length: float = Form(...),
serial_number: str = Form(...),
photo_continuity: UploadFile = File(...),
photo_length: UploadFile = File(...),
photo_verification: UploadFile = File(...),
photo_close: UploadFile = File(...),
photo_distance: UploadFile = File(...),
):
# Capitalize serial number
serial_number = serial_number.upper()
# Create folder locally before upload
folder_name = f"AP{ap_location}"
os.makedirs(folder_name, exist_ok=True)
# Save photos locally first
photo_mapping = {
"continuity": photo_continuity,
"length": photo_length,
"verification": photo_verification,
"close": photo_close,
"distance": photo_distance
}
saved_files = []
for key, file in photo_mapping.items():
filename = f"AP{ap_location}_{key}.jpg"
local_path = os.path.join(folder_name, filename)
async with aiofiles.open(local_path, "wb") as out_file:
content = await file.read()
await out_file.write(content)
saved_files.append((local_path, filename)) # store for upload
# Append data to Excel
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
data_row = [timestamp, site_id, ap_location, cable_length, serial_number]
append_to_excel(data_row)
# Upload Excel to Nextcloud
await upload_to_nextcloud(EXCEL_FILENAME, EXCEL_FILENAME)
# Upload photos to Nextcloud
for local_path, remote_name in saved_files:
await upload_to_nextcloud(local_path, remote_name)
return JSONResponse(content={"site_id": site_id, "ap_location": ap_location})

5
backend/requirements.txt Normal file
View File

@@ -0,0 +1,5 @@
fastapi
uvicorn
python-multipart
openpyxl
portalocker