a working product with ugly ui
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlalchemy.orm import Session
|
||||
from app.database import get_db
|
||||
from app.dependencies import get_current_user
|
||||
from app.schemas.auth import LoginRequest, TokenResponse
|
||||
from app.schemas.user import UserCreate, UserResponse, UserWithToken
|
||||
from app.services.auth_service import authenticate_user, create_user, create_tokens_for_user
|
||||
from app.models.user import User
|
||||
|
||||
router = APIRouter(prefix="/api/auth", tags=["authentication"])
|
||||
|
||||
|
||||
@router.post("/register", response_model=UserWithToken, status_code=status.HTTP_201_CREATED)
|
||||
async def register(
|
||||
user_data: UserCreate,
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""
|
||||
Register a new user.
|
||||
Registration must be enabled via ALLOW_REGISTRATION environment variable.
|
||||
"""
|
||||
user = create_user(db, user_data)
|
||||
tokens = create_tokens_for_user(user)
|
||||
|
||||
return UserWithToken(
|
||||
id=user.id,
|
||||
username=user.username,
|
||||
email=user.email,
|
||||
is_admin=user.is_admin,
|
||||
created_at=user.created_at,
|
||||
updated_at=user.updated_at,
|
||||
access_token=tokens.access_token,
|
||||
refresh_token=tokens.refresh_token,
|
||||
token_type=tokens.token_type
|
||||
)
|
||||
|
||||
|
||||
@router.post("/login", response_model=TokenResponse)
|
||||
async def login(
|
||||
credentials: LoginRequest,
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""
|
||||
Login with username and password.
|
||||
Returns JWT access and refresh tokens.
|
||||
"""
|
||||
user = authenticate_user(db, credentials.username, credentials.password)
|
||||
tokens = create_tokens_for_user(user)
|
||||
|
||||
return tokens
|
||||
|
||||
|
||||
@router.get("/me", response_model=UserResponse)
|
||||
async def get_current_user_info(
|
||||
current_user: User = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Get current authenticated user information.
|
||||
Requires valid JWT token in Authorization header.
|
||||
"""
|
||||
return UserResponse(
|
||||
id=current_user.id,
|
||||
username=current_user.username,
|
||||
email=current_user.email,
|
||||
is_admin=current_user.is_admin,
|
||||
created_at=current_user.created_at,
|
||||
updated_at=current_user.updated_at
|
||||
)
|
||||
|
||||
|
||||
@router.post("/refresh", response_model=TokenResponse)
|
||||
async def refresh_access_token(
|
||||
current_user: User = Depends(get_current_user)
|
||||
):
|
||||
"""
|
||||
Refresh access token using a valid refresh token.
|
||||
Returns new access and refresh tokens.
|
||||
"""
|
||||
tokens = create_tokens_for_user(current_user)
|
||||
return tokens
|
||||
@@ -0,0 +1,90 @@
|
||||
"""Map items router for CRUD operations."""
|
||||
from typing import List
|
||||
from uuid import UUID
|
||||
from fastapi import APIRouter, Depends, status
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.database import get_db
|
||||
from app.dependencies import get_current_user, get_optional_current_user
|
||||
from app.models.user import User
|
||||
from app.schemas.map_item import MapItemCreate, MapItemUpdate, MapItemResponse
|
||||
from app.services import item_service
|
||||
from app.services.item_service import geography_to_geojson
|
||||
|
||||
|
||||
router = APIRouter(prefix="/api/maps/{map_id}/items", tags=["map-items"])
|
||||
|
||||
|
||||
def format_item_response(item) -> dict:
|
||||
"""Format map item for response with GeoJSON geometry."""
|
||||
return {
|
||||
"id": str(item.id),
|
||||
"map_id": str(item.map_id),
|
||||
"type": item.type,
|
||||
"geometry": geography_to_geojson(item.geometry),
|
||||
"properties": item.properties,
|
||||
"created_at": item.created_at.isoformat(),
|
||||
"updated_at": item.updated_at.isoformat(),
|
||||
"created_by": str(item.created_by) if item.created_by else None,
|
||||
"updated_by": str(item.updated_by) if item.updated_by else None,
|
||||
}
|
||||
|
||||
|
||||
@router.get("", response_model=List[dict])
|
||||
async def list_map_items(
|
||||
map_id: UUID,
|
||||
current_user: User = Depends(get_optional_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get all items for a map."""
|
||||
items = item_service.get_map_items(db, map_id, current_user)
|
||||
return [format_item_response(item) for item in items]
|
||||
|
||||
|
||||
@router.post("", response_model=dict, status_code=status.HTTP_201_CREATED)
|
||||
async def create_map_item(
|
||||
map_id: UUID,
|
||||
item_data: MapItemCreate,
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Create a new map item."""
|
||||
item = item_service.create_map_item(db, map_id, item_data, current_user)
|
||||
return format_item_response(item)
|
||||
|
||||
|
||||
@router.get("/{item_id}", response_model=dict)
|
||||
async def get_map_item(
|
||||
map_id: UUID,
|
||||
item_id: UUID,
|
||||
current_user: User = Depends(get_optional_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get a specific map item."""
|
||||
item = item_service.get_map_item_by_id(db, item_id, current_user)
|
||||
return format_item_response(item)
|
||||
|
||||
|
||||
@router.patch("/{item_id}", response_model=dict)
|
||||
async def update_map_item(
|
||||
map_id: UUID,
|
||||
item_id: UUID,
|
||||
item_data: MapItemUpdate,
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Update a map item."""
|
||||
item = item_service.update_map_item(db, item_id, item_data, current_user)
|
||||
return format_item_response(item)
|
||||
|
||||
|
||||
@router.delete("/{item_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_map_item(
|
||||
map_id: UUID,
|
||||
item_id: UUID,
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Delete a map item."""
|
||||
item_service.delete_map_item(db, item_id, current_user)
|
||||
return None
|
||||
@@ -0,0 +1,94 @@
|
||||
"""Maps router for CRUD operations."""
|
||||
from typing import List
|
||||
from uuid import UUID
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.database import get_db
|
||||
from app.dependencies import get_current_user, get_optional_current_user
|
||||
from app.models.user import User
|
||||
from app.schemas.map import MapCreate, MapUpdate, MapResponse
|
||||
from app.services import map_service
|
||||
|
||||
|
||||
router = APIRouter(prefix="/api/maps", tags=["maps"])
|
||||
|
||||
|
||||
@router.get("", response_model=List[MapResponse])
|
||||
async def list_user_maps(
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get all maps owned by the current user."""
|
||||
maps = map_service.get_user_maps(db, current_user.id)
|
||||
return maps
|
||||
|
||||
|
||||
@router.post("", response_model=MapResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def create_map(
|
||||
map_data: MapCreate,
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Create a new map."""
|
||||
new_map = map_service.create_map(db, map_data, current_user.id)
|
||||
return new_map
|
||||
|
||||
|
||||
@router.get("/public", response_model=MapResponse)
|
||||
async def get_public_map(db: Session = Depends(get_db)):
|
||||
"""Get the default public map (no authentication required)."""
|
||||
public_map = map_service.get_default_public_map(db)
|
||||
|
||||
if not public_map:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="No public map available"
|
||||
)
|
||||
|
||||
return public_map
|
||||
|
||||
|
||||
@router.get("/{map_id}", response_model=MapResponse)
|
||||
async def get_map(
|
||||
map_id: UUID,
|
||||
current_user: User = Depends(get_optional_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get a specific map by ID. Requires authentication unless it's the public map."""
|
||||
map_obj = map_service.get_map_by_id(db, map_id, current_user)
|
||||
return map_obj
|
||||
|
||||
|
||||
@router.patch("/{map_id}", response_model=MapResponse)
|
||||
async def update_map(
|
||||
map_id: UUID,
|
||||
map_data: MapUpdate,
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Update a map. Only the owner or admin can update."""
|
||||
updated_map = map_service.update_map(db, map_id, map_data, current_user)
|
||||
return updated_map
|
||||
|
||||
|
||||
@router.delete("/{map_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_map(
|
||||
map_id: UUID,
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Delete a map. Only the owner or admin can delete."""
|
||||
map_service.delete_map(db, map_id, current_user)
|
||||
return None
|
||||
|
||||
|
||||
@router.post("/{map_id}/set-default-public", response_model=MapResponse)
|
||||
async def set_default_public(
|
||||
map_id: UUID,
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Set a map as the default public map. Admin only."""
|
||||
updated_map = map_service.set_default_public_map(db, map_id, current_user)
|
||||
return updated_map
|
||||
Reference in New Issue
Block a user