Added some logging and object upload code.

This commit is contained in:
Michael Woods
2025-12-25 22:32:44 -05:00
parent d5983b6bf3
commit 07e6519679
3 changed files with 98 additions and 3 deletions

View File

@@ -0,0 +1,13 @@
from .config import Settings
import logging
def init_logging():
settings = Settings()
desired_level = settings.log_level.upper().strip()
if desired_level not in logging.getLevelNamesMapping():
raise ValueError(f"Invalid log level '{desired_level}'")
logging.basicConfig(level=logging.getLevelName(desired_level))

View File

@@ -1,13 +1,17 @@
from fastapi import APIRouter, Depends, HTTPException from fastapi import APIRouter, Depends, HTTPException, UploadFile, File, Form
from typing import List from fastapi.responses import JSONResponse
from typing import List, Optional
from datetime import datetime from datetime import datetime
from uuid import UUID from uuid import UUID
import mimetypes import mimetypes
import logging
from traceback import format_exc
from packetserver.http.dependencies import get_current_http_user from packetserver.http.dependencies import get_current_http_user
from packetserver.http.auth import HttpUser from packetserver.http.auth import HttpUser
from packetserver.http.database import DbDependency from packetserver.http.database import DbDependency
from packetserver.server.objects import Object from packetserver.server.objects import Object
from packetserver.server.users import User
from pydantic import BaseModel from pydantic import BaseModel
router = APIRouter(prefix="/api/v1", tags=["objects"]) router = APIRouter(prefix="/api/v1", tags=["objects"])
@@ -49,4 +53,79 @@ async def list_my_objects(db: DbDependency, current_user: HttpUser = Depends(get
modified_at=obj.modified_at modified_at=obj.modified_at
)) ))
return user_objects return user_objects
@router.post("/objects", response_model=ObjectSummary)
async def upload_object(
db: DbDependency,
file: UploadFile = File(...),
name: Optional[str] = Form(None),
private: bool = Form(True),
force_text: bool = Form(False), # NEW: force treat as UTF-8 text
current_user: HttpUser = Depends(get_current_http_user)
):
username = current_user.username
content = await file.read()
if not content:
raise HTTPException(status_code=400, detail="Empty file upload")
obj_name = (name or file.filename or "unnamed_object").strip()
if len(obj_name) > 300:
raise HTTPException(status_code=400, detail="Object name too long (max 300 chars)")
if not obj_name:
raise HTTPException(status_code=400, detail="Invalid object name")
try:
with db.transaction() as conn:
root = conn.root()
user = User.get_user_by_username(username, root)
if not user:
raise HTTPException(status_code=404, detail="User not found")
# Handle force_text logic
if force_text:
try:
text_content = content.decode('utf-8', errors='strict')
object_data = text_content # str → will set binary=False
except UnicodeDecodeError:
raise HTTPException(status_code=400, detail="Content is not valid UTF-8 and cannot be forced as text")
else:
object_data = content # bytes → will set binary=True
# Create and persist the object
new_object = Object(name=obj_name, data=object_data)
new_object.private = private
obj_uuid = new_object.write_new(db) # assuming write_new takes db and handles root.objects storage
new_object.chown(username, db)
if force_text:
obj_type = 'string'
else:
obj_type = 'binary'
logging.info(f"User {username} uploaded {obj_type} object {obj_uuid} ({obj_name}, {len(content)} bytes, force_text={force_text})")
except HTTPException:
raise
except Exception as e:
logging.error(f"Object upload failed for {username}: {e}\n{format_exc()}")
raise HTTPException(status_code=500, detail="Failed to store object")
# Build summary (matching your existing list endpoint)
content_type, _ = mimetypes.guess_type(new_object.name)
if content_type is None:
content_type = "application/octet-stream" if new_object.binary else "text/plain"
return ObjectSummary(
uuid=obj_uuid,
name=new_object.name,
binary=new_object.binary,
size=new_object.size,
content_type=content_type,
private=new_object.private,
created_at=new_object.created_at,
modified_at=new_object.modified_at
)

View File

@@ -6,6 +6,9 @@ from pathlib import Path
from .database import init_db from .database import init_db
from .routers import public, profile, messages, send from .routers import public, profile, messages, send
from .logging import init_logging
init_logging()
BASE_DIR = Path(__file__).parent.resolve() BASE_DIR = Path(__file__).parent.resolve()