diff --git a/imptune/api/printers.py b/imptune/api/printers.py index 7d98664..2e88a56 100644 --- a/imptune/api/printers.py +++ b/imptune/api/printers.py @@ -1,4 +1,4 @@ -"""Printer CRUD API — POST /printers, DELETE /printers/{id}.""" +"""Printer CRUD API — POST /printers, DELETE /printers/{id}, PATCH /printers/{id}.""" from __future__ import annotations from collections import defaultdict @@ -9,7 +9,7 @@ from fastapi.responses import HTMLResponse, RedirectResponse from fastapi.templating import Jinja2Templates from peewee import JOIN -from imptune.db.models import Client, Printer +from imptune.db.models import Client, Driver, Printer router = APIRouter(prefix="/printers") @@ -31,6 +31,8 @@ def _error_response(message: str, status_code: int = 400) -> HTMLResponse: def _render_printer_list(request: Request) -> HTMLResponse: """Query printers with LEFT JOIN on client and render grouped partial.""" + import json + query = ( Printer.select(Printer, Client) .join(Client, JOIN.LEFT_OUTER) @@ -41,10 +43,17 @@ def _render_printer_list(request: Request) -> HTMLResponse: client_name = p.client.name if p.client_id else "Unassigned" grouped[client_name].append(p) + clients = list(Client.select().order_by(Client.name)) + all_drivers = list(Driver.select().order_by(Driver.uploaded_at.desc())) + driver_data = [ + {"driver": d, "names": json.loads(d.driver_desc) if d.driver_desc else []} + for d in all_drivers + ] + return templates.TemplateResponse( request=request, name="partials/printer_list.html", - context={"grouped": grouped}, + context={"grouped": grouped, "clients": clients, "driver_data": driver_data}, ) @@ -112,3 +121,54 @@ def delete_printer(request: Request, printer_id: int) -> HTMLResponse: return _error_response(f"Printer {printer_id} not found.", status_code=404) return _render_printer_list(request) + + +@router.patch("/{printer_id}", response_class=HTMLResponse) +def update_printer( + request: Request, + printer_id: int, + name: str = Form(...), + ip_address: str = Form(""), + port_name: str = Form(""), + duplex_mode: str = Form("OneSided"), + color_mode: str = Form(""), + paper_size: str = Form("A4"), + collate: str = Form(""), + client_id: str = Form(""), + driver_id: str = Form(""), +) -> HTMLResponse: + """Update an existing printer configuration in-place.""" + from datetime import UTC, datetime + + printer = Printer.get_or_none(Printer.id == printer_id) + if printer is None: + return _error_response(f"Printer {printer_id} not found.", status_code=404) + + name = name.strip() + ip_address = ip_address.strip() or printer.ip_address + port_name = port_name.strip() or printer.port_name + + if not name: + return _error_response("Printer name is required.") + if not ip_address: + return _error_response("IP address is required.") + if not port_name: + return _error_response("Port name is required.") + if duplex_mode not in _VALID_DUPLEX: + return _error_response(f"Invalid duplex mode: {duplex_mode}.") + if paper_size not in _VALID_PAPER: + return _error_response(f"Invalid paper size: {paper_size}.") + + printer.name = name + printer.ip_address = ip_address + printer.port_name = port_name + printer.duplex_mode = duplex_mode + printer.color_mode = color_mode == "on" + printer.paper_size = paper_size + printer.collate = collate == "on" + printer.client = int(client_id) if client_id.strip() else None + printer.driver = int(driver_id) if driver_id.strip() else None + printer.updated_at = datetime.now(UTC).replace(tzinfo=None) + printer.save() + + return _render_printer_list(request)