2026-04-06 22:34:22 +02:00

347 lines
12 KiB
Python

from datetime import datetime
from fastapi import FastAPI, HTTPException, Query, Response, status
from .models import ChatMessage, Favorite, Follow, Prompt, Rating, User
from .schemas import (
AuthResponse,
ChatMessageCreateRequest,
ChatMessageResponse,
CreatorDetailResponse,
FavoriteCreateRequest,
FavoriteResponse,
FollowResponse,
LoginRequest,
ProfileUpdateRequest,
PromptCreateRequest,
PromptResponse,
PromptUpdateRequest,
RatingCreateRequest,
RatingResponse,
RegisterRequest,
UserResponse,
)
from .store import store
app = FastAPI(title="OnlyPrompt API", version="1.0.0")
def get_current_user() -> User:
user = store.users.get(store.current_user_id)
if user is None:
raise HTTPException(status_code=404, detail="Current user not found.")
return user
@app.post("/api/auth/register", response_model=AuthResponse, status_code=status.HTTP_201_CREATED)
def register(payload: RegisterRequest) -> AuthResponse:
if any(user.email == payload.email for user in store.users.values()):
raise HTTPException(status_code=400, detail="Email already exists.")
if any(user.username == payload.username for user in store.users.values()):
raise HTTPException(status_code=400, detail="Username already exists.")
now = datetime.utcnow()
user_id = store.next_id("user")
user = User(
id=user_id,
email=payload.email,
password_hash=payload.password,
full_name=payload.full_name,
username=payload.username,
bio="",
location="",
avatar_url="",
role=payload.role,
is_verified=False,
created_at=now,
)
store.users[user_id] = user
store.current_user_id = user_id
return AuthResponse(message="User created successfully.", user=UserResponse.model_validate(user))
@app.post("/api/auth/login", response_model=AuthResponse)
def login(payload: LoginRequest) -> AuthResponse:
user = next((item for item in store.users.values() if item.email == payload.email), None)
if user is None or user.password_hash != payload.password:
raise HTTPException(status_code=401, detail="Invalid email or password.")
store.current_user_id = user.id
return AuthResponse(message="Login successful.", user=UserResponse.model_validate(user))
@app.get("/api/prompts", response_model=list[PromptResponse])
def list_prompts(
category: str | None = Query(default=None),
search: str | None = Query(default=None),
) -> list[PromptResponse]:
prompts = list(store.prompts.values())
if category:
prompts = [prompt for prompt in prompts if prompt.category.lower() == category.lower()]
if search:
term = search.lower()
prompts = [
prompt
for prompt in prompts
if term in prompt.title.lower() or term in prompt.description.lower()
]
return [PromptResponse.model_validate(prompt) for prompt in prompts]
@app.get("/api/prompts/{prompt_id}", response_model=PromptResponse)
def get_prompt(prompt_id: int) -> PromptResponse:
prompt = store.prompts.get(prompt_id)
if prompt is None:
raise HTTPException(status_code=404, detail="Prompt not found.")
return PromptResponse.model_validate(prompt)
@app.post("/api/prompts", response_model=PromptResponse, status_code=status.HTTP_201_CREATED)
def create_prompt(payload: PromptCreateRequest) -> PromptResponse:
creator = store.users.get(payload.creator_id)
if creator is None or creator.role != "creator":
raise HTTPException(status_code=404, detail="Creator not found.")
prompt = Prompt(
id=store.next_id("prompt"),
title=payload.title,
description=payload.description,
content=payload.content,
image_url=payload.image_url,
category=payload.category,
price=payload.price,
creator_id=payload.creator_id,
created_at=datetime.utcnow(),
)
store.prompts[prompt.id] = prompt
return PromptResponse.model_validate(prompt)
@app.put("/api/prompts/{prompt_id}", response_model=PromptResponse)
def update_prompt(prompt_id: int, payload: PromptUpdateRequest) -> PromptResponse:
prompt = store.prompts.get(prompt_id)
if prompt is None:
raise HTTPException(status_code=404, detail="Prompt not found.")
updates = payload.model_dump(exclude_unset=True)
for field, value in updates.items():
setattr(prompt, field, value)
return PromptResponse.model_validate(prompt)
@app.delete("/api/prompts/{prompt_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_prompt(prompt_id: int) -> Response:
if prompt_id not in store.prompts:
raise HTTPException(status_code=404, detail="Prompt not found.")
del store.prompts[prompt_id]
return Response(status_code=status.HTTP_204_NO_CONTENT)
@app.get("/api/creators", response_model=list[UserResponse])
def list_creators(sort: str | None = Query(default=None)) -> list[UserResponse]:
creators = [user for user in store.users.values() if user.role == "creator"]
if sort == "new":
creators.sort(key=lambda item: item.created_at, reverse=True)
elif sort == "popular":
creators.sort(
key=lambda item: sum(1 for follow in store.follows.values() if follow.creator_id == item.id),
reverse=True,
)
elif sort == "top_rated":
def creator_rating(user: User) -> float:
creator_prompt_ids = [prompt.id for prompt in store.prompts.values() if prompt.creator_id == user.id]
ratings = [rating.score for rating in store.ratings.values() if rating.prompt_id in creator_prompt_ids]
return sum(ratings) / len(ratings) if ratings else 0
creators.sort(key=creator_rating, reverse=True)
return [UserResponse.model_validate(creator) for creator in creators]
@app.get("/api/creators/{creator_id}", response_model=CreatorDetailResponse)
def get_creator(creator_id: int) -> CreatorDetailResponse:
creator = store.users.get(creator_id)
if creator is None or creator.role != "creator":
raise HTTPException(status_code=404, detail="Creator not found.")
prompts = [prompt for prompt in store.prompts.values() if prompt.creator_id == creator_id]
return CreatorDetailResponse(
creator=UserResponse.model_validate(creator),
prompts=[PromptResponse.model_validate(prompt) for prompt in prompts],
)
@app.get("/api/prompts/{prompt_id}/ratings", response_model=list[RatingResponse])
def list_ratings(prompt_id: int) -> list[RatingResponse]:
if prompt_id not in store.prompts:
raise HTTPException(status_code=404, detail="Prompt not found.")
ratings = [rating for rating in store.ratings.values() if rating.prompt_id == prompt_id]
return [RatingResponse.model_validate(rating) for rating in ratings]
@app.post("/api/prompts/{prompt_id}/ratings", response_model=RatingResponse, status_code=status.HTTP_201_CREATED)
def create_rating(prompt_id: int, payload: RatingCreateRequest) -> RatingResponse:
if prompt_id not in store.prompts:
raise HTTPException(status_code=404, detail="Prompt not found.")
if payload.user_id not in store.users:
raise HTTPException(status_code=404, detail="User not found.")
rating = Rating(
id=store.next_id("rating"),
prompt_id=prompt_id,
user_id=payload.user_id,
score=payload.score,
comment=payload.comment,
created_at=datetime.utcnow(),
)
store.ratings[rating.id] = rating
return RatingResponse.model_validate(rating)
@app.get("/api/favorites", response_model=list[FavoriteResponse])
def list_favorites() -> list[FavoriteResponse]:
current_user = get_current_user()
favorites = [item for item in store.favorites.values() if item.user_id == current_user.id]
return [FavoriteResponse.model_validate(item) for item in favorites]
@app.post("/api/favorites", response_model=FavoriteResponse, status_code=status.HTTP_201_CREATED)
def create_favorite(payload: FavoriteCreateRequest) -> FavoriteResponse:
current_user = get_current_user()
if payload.prompt_id not in store.prompts:
raise HTTPException(status_code=404, detail="Prompt not found.")
existing = next(
(
item
for item in store.favorites.values()
if item.user_id == current_user.id and item.prompt_id == payload.prompt_id
),
None,
)
if existing is not None:
return FavoriteResponse.model_validate(existing)
favorite = Favorite(
id=store.next_id("favorite"),
user_id=current_user.id,
prompt_id=payload.prompt_id,
created_at=datetime.utcnow(),
)
store.favorites[favorite.id] = favorite
return FavoriteResponse.model_validate(favorite)
@app.delete("/api/favorites/{prompt_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_favorite(prompt_id: int) -> Response:
current_user = get_current_user()
favorite_id = next(
(
item.id
for item in store.favorites.values()
if item.user_id == current_user.id and item.prompt_id == prompt_id
),
None,
)
if favorite_id is None:
raise HTTPException(status_code=404, detail="Favorite not found.")
del store.favorites[favorite_id]
return Response(status_code=status.HTTP_204_NO_CONTENT)
@app.post("/api/follows/{creator_id}", response_model=FollowResponse, status_code=status.HTTP_201_CREATED)
def create_follow(creator_id: int) -> FollowResponse:
current_user = get_current_user()
creator = store.users.get(creator_id)
if creator is None or creator.role != "creator":
raise HTTPException(status_code=404, detail="Creator not found.")
existing = next(
(
item
for item in store.follows.values()
if item.follower_id == current_user.id and item.creator_id == creator_id
),
None,
)
if existing is not None:
return FollowResponse.model_validate(existing)
follow = Follow(
id=store.next_id("follow"),
follower_id=current_user.id,
creator_id=creator_id,
created_at=datetime.utcnow(),
)
store.follows[follow.id] = follow
return FollowResponse.model_validate(follow)
@app.delete("/api/follows/{creator_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_follow(creator_id: int) -> Response:
current_user = get_current_user()
follow_id = next(
(
item.id
for item in store.follows.values()
if item.follower_id == current_user.id and item.creator_id == creator_id
),
None,
)
if follow_id is None:
raise HTTPException(status_code=404, detail="Follow not found.")
del store.follows[follow_id]
return Response(status_code=status.HTTP_204_NO_CONTENT)
@app.get("/api/profile", response_model=UserResponse)
def get_profile() -> UserResponse:
return UserResponse.model_validate(get_current_user())
@app.put("/api/profile", response_model=UserResponse)
def update_profile(payload: ProfileUpdateRequest) -> UserResponse:
user = get_current_user()
updates = payload.model_dump(exclude_unset=True)
for field, value in updates.items():
setattr(user, field, value)
return UserResponse.model_validate(user)
@app.get("/api/chats/{user_id}", response_model=list[ChatMessageResponse])
def get_chat(user_id: int) -> list[ChatMessageResponse]:
current_user = get_current_user()
if user_id not in store.users:
raise HTTPException(status_code=404, detail="User not found.")
messages = [
message
for message in store.chat_messages.values()
if {message.sender_id, message.receiver_id} == {current_user.id, user_id}
]
messages.sort(key=lambda item: item.created_at)
return [ChatMessageResponse.model_validate(message) for message in messages]
@app.post("/api/chats", response_model=ChatMessageResponse, status_code=status.HTTP_201_CREATED)
def create_chat_message(payload: ChatMessageCreateRequest) -> ChatMessageResponse:
current_user = get_current_user()
if payload.receiver_id not in store.users:
raise HTTPException(status_code=404, detail="Receiver not found.")
message = ChatMessage(
id=store.next_id("chat_message"),
sender_id=current_user.id,
receiver_id=payload.receiver_id,
content=payload.content,
created_at=datetime.utcnow(),
)
store.chat_messages[message.id] = message
return ChatMessageResponse.model_validate(message)