From 2f688663984c07afa684e2eb4846829d71dd2958 Mon Sep 17 00:00:00 2001 From: Michael Woods Date: Sat, 27 Dec 2025 11:38:10 -0500 Subject: [PATCH] Changes to jobs, made a change to the base server to store the callsign in a config location and set it upon startup. --- packetserver/http/routers/jobs.py | 107 +++++++++++++++--------------- packetserver/http/server.py | 2 +- packetserver/server/__init__.py | 1 + packetserver/server/constants.py | 9 ++- 4 files changed, 63 insertions(+), 56 deletions(-) diff --git a/packetserver/http/routers/jobs.py b/packetserver/http/routers/jobs.py index d336037..2b36ecf 100644 --- a/packetserver/http/routers/jobs.py +++ b/packetserver/http/routers/jobs.py @@ -136,6 +136,60 @@ async def jobs_list_page( } ) +@dashboard_router.get("/jobs/new", response_class=HTMLResponse) +async def new_job_form( + request: Request, + current_user: HttpUser = Depends(get_current_http_user) +): + return templates.TemplateResponse( + "job_new.html", + { + "request": request, + "current_user": current_user.username + } + ) + +@dashboard_router.post("/jobs/new") +async def create_job_from_form( + db: DbDependency, + request: Request, + cmd: str = Form(...), + env_keys: List[str] = Form(default=[]), + env_values: List[str] = Form(default=[]), + files: List[UploadFile] = File(default=[]), + current_user: HttpUser = Depends(get_current_http_user) +): + # Build env dict from parallel lists + env = {} + for k, v in zip(env_keys, env_values): + if k.strip(): + env[k.strip()] = v.strip() + + # Build files dict for API (filename → base64) + files_dict = {} + for upload in files: + if upload.filename: + content = await upload.read() + files_dict[upload.filename] = base64.b64encode(content).decode('ascii') + + # Prepare payload for the existing API + payload = { + "cmd": [part.strip() for part in cmd.split() if part.strip()], # split on whitespace, like shell + "env": env if env else None, + "files": files_dict if files_dict else None + } + + # Call the API internally + from packetserver.http.routers.jobs import create_job as api_create_job + response = await api_create_job( + payload=JobCreate(**{k: v for k, v in payload.items() if v is not None}), + db=db, + current_user=current_user + ) + + # Redirect to the new job detail page + return RedirectResponse(url=f"/jobs/{response.id}", status_code=303) + @dashboard_router.get("/jobs/{jid}", response_class=HTMLResponse) async def job_detail_page( request: Request, @@ -206,56 +260,3 @@ async def create_job( logging.error(f"Job creation failed for {username}: {e}\n{format_exc()}") raise HTTPException(status_code=500, detail="Failed to queue job") -@dashboard_router.get("/jobs/new", response_class=HTMLResponse) -async def new_job_form( - request: Request, - current_user: HttpUser = Depends(get_current_http_user) -): - return templates.TemplateResponse( - "job_new.html", - { - "request": request, - "current_user": current_user.username - } - ) - -@dashboard_router.post("/jobs/new") -async def create_job_from_form( - db: DbDependency, - request: Request, - cmd: str = Form(...), - env_keys: List[str] = Form(default=[]), - env_values: List[str] = Form(default=[]), - files: List[UploadFile] = File(default=[]), - current_user: HttpUser = Depends(get_current_http_user) -): - # Build env dict from parallel lists - env = {} - for k, v in zip(env_keys, env_values): - if k.strip(): - env[k.strip()] = v.strip() - - # Build files dict for API (filename → base64) - files_dict = {} - for upload in files: - if upload.filename: - content = await upload.read() - files_dict[upload.filename] = base64.b64encode(content).decode('ascii') - - # Prepare payload for the existing API - payload = { - "cmd": [part.strip() for part in cmd.split() if part.strip()], # split on whitespace, like shell - "env": env if env else None, - "files": files_dict if files_dict else None - } - - # Call the API internally - from packetserver.http.routers.jobs import create_job as api_create_job - response = await api_create_job( - payload=JobCreate(**{k: v for k, v in payload.items() if v is not None}), - db=db, - current_user=current_user - ) - - # Redirect to the new job detail page - return RedirectResponse(url=f"/jobs/{response.id}", status_code=303) \ No newline at end of file diff --git a/packetserver/http/server.py b/packetserver/http/server.py index 3b8db06..ea332d3 100644 --- a/packetserver/http/server.py +++ b/packetserver/http/server.py @@ -16,7 +16,7 @@ BASE_DIR = Path(__file__).parent.resolve() app = FastAPI( title="PacketServer HTTP API", description="RESTful interface to the AX.25 packet radio BBS", - version="0.1.0", + version="0.5.0", ) # Define templates EARLY (before importing dashboard) diff --git a/packetserver/server/__init__.py b/packetserver/server/__init__.py index bd11d4b..60906ba 100644 --- a/packetserver/server/__init__.py +++ b/packetserver/server/__init__.py @@ -73,6 +73,7 @@ class Server: if 'config' not in conn.root(): logging.debug("no config, writing blank default config") conn.root.config = PersistentMapping(deepcopy(default_server_config)) + conn.root.server_callsign = self.callsign conn.root.config['blacklist'] = PersistentList() if 'SYSTEM' not in conn.root.config['blacklist']: logging.debug("Adding 'SYSTEM' to blacklist in case someone feels like violating FCC rules.") diff --git a/packetserver/server/constants.py b/packetserver/server/constants.py index a80ca1e..ed68c4b 100644 --- a/packetserver/server/constants.py +++ b/packetserver/server/constants.py @@ -1,6 +1,11 @@ default_server_config = { "motd": "Welcome to this PacketServer BBS!", - "operator": "placeholder", - "max_message_length": 2000 + "operator": "email_callsign_name_whatever", + "max_message_length": 2000, + "server_name": "Packet Server BBS" +} + +jobs_default = { + } \ No newline at end of file