Initial commit
This commit is contained in:
10
backend/Dockerfile
Normal file
10
backend/Dockerfile
Normal 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
110
backend/main.py
Normal 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
5
backend/requirements.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
fastapi
|
||||
uvicorn
|
||||
python-multipart
|
||||
openpyxl
|
||||
portalocker
|
||||
Reference in New Issue
Block a user