fix: Consolidate get methods with JWT token resolution
This commit is contained in:
parent
253b8109cb
commit
8d2f3db6ba
63
src/crud.py
63
src/crud.py
|
|
@ -348,7 +348,22 @@ async def get_session(
|
|||
app_id: str,
|
||||
session_id: str,
|
||||
user_id: Optional[str] = None,
|
||||
) -> Optional[models.Session]:
|
||||
) -> models.Session:
|
||||
"""
|
||||
Get a session by ID for a specific user and app.
|
||||
|
||||
Args:
|
||||
db: Database session
|
||||
app_id: Public ID of the app
|
||||
session_id: Public ID of the session
|
||||
user_id: Optional public ID of the user
|
||||
|
||||
Returns:
|
||||
The session if found
|
||||
|
||||
Raises:
|
||||
ResourceNotFoundException: If the session does not exist or doesn't belong to the user
|
||||
"""
|
||||
stmt = (
|
||||
select(models.Session)
|
||||
.join(models.User, models.User.public_id == models.Session.user_id)
|
||||
|
|
@ -359,6 +374,11 @@ async def get_session(
|
|||
stmt = stmt.where(models.Session.user_id == user_id)
|
||||
result = await db.execute(stmt)
|
||||
session = result.scalar_one_or_none()
|
||||
if session is None:
|
||||
logger.warning(
|
||||
f"Session with ID '{session_id}' not found for user {user_id}"
|
||||
)
|
||||
raise ResourceNotFoundException("Session not found or does not belong to user")
|
||||
return session
|
||||
|
||||
|
||||
|
|
@ -750,10 +770,9 @@ async def get_message(
|
|||
select(models.Message)
|
||||
.join(models.Session, models.Session.public_id == models.Message.session_id)
|
||||
.join(models.User, models.User.public_id == models.Session.user_id)
|
||||
.join(models.App, models.App.public_id == models.User.app_id)
|
||||
.where(models.App.public_id == app_id)
|
||||
.where(models.User.app_id == app_id)
|
||||
.where(models.User.public_id == user_id)
|
||||
.where(models.Message.session_id == session_id)
|
||||
.where(models.Session.public_id == session_id)
|
||||
.where(models.Message.public_id == message_id)
|
||||
)
|
||||
result = await db.execute(stmt)
|
||||
|
|
@ -902,22 +921,20 @@ async def get_metamessage(
|
|||
stmt = (
|
||||
select(models.Metamessage)
|
||||
.join(models.User, models.User.public_id == models.Metamessage.user_id)
|
||||
.join(models.App, models.App.public_id == models.User.app_id)
|
||||
.where(models.App.public_id == app_id)
|
||||
.where(models.User.app_id == app_id)
|
||||
.where(models.User.public_id == user_id)
|
||||
.where(models.Metamessage.public_id == metamessage_id)
|
||||
)
|
||||
|
||||
# Add session filter if provided
|
||||
# Add optional filters
|
||||
if session_id is not None:
|
||||
stmt = stmt.where(models.Metamessage.session_id == session_id)
|
||||
|
||||
# Add message filter if provided
|
||||
if message_id is not None:
|
||||
stmt = stmt.where(models.Metamessage.message_id == message_id)
|
||||
|
||||
result = await db.execute(stmt)
|
||||
return result.scalar_one_or_none()
|
||||
metamessage = result.scalar_one_or_none()
|
||||
return metamessage
|
||||
|
||||
|
||||
async def update_metamessage(
|
||||
|
|
@ -927,25 +944,19 @@ async def update_metamessage(
|
|||
metamessage_id: str,
|
||||
) -> bool:
|
||||
# First retrieve the metamessage
|
||||
honcho_metamessage = await get_metamessage(
|
||||
db,
|
||||
app_id=app_id,
|
||||
user_id=metamessage.user_id,
|
||||
metamessage_id=metamessage_id,
|
||||
session_id=metamessage.session_id,
|
||||
message_id=metamessage.message_id,
|
||||
metamessage_obj = await get_metamessage(
|
||||
db, app_id=app_id, user_id=metamessage.user_id, metamessage_id=metamessage_id
|
||||
)
|
||||
|
||||
if honcho_metamessage is None:
|
||||
if metamessage_obj is None:
|
||||
raise ResourceNotFoundException(
|
||||
"Metamessage not found or does not belong to user"
|
||||
f"Metamessage with ID {metamessage_id} not found"
|
||||
)
|
||||
|
||||
# Validate the consistency of relationships if they're being changed
|
||||
# If we're setting message_id, we must have a session_id
|
||||
if metamessage.message_id is not None and metamessage.session_id is None:
|
||||
# If updating message_id but not session_id, use the existing session_id
|
||||
metamessage.session_id = honcho_metamessage.session_id
|
||||
metamessage.session_id = metamessage_obj.session_id
|
||||
if metamessage.session_id is None:
|
||||
raise ValidationException("Cannot specify message_id without session_id")
|
||||
|
||||
|
|
@ -965,19 +976,19 @@ async def update_metamessage(
|
|||
|
||||
# Update fields
|
||||
if metamessage.session_id is not None:
|
||||
honcho_metamessage.session_id = metamessage.session_id
|
||||
metamessage_obj.session_id = metamessage.session_id
|
||||
|
||||
if metamessage.message_id is not None:
|
||||
honcho_metamessage.message_id = metamessage.message_id
|
||||
metamessage_obj.message_id = metamessage.message_id
|
||||
|
||||
if metamessage.metadata is not None:
|
||||
honcho_metamessage.h_metadata = metamessage.metadata
|
||||
metamessage_obj.h_metadata = metamessage.metadata
|
||||
|
||||
if metamessage.metamessage_type is not None:
|
||||
honcho_metamessage.metamessage_type = metamessage.metamessage_type
|
||||
metamessage_obj.metamessage_type = metamessage.metamessage_type
|
||||
|
||||
await db.commit()
|
||||
return honcho_metamessage
|
||||
return metamessage_obj
|
||||
|
||||
|
||||
########################################################
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ from fastapi_pagination import add_pagination
|
|||
from sentry_sdk.integrations.fastapi import FastApiIntegration
|
||||
from sentry_sdk.integrations.starlette import StarletteIntegration
|
||||
|
||||
from src.db import engine, scaffold_db
|
||||
from src.db import engine
|
||||
from src.exceptions import HonchoException
|
||||
from src.routers import (
|
||||
apps,
|
||||
|
|
@ -25,7 +25,6 @@ from src.routers import (
|
|||
from src.security import create_admin_jwt
|
||||
|
||||
|
||||
|
||||
def get_log_level(env_var="LOG_LEVEL", default="INFO"):
|
||||
"""
|
||||
Convert log level string from environment variable to logging module constant.
|
||||
|
|
@ -70,7 +69,6 @@ SENTRY_ENABLED = os.getenv("SENTRY_ENABLED", "False").lower() == "true"
|
|||
if SENTRY_ENABLED:
|
||||
sentry_sdk.init(
|
||||
dsn=os.getenv("SENTRY_DSN"),
|
||||
enable_tracing=True,
|
||||
traces_sample_rate=0.4,
|
||||
profiles_sample_rate=0.4,
|
||||
integrations=[
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from fastapi_pagination import Page
|
||||
from fastapi_pagination.ext.sqlalchemy import paginate
|
||||
|
||||
from src import crud, schemas
|
||||
from src.dependencies import db
|
||||
from src.exceptions import AuthenticationException, ResourceNotFoundException
|
||||
from src.security import require_auth
|
||||
from src.security import JWTParams, require_auth
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -17,21 +17,60 @@ router = APIRouter(
|
|||
tags=["apps"],
|
||||
)
|
||||
|
||||
jwt_params = Depends(require_auth(app_id="app_id"))
|
||||
# jwt_params = Depends(require_auth(app_id="app_id"))
|
||||
|
||||
|
||||
@router.get(
|
||||
"",
|
||||
response_model=schemas.App,
|
||||
)
|
||||
async def get_app_from_token(jwt_params=jwt_params, db=db):
|
||||
@router.get("", response_model=schemas.App)
|
||||
async def get_app(
|
||||
app_id: Optional[str] = Query(
|
||||
None, description="App ID to retrieve. If not provided, uses JWT token"
|
||||
),
|
||||
jwt_params: JWTParams = Depends(require_auth()),
|
||||
db=db,
|
||||
):
|
||||
"""
|
||||
Get an App by ID from the app_id provided in the JWT.
|
||||
If no app_id is provided, return a 401 Unauthorized error.
|
||||
Get an App by ID.
|
||||
|
||||
If app_id is provided as a query parameter, it uses that (must match JWT app_id).
|
||||
Otherwise, it uses the app_id from the JWT token.
|
||||
"""
|
||||
if jwt_params.ap is None:
|
||||
raise AuthenticationException("App not found in JWT")
|
||||
return await crud.get_app(db, app_id=jwt_params.ap)
|
||||
# If app_id provided in query, check if it matches jwt or user is admin
|
||||
if app_id:
|
||||
if not jwt_params.ad and jwt_params.ap != app_id:
|
||||
raise AuthenticationException("Unauthorized access to resource")
|
||||
target_app_id = app_id
|
||||
else:
|
||||
# Use app_id from JWT
|
||||
if not jwt_params.ap:
|
||||
raise AuthenticationException("App ID not found in query parameter or JWT")
|
||||
target_app_id = jwt_params.ap
|
||||
|
||||
return await crud.get_app(db, app_id=target_app_id)
|
||||
|
||||
|
||||
# @router.get(
|
||||
# "",
|
||||
# response_model=schemas.App,
|
||||
# )
|
||||
# async def get_app_from_token(jwt_params=jwt_params, db=db):
|
||||
# """
|
||||
# Get an App by ID from the app_id provided in the JWT.
|
||||
# If no app_id is provided, return a 401 Unauthorized error.
|
||||
# """
|
||||
# if jwt_params.ap is None:
|
||||
# raise AuthenticationException("App not found in JWT")
|
||||
# return await crud.get_app(db, app_id=jwt_params.ap)
|
||||
#
|
||||
#
|
||||
# @router.get(
|
||||
# "/{app_id}",
|
||||
# response_model=schemas.App,
|
||||
# dependencies=[Depends(require_auth(app_id="app_id"))],
|
||||
# )
|
||||
# async def get_app(app_id: str, db=db):
|
||||
# """Get an App by ID"""
|
||||
# app = await crud.get_app(db, app_id=app_id)
|
||||
# return app
|
||||
|
||||
|
||||
@router.post(
|
||||
|
|
@ -55,17 +94,6 @@ async def get_all_apps(
|
|||
)
|
||||
|
||||
|
||||
@router.get(
|
||||
"/{app_id}",
|
||||
response_model=schemas.App,
|
||||
dependencies=[Depends(require_auth(app_id="app_id"))],
|
||||
)
|
||||
async def get_app(app_id: str, db=db):
|
||||
"""Get an App by ID"""
|
||||
app = await crud.get_app(db, app_id=app_id)
|
||||
return app
|
||||
|
||||
|
||||
@router.get(
|
||||
"/name/{name}",
|
||||
response_model=schemas.App,
|
||||
|
|
|
|||
|
|
@ -1,40 +1,65 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from fastapi_pagination import Page
|
||||
from fastapi_pagination.ext.sqlalchemy import paginate
|
||||
|
||||
from src import crud, schemas
|
||||
from src.dependencies import db
|
||||
from src.exceptions import AuthenticationException
|
||||
from src.security import require_auth
|
||||
from src.exceptions import AuthenticationException, ResourceNotFoundException
|
||||
from src.security import JWTParams, require_auth
|
||||
|
||||
router = APIRouter(
|
||||
prefix="/apps/{app_id}/users/{user_id}/collections",
|
||||
tags=["collections"],
|
||||
)
|
||||
|
||||
jwt_params = Depends(require_auth(collection_id="collection_id"))
|
||||
|
||||
|
||||
@router.get(
|
||||
"",
|
||||
response_model=schemas.Collection,
|
||||
)
|
||||
async def get_collection_from_token(
|
||||
async def get_collection(
|
||||
app_id: str,
|
||||
user_id: str,
|
||||
jwt_params=jwt_params,
|
||||
collection_id: Optional[str] = Query(
|
||||
None, description="Collection ID to retrieve. If not provided, uses JWT token"
|
||||
),
|
||||
jwt_params: JWTParams = Depends(require_auth()),
|
||||
db=db,
|
||||
):
|
||||
"""
|
||||
Get a specific collection for a user by collection_id provided in the JWT.
|
||||
If no collection_id is provided, return a 401 Unauthorized error.
|
||||
Get a specific collection for a user.
|
||||
|
||||
If collection_id is provided as a query parameter, it uses that (must match JWT collection_id).
|
||||
Otherwise, it uses the collection_id from the JWT token.
|
||||
"""
|
||||
if jwt_params.co is None:
|
||||
raise AuthenticationException("Collection not found in JWT")
|
||||
# Verify JWT has access to the requested resource
|
||||
if not jwt_params.ad:
|
||||
if jwt_params.ap is not None and jwt_params.ap != app_id:
|
||||
raise AuthenticationException("Unauthorized access to resource")
|
||||
if jwt_params.us is not None and jwt_params.us != user_id:
|
||||
raise AuthenticationException("Unauthorized access to resource")
|
||||
# If collection_id provided in query, check if it matches jwt or user is admin
|
||||
if collection_id:
|
||||
if (
|
||||
not jwt_params.ad
|
||||
and jwt_params.co is not None
|
||||
and jwt_params.co != collection_id
|
||||
):
|
||||
raise AuthenticationException("Unauthorized access to resource")
|
||||
target_collection_id = collection_id
|
||||
else:
|
||||
# Use collection_id from JWT
|
||||
if not jwt_params.co:
|
||||
raise AuthenticationException(
|
||||
"Collection ID not found in query parameter or JWT"
|
||||
)
|
||||
target_collection_id = jwt_params.co
|
||||
|
||||
# Let crud function handle the ResourceNotFoundException
|
||||
return await crud.get_collection_by_id(
|
||||
db, app_id=app_id, collection_id=jwt_params.co, user_id=user_id
|
||||
db, app_id=app_id, collection_id=target_collection_id, user_id=user_id
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -77,30 +102,6 @@ async def get_collection_by_name(
|
|||
return honcho_collection
|
||||
|
||||
|
||||
@router.get(
|
||||
"/{collection_id}",
|
||||
response_model=schemas.Collection,
|
||||
dependencies=[
|
||||
Depends(
|
||||
require_auth(
|
||||
app_id="app_id", user_id="user_id", collection_id="collection_id"
|
||||
)
|
||||
)
|
||||
],
|
||||
)
|
||||
async def get_collection_by_id(
|
||||
app_id: str,
|
||||
user_id: str,
|
||||
collection_id: str,
|
||||
db=db,
|
||||
) -> schemas.Collection:
|
||||
"""Get a Collection by ID"""
|
||||
honcho_collection = await crud.get_collection_by_id(
|
||||
db, app_id=app_id, user_id=user_id, collection_id=collection_id
|
||||
)
|
||||
return honcho_collection
|
||||
|
||||
|
||||
@router.post(
|
||||
"",
|
||||
response_model=schemas.Collection,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import logging
|
|||
from typing import Optional
|
||||
|
||||
from anthropic import MessageStreamManager
|
||||
from fastapi import APIRouter, Depends
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from fastapi.responses import StreamingResponse
|
||||
from fastapi_pagination import Page
|
||||
from fastapi_pagination.ext.sqlalchemy import paginate
|
||||
|
|
@ -14,7 +14,7 @@ from src.exceptions import (
|
|||
ResourceNotFoundException,
|
||||
ValidationException,
|
||||
)
|
||||
from src.security import require_auth
|
||||
from src.security import JWTParams, require_auth
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -23,27 +23,52 @@ router = APIRouter(
|
|||
tags=["sessions"],
|
||||
)
|
||||
|
||||
jwt_params = Depends(require_auth(session_id="session_id"))
|
||||
|
||||
|
||||
@router.get(
|
||||
"",
|
||||
response_model=schemas.Session,
|
||||
)
|
||||
async def get_session_from_token(
|
||||
async def get_session(
|
||||
app_id: str,
|
||||
user_id: str,
|
||||
jwt_params=jwt_params,
|
||||
session_id: Optional[str] = Query(
|
||||
None, description="Session ID to retrieve. If not provided, uses JWT token"
|
||||
),
|
||||
jwt_params: JWTParams = Depends(require_auth()),
|
||||
db=db,
|
||||
):
|
||||
"""
|
||||
Get a specific session for a user by session_id provided in the JWT.
|
||||
If no session_id is provided, return a 401 Unauthorized error.
|
||||
Get a specific session for a user.
|
||||
|
||||
If session_id is provided as a query parameter, it uses that (must match JWT session_id).
|
||||
Otherwise, it uses the session_id from the JWT token.
|
||||
"""
|
||||
if jwt_params.se is None:
|
||||
raise AuthenticationException("Session not found in JWT")
|
||||
# Verify JWT has access to the requested resource
|
||||
if not jwt_params.ad:
|
||||
if jwt_params.ap is not None and jwt_params.ap != app_id:
|
||||
raise AuthenticationException("Unauthorized access to resource")
|
||||
if jwt_params.us is not None and jwt_params.us != user_id:
|
||||
raise AuthenticationException("Unauthorized access to resource")
|
||||
# If session_id provided in query, check if it matches jwt or user is admin
|
||||
if session_id:
|
||||
if (
|
||||
not jwt_params.ad
|
||||
and jwt_params.se is not None
|
||||
and jwt_params.se != session_id
|
||||
):
|
||||
raise AuthenticationException("Unauthorized access to resource")
|
||||
target_session_id = session_id
|
||||
else:
|
||||
# Use session_id from JWT
|
||||
if not jwt_params.se:
|
||||
raise AuthenticationException(
|
||||
"Session ID not found in query parameter or JWT"
|
||||
)
|
||||
target_session_id = jwt_params.se
|
||||
|
||||
# Let crud function handle the ResourceNotFoundException
|
||||
return await crud.get_session(
|
||||
db, app_id=app_id, session_id=jwt_params.se, user_id=user_id
|
||||
db, app_id=app_id, session_id=target_session_id, user_id=user_id
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -150,31 +175,6 @@ async def delete_session(
|
|||
raise ResourceNotFoundException("Session not found") from e
|
||||
|
||||
|
||||
@router.get(
|
||||
"/{session_id}",
|
||||
response_model=schemas.Session,
|
||||
dependencies=[
|
||||
Depends(
|
||||
require_auth(app_id="app_id", user_id="user_id", session_id="session_id")
|
||||
)
|
||||
],
|
||||
)
|
||||
async def get_session(
|
||||
app_id: str,
|
||||
user_id: str,
|
||||
session_id: str,
|
||||
db=db,
|
||||
):
|
||||
"""Get a specific session for a user by ID"""
|
||||
honcho_session = await crud.get_session(
|
||||
db, app_id=app_id, session_id=session_id, user_id=user_id
|
||||
)
|
||||
if honcho_session is None:
|
||||
logger.warning(f"Session {session_id} not found for user {user_id}")
|
||||
raise ResourceNotFoundException(f"Session with ID {session_id} not found")
|
||||
return honcho_session
|
||||
|
||||
|
||||
@router.post(
|
||||
"/{session_id}/chat",
|
||||
response_model=schemas.AgentChat,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from fastapi_pagination import Page
|
||||
from fastapi_pagination.ext.sqlalchemy import paginate
|
||||
|
||||
|
|
@ -10,7 +11,7 @@ from src.exceptions import (
|
|||
AuthenticationException,
|
||||
ResourceNotFoundException,
|
||||
)
|
||||
from src.security import require_auth
|
||||
from src.security import JWTParams, require_auth
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -19,22 +20,6 @@ router = APIRouter(
|
|||
tags=["users"],
|
||||
)
|
||||
|
||||
jwt_params = Depends(require_auth(user_id="user_id"))
|
||||
|
||||
|
||||
@router.get(
|
||||
"",
|
||||
response_model=schemas.User,
|
||||
)
|
||||
async def get_user_from_token(app_id: str, jwt_params=jwt_params, db=db):
|
||||
"""
|
||||
Get a User by ID from the user_id provided in the JWT.
|
||||
If no user_id is provided, return a 401 Unauthorized error.
|
||||
"""
|
||||
if jwt_params.us is None:
|
||||
raise AuthenticationException("User not found in JWT")
|
||||
return await crud.get_user(db, app_id=app_id, user_id=jwt_params.us)
|
||||
|
||||
|
||||
@router.post(
|
||||
"",
|
||||
|
|
@ -69,6 +54,71 @@ async def get_users(
|
|||
)
|
||||
|
||||
|
||||
@router.get(
|
||||
"",
|
||||
response_model=schemas.User,
|
||||
)
|
||||
async def get_user(
|
||||
app_id: str,
|
||||
user_id: Optional[str] = Query(
|
||||
None, description="User ID to retrieve. If not provided, users JWT token"
|
||||
),
|
||||
jwt_params: JWTParams = Depends(require_auth()),
|
||||
db=db,
|
||||
):
|
||||
"""
|
||||
Get a User by ID
|
||||
|
||||
If user_id is provided as a query parameter, it uses that (must match JWT app_id).
|
||||
Otherwise, it uses the user_id from the JWT token.
|
||||
"""
|
||||
# validate app query param
|
||||
if not jwt_params.ad and jwt_params.ap is not None and jwt_params.ap != app_id:
|
||||
raise AuthenticationException("Unauthorized access to resource")
|
||||
|
||||
if user_id:
|
||||
if not jwt_params.ad and jwt_params.us is not None and jwt_params.us != user_id:
|
||||
raise AuthenticationException("Unauthorized access to resource")
|
||||
target_user_id = user_id
|
||||
else:
|
||||
# Use user_id from JWT
|
||||
if not jwt_params.us:
|
||||
raise AuthenticationException("User ID not found in query parameter or JWT")
|
||||
target_user_id = jwt_params.us
|
||||
user = await crud.get_user(db, app_id=app_id, user_id=target_user_id)
|
||||
return user
|
||||
|
||||
|
||||
# @router.get(
|
||||
# "",
|
||||
# response_model=schemas.User,
|
||||
# )
|
||||
# async def get_user_from_token(app_id: str, jwt_params=jwt_params, db=db):
|
||||
# """
|
||||
# Get a User by ID from the user_id provided in the JWT.
|
||||
# If no user_id is provided, return a 401 Unauthorized error.
|
||||
# """
|
||||
# if jwt_params.us is None:
|
||||
# raise AuthenticationException("User not found in JWT")
|
||||
# return await crud.get_user(db, app_id=app_id, user_id=jwt_params.us)
|
||||
#
|
||||
#
|
||||
# @router.get(
|
||||
# "/{user_id}",
|
||||
# response_model=schemas.User,
|
||||
# dependencies=[Depends(require_auth(app_id="app_id", user_id="user_id"))],
|
||||
# )
|
||||
# async def get_user(
|
||||
# app_id: str,
|
||||
# user_id: str,
|
||||
# db=db,
|
||||
# ):
|
||||
# """Get a User by ID"""
|
||||
# user = await crud.get_user(db, app_id=app_id, user_id=user_id)
|
||||
# return user
|
||||
#
|
||||
|
||||
|
||||
@router.get(
|
||||
"/name/{name}",
|
||||
response_model=schemas.User,
|
||||
|
|
@ -90,21 +140,6 @@ async def get_user_by_name(
|
|||
return user
|
||||
|
||||
|
||||
@router.get(
|
||||
"/{user_id}",
|
||||
response_model=schemas.User,
|
||||
dependencies=[Depends(require_auth(app_id="app_id", user_id="user_id"))],
|
||||
)
|
||||
async def get_user(
|
||||
app_id: str,
|
||||
user_id: str,
|
||||
db=db,
|
||||
):
|
||||
"""Get a User by ID"""
|
||||
user = await crud.get_user(db, app_id=app_id, user_id=user_id)
|
||||
return user
|
||||
|
||||
|
||||
@router.get(
|
||||
"/get_or_create/{name}",
|
||||
response_model=schemas.User,
|
||||
|
|
|
|||
|
|
@ -123,11 +123,26 @@ def require_auth(
|
|||
credentials: HTTPAuthorizationCredentials = Depends(security),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
app_id_param = request.path_params.get(app_id) if app_id else None
|
||||
user_id_param = request.path_params.get(user_id) if user_id else None
|
||||
session_id_param = request.path_params.get(session_id) if session_id else None
|
||||
app_id_param = (
|
||||
request.path_params.get(app_id) or request.query_params.get(app_id)
|
||||
if app_id
|
||||
else None
|
||||
)
|
||||
user_id_param = (
|
||||
request.path_params.get(user_id) or request.query_params.get(user_id)
|
||||
if user_id
|
||||
else None
|
||||
)
|
||||
session_id_param = (
|
||||
request.path_params.get(session_id) or request.query_params.get(session_id)
|
||||
if session_id
|
||||
else None
|
||||
)
|
||||
collection_id_param = (
|
||||
request.path_params.get(collection_id) if collection_id else None
|
||||
request.path_params.get(collection_id)
|
||||
or request.query_params.get(collection_id)
|
||||
if collection_id
|
||||
else None
|
||||
)
|
||||
|
||||
return await auth(
|
||||
|
|
@ -181,6 +196,8 @@ async def auth(
|
|||
return jwt_params
|
||||
|
||||
if any([session_id, collection_id, user_id, app_id]):
|
||||
print([session_id, collection_id, user_id, app_id])
|
||||
print(jwt_params)
|
||||
raise AuthenticationException("JWT not permissioned for this resource")
|
||||
|
||||
# Route did not specify any parameters, so it should parse parameters itself
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import os
|
|||
import sys
|
||||
import jwt
|
||||
from nanoid import generate as generate_nanoid
|
||||
from unittest.mock import patch, MagicMock
|
||||
from unittest.mock import patch, MagicMock, AsyncMock
|
||||
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
|
|
@ -235,4 +235,14 @@ def mock_langfuse():
|
|||
for handler in logging.getLogger().handlers[:]:
|
||||
if isinstance(handler, TestHandler):
|
||||
handler.close()
|
||||
logging.getLogger().removeHandler(handler)
|
||||
logging.getLogger().removeHandler(handler)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def mock_openai_embeddings():
|
||||
"""Mock OpenAI embeddings API calls for testing"""
|
||||
with patch("src.crud.openai_client.embeddings.create") as mock_create:
|
||||
mock_response = AsyncMock()
|
||||
mock_response.data = [MagicMock(embedding=[0.1] * 1536)]
|
||||
mock_create.return_value = mock_response
|
||||
yield mock_create
|
||||
|
|
@ -74,7 +74,7 @@ def test_get_or_create_existing_app(client):
|
|||
|
||||
def test_get_app_by_id(client, sample_data):
|
||||
test_app, _ = sample_data
|
||||
response = client.get(f"/v1/apps/{test_app.public_id}")
|
||||
response = client.get(f"/v1/apps?app_id={test_app.public_id}")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["name"] == test_app.name
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ def test_get_collection_by_id(client, sample_data) -> None:
|
|||
data = response.json()
|
||||
# Get the collection
|
||||
response = client.get(
|
||||
f"/v1/apps/{test_app.public_id}/users/{test_user.public_id}/collections/{data['id']}"
|
||||
f"/v1/apps/{test_app.public_id}/users/{test_user.public_id}/collections?collection_id={data['id']}"
|
||||
)
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
|
|
@ -127,6 +127,6 @@ def test_delete_collection(client, sample_data) -> None:
|
|||
)
|
||||
assert response.status_code == 200
|
||||
response = client.get(
|
||||
f"/v1/apps/{test_app.public_id}/users/{test_user.public_id}/collections/{data['id']}"
|
||||
f"/v1/apps/{test_app.public_id}/users/{test_user.public_id}/collections?collection_id={data['id']}"
|
||||
)
|
||||
assert response.status_code == 404
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ def test_get_app_by_id_with_auth(auth_client, sample_data):
|
|||
f"Bearer {create_jwt(JWTParams(ap=test_app.public_id))}"
|
||||
)
|
||||
|
||||
response = auth_client.get(f"/v1/apps/{test_app.public_id}")
|
||||
response = auth_client.get(f"/v1/apps?app_id={test_app.public_id}")
|
||||
|
||||
# Admin JWT or JWT with matching app_id should be allowed
|
||||
if auth_client.auth_type in ["admin", "empty"]:
|
||||
|
|
@ -198,7 +198,7 @@ def test_get_user_by_id_with_auth(auth_client, sample_data):
|
|||
)
|
||||
|
||||
response = auth_client.get(
|
||||
f"/v1/apps/{test_app.public_id}/users/{test_user.public_id}"
|
||||
f"/v1/apps/{test_app.public_id}/users?user_id={test_user.public_id}"
|
||||
)
|
||||
|
||||
# Admin JWT or JWT with matching app_id should be allowed
|
||||
|
|
@ -214,11 +214,19 @@ def test_get_user_by_id_with_auth(auth_client, sample_data):
|
|||
)
|
||||
|
||||
response = auth_client.get(
|
||||
f"/v1/apps/{test_app.public_id}/users/{test_user.public_id}"
|
||||
f"/v1/apps/{test_app.public_id}/users?user_id={test_user.public_id}"
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
response2 = auth_client.get(f"/v1/apps/{test_app.public_id}/users")
|
||||
|
||||
assert response2.status_code == 200
|
||||
|
||||
print(response2.json())
|
||||
|
||||
assert response2.json()["id"] == test_user.public_id
|
||||
|
||||
|
||||
def test_get_user_by_name_with_auth(auth_client, sample_data):
|
||||
test_app, test_user = sample_data
|
||||
|
|
@ -335,7 +343,7 @@ def test_get_session_by_id_with_auth(auth_client, sample_data):
|
|||
|
||||
# Test with app and user scoped JWT
|
||||
response = auth_client.get(
|
||||
f"/v1/apps/{test_app.public_id}/users/{test_user.public_id}/sessions/{session_id}"
|
||||
f"/v1/apps/{test_app.public_id}/users/{test_user.public_id}/sessions?session_id={session_id}"
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
|
|
@ -346,10 +354,18 @@ def test_get_session_by_id_with_auth(auth_client, sample_data):
|
|||
)
|
||||
|
||||
response = auth_client.get(
|
||||
f"/v1/apps/{test_app.public_id}/users/{test_user.public_id}/sessions/{session_id}"
|
||||
f"/v1/apps/{test_app.public_id}/users/{test_user.public_id}/sessions?session_id={session_id}"
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
response2 = auth_client.get(
|
||||
f"/v1/apps/{test_app.public_id}/users/{test_user.public_id}/sessions"
|
||||
)
|
||||
|
||||
assert response2.status_code == 200
|
||||
|
||||
assert response2.json()["id"] == session_id
|
||||
|
||||
|
||||
def test_create_collection(auth_client, sample_data) -> None:
|
||||
test_app, test_user = sample_data
|
||||
|
|
@ -421,7 +437,7 @@ def test_get_collection_by_id_with_auth(auth_client, sample_data) -> None:
|
|||
|
||||
# Test with app and user scoped JWT
|
||||
response = auth_client.get(
|
||||
f"/v1/apps/{test_app.public_id}/users/{test_user.public_id}/collections/{collection_id}"
|
||||
f"/v1/apps/{test_app.public_id}/users/{test_user.public_id}/collections?collection_id={collection_id}"
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
|
|
@ -432,10 +448,17 @@ def test_get_collection_by_id_with_auth(auth_client, sample_data) -> None:
|
|||
)
|
||||
|
||||
response = auth_client.get(
|
||||
f"/v1/apps/{test_app.public_id}/users/{test_user.public_id}/collections/{collection_id}"
|
||||
f"/v1/apps/{test_app.public_id}/users/{test_user.public_id}/collections?collection_id={collection_id}"
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
# Test auto resolution of ID
|
||||
response2 = auth_client.get(
|
||||
f"/v1/apps/{test_app.public_id}/users/{test_user.public_id}/collections"
|
||||
)
|
||||
assert response2.status_code == 200
|
||||
assert response2.json()["id"] == collection_id
|
||||
|
||||
|
||||
def test_get_collection_by_name_with_auth(auth_client, sample_data) -> None:
|
||||
test_app, test_user = sample_data
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ async def test_delete_session(client, db_session, sample_data):
|
|||
)
|
||||
assert response.status_code == 200
|
||||
response = client.get(
|
||||
f"/v1/apps/{test_app.public_id}/users/{test_user.public_id}/sessions/{test_session.public_id}"
|
||||
f"/v1/apps/{test_app.public_id}/users/{test_user.public_id}/sessions?session_id={test_session.public_id}"
|
||||
)
|
||||
data = response.json()
|
||||
assert data["is_active"] is False
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ def test_create_user(client, sample_data):
|
|||
|
||||
def test_get_user_by_id(client, sample_data):
|
||||
test_app, test_user = sample_data
|
||||
response = client.get(f"/v1/apps/{test_app.public_id}/users/{test_user.public_id}")
|
||||
response = client.get(f"/v1/apps/{test_app.public_id}/users?user_id={test_user.public_id}")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["name"] == test_user.name
|
||||
|
|
|
|||
Loading…
Reference in New Issue