a working product with ugly ui

This commit is contained in:
2025-12-12 20:15:27 +05:00
parent e6d04f986f
commit 4d3085623a
77 changed files with 8750 additions and 0 deletions
View File
+80
View File
@@ -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
+90
View File
@@ -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
+94
View File
@@ -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