diff --git a/backend/src/xfd_django/xfd_api/api_methods/api_key.py b/backend/src/xfd_django/xfd_api/api_methods/api_key.py index 73d666e7..09ba1910 100644 --- a/backend/src/xfd_django/xfd_api/api_methods/api_key.py +++ b/backend/src/xfd_django/xfd_api/api_methods/api_key.py @@ -1,6 +1,7 @@ """/api-keys API logic""" # Standard Python Libraries +from datetime import datetime, timezone import hashlib import secrets import uuid @@ -12,26 +13,33 @@ def post(current_user): - """POST API LOGIC""" + """POST API logic for creating a new API key.""" # Generate a random 16-byte API key key = secrets.token_hex(16) # Hash the API key hashed_key = hashlib.sha256(key.encode()).hexdigest() - # Create with schema validation - api_key = ApiKeySchema( + # Create ApiKey instance in the database + api_key_instance = ApiKey.objects.create( id=uuid.uuid4(), hashedKey=hashed_key, lastFour=key[-4:], userId=current_user, + createdAt=datetime.utcnow(), + updatedAt=datetime.utcnow(), ) - # Return Serialized data from Schema - return ApiKeySchema.model_validate(api_key).model_dump( - exclude={"hashedKey", "userId"}, api_key=key + # Convert the Django model instance to the Pydantic model, excluding fields like hashedKey and userId + validated_data = ApiKeySchema.model_validate(api_key_instance).model_dump( + exclude={"hashedKey", "userId"} ) + # Add the actual API key to the response for initial display to the user + validated_data["api_key"] = key + + return validated_data + def delete(id, current_user): """DELETE API LOGIC""" diff --git a/backend/src/xfd_django/xfd_api/schema_models/api_key.py b/backend/src/xfd_django/xfd_api/schema_models/api_key.py index 84df02af..b6d59558 100644 --- a/backend/src/xfd_django/xfd_api/schema_models/api_key.py +++ b/backend/src/xfd_django/xfd_api/schema_models/api_key.py @@ -7,6 +7,35 @@ # Third-Party Libraries from pydantic import BaseModel, ConfigDict +# class ApiKey(BaseModel): +# """Pydantic model for the ApiKey model.""" + +# id: UUID +# createdAt: datetime +# updatedAt: datetime +# lastUsed: Optional[datetime] +# hashedKey: Optional[str] +# lastFour: Optional[str] +# userId: Optional[UUID] + +# @classmethod +# def model_validate(cls, obj): +# # Ensure that we convert the UUIDs to strings when validating +# api_key_data = obj.__dict__.copy() + +# # Remove the '_state' field or any other unwanted internal Django fields +# api_key_data.pop("_state", None) +# api_key_data["userId"] = api_key_data.pop("userId_id", None) + +# for key, val in api_key_data.items(): +# # Convert any UUIDs to strings +# if isinstance(val, UUID): +# api_key_data[key] = str(val) +# return cls(**api_key_data) + +# class Config: +# from_attributes = True + class ApiKey(BaseModel): """Pydantic model for the ApiKey model.""" @@ -15,16 +44,21 @@ class ApiKey(BaseModel): createdAt: datetime updatedAt: datetime lastUsed: Optional[datetime] - hashedKey: Optional[str] + hashedKey: Optional[ + str + ] = None # Make optional to avoid validation error in response lastFour: Optional[str] - userId: Optional[UUID] + userId: Optional[UUID] = None # Make optional to avoid validation error in response + api_key: Optional[ + str + ] = None # Add the actual key to the schema for response inclusion @classmethod def model_validate(cls, obj): # Ensure that we convert the UUIDs to strings when validating api_key_data = obj.__dict__.copy() - # Remove the '_state' field or any other unwanted internal Django fields + # Remove the '_state' field or any other unwanted internal fields api_key_data.pop("_state", None) api_key_data["userId"] = api_key_data.pop("userId_id", None)