-
Notifications
You must be signed in to change notification settings - Fork 0
Sub feat/crud genre song albums #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from 13 commits
932bcd0
1c9788e
52f2fde
da0dc1f
7de0683
5906821
6150156
53ed52c
94bb0aa
8b3c90e
3398683
49d058d
28f39a2
269864f
8fc2e54
40aad43
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,21 +1,41 @@ | ||
| # App Settings | ||
| app_name= | ||
| app_env= | ||
| app_version= | ||
|
|
||
| APP_NAME=musicstreamer | ||
| APP_ENV=development | ||
| APP_VERSION=1.0.0 | ||
|
|
||
| # Database Settings | ||
| postgres_db= | ||
| postgres_user= | ||
| postgres_password= | ||
| postgres_server= | ||
| postgres_port= | ||
| POSTGRES_DB=music_stream_secure | ||
| POSTGRES_USER=music_admin | ||
| POSTGRES_PASSWORD=your_secure_password_here | ||
| POSTGRES_SERVER=localhost | ||
| POSTGRES_PORT=5432 | ||
|
|
||
| # JWT Authentication | ||
| jwt_secret_key= | ||
| jwt_algorithm= | ||
| access_token_expire_minutes= | ||
| refresh_token_expire_minutes= | ||
| JWT_SECRET_KEY=your_jwt_secret_key_here | ||
| JWT_ALGORITHM=HS256 | ||
| ACCESS_TOKEN_EXPIRE_MINUTES=60 | ||
| REFRESH_TOKEN_EXPIRE_MINUTES=43200 | ||
|
|
||
| # Password Security | ||
| password_pepper= | ||
| PASSWORD_PEPPER=password_pepper_here | ||
|
|
||
| # Test User Credentials | ||
| TEST_ADMIN_USERNAME=test_admin | ||
| [email protected] | ||
| TEST_ADMIN_PASSWORD=AdminPass123! | ||
| TEST_ADMIN_FIRST_NAME=Test | ||
| TEST_ADMIN_LAST_NAME=Admin | ||
|
|
||
| TEST_MUSICIAN_USERNAME=test_musician | ||
| [email protected] | ||
| TEST_MUSICIAN_PASSWORD=MusicianPass123! | ||
| TEST_MUSICIAN_FIRST_NAME=Test | ||
| TEST_MUSICIAN_LAST_NAME=Musician | ||
| TEST_MUSICIAN_STAGE_NAME=Test Musician | ||
| TEST_MUSICIAN_BIO=A test musician for development | ||
|
|
||
| TEST_LISTENER_USERNAME=test_listener | ||
| [email protected] | ||
| TEST_LISTENER_PASSWORD=ListenerPass123! | ||
| TEST_LISTENER_FIRST_NAME=Test | ||
| TEST_LISTENER_LAST_NAME=Listener |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,207 @@ | ||
| from typing import List | ||
| from fastapi import APIRouter, Depends, HTTPException, status | ||
| from sqlalchemy.orm import Session | ||
| from app.db.session import get_db | ||
| from app.core.deps import get_current_admin | ||
| from app.schemas.genre import GenreCreate, GenreUpdate, GenreOut, GenreStats | ||
| from app.crud.genre import ( | ||
| create_genre, get_genre_by_id, get_genre_by_name, get_all_genres, | ||
| get_all_active_genres, update_genre, disable_genre, enable_genre, | ||
| genre_exists, genre_name_taken, get_genre_statistics | ||
| ) | ||
|
|
||
| router = APIRouter() | ||
|
|
||
|
|
||
| @router.get("/", response_model=List[GenreOut]) | ||
| async def get_active_genres(db: Session = Depends(get_db)): | ||
| """Get all active genres - public access""" | ||
| return get_all_active_genres(db) | ||
|
|
||
|
|
||
| @router.get("/{genre_id}", response_model=GenreOut) | ||
| async def get_genre(genre_id: int, db: Session = Depends(get_db)): | ||
| """Get a specific genre by ID - public access""" | ||
| genre = get_genre_by_id(db, genre_id) | ||
| if not genre: | ||
| raise HTTPException( | ||
| status_code=status.HTTP_404_NOT_FOUND, | ||
| detail="Genre not found" | ||
| ) | ||
| return genre | ||
|
|
||
|
|
||
| @router.get("/name/{name}", response_model=GenreOut) | ||
| async def get_genre_by_name_endpoint(name: str, db: Session = Depends(get_db)): | ||
| """Get a specific genre by name - public access""" | ||
| genre = get_genre_by_name(db, name) | ||
| if not genre: | ||
| raise HTTPException( | ||
| status_code=status.HTTP_404_NOT_FOUND, | ||
| detail="Genre not found" | ||
| ) | ||
| return genre | ||
|
|
||
|
|
||
| @router.post("/", response_model=GenreOut, status_code=status.HTTP_201_CREATED) | ||
| async def create_new_genre( | ||
| genre_data: GenreCreate, | ||
| db: Session = Depends(get_db), | ||
| current_admin: dict = Depends(get_current_admin) | ||
| ): | ||
| """Create a new genre - admin only""" | ||
| if genre_name_taken(db, genre_data.name): | ||
|
||
| raise HTTPException( | ||
| status_code=status.HTTP_409_CONFLICT, | ||
| detail="Genre name already exists" | ||
| ) | ||
|
|
||
| return create_genre(db, genre_data) | ||
|
|
||
|
|
||
| @router.put("/{genre_id}", response_model=GenreOut) | ||
| async def update_genre_endpoint( | ||
| genre_id: int, | ||
| genre_data: GenreUpdate, | ||
| db: Session = Depends(get_db), | ||
| current_admin: dict = Depends(get_current_admin) | ||
| ): | ||
| """Update a genre - admin only""" | ||
| if not genre_exists(db, genre_id): | ||
| raise HTTPException( | ||
| status_code=status.HTTP_404_NOT_FOUND, | ||
| detail="Genre not found" | ||
| ) | ||
|
|
||
| if genre_data.name and genre_name_taken(db, genre_data.name, exclude_genre_id=genre_id): | ||
| raise HTTPException( | ||
| status_code=status.HTTP_409_CONFLICT, | ||
| detail="Genre name already exists" | ||
| ) | ||
|
|
||
| updated_genre = update_genre(db, genre_id, genre_data) | ||
| if not updated_genre: | ||
| raise HTTPException( | ||
| status_code=status.HTTP_404_NOT_FOUND, | ||
| detail="Genre not found" | ||
| ) | ||
|
|
||
| return updated_genre | ||
|
|
||
|
|
||
| @router.patch("/{genre_id}", response_model=GenreOut) | ||
| async def partial_update_genre( | ||
| genre_id: int, | ||
| genre_data: GenreUpdate, | ||
| db: Session = Depends(get_db), | ||
| current_admin: dict = Depends(get_current_admin) | ||
| ): | ||
| """Partially update a genre - admin only""" | ||
| if not genre_exists(db, genre_id): | ||
| raise HTTPException( | ||
| status_code=status.HTTP_404_NOT_FOUND, | ||
| detail="Genre not found" | ||
| ) | ||
|
|
||
| if genre_data.name and genre_name_taken(db, genre_data.name, exclude_genre_id=genre_id): | ||
| raise HTTPException( | ||
| status_code=status.HTTP_409_CONFLICT, | ||
| detail="Genre name already exists" | ||
| ) | ||
|
|
||
| updated_genre = update_genre(db, genre_id, genre_data) | ||
| if not updated_genre: | ||
| raise HTTPException( | ||
| status_code=status.HTTP_404_NOT_FOUND, | ||
| detail="Genre not found" | ||
| ) | ||
|
|
||
| return updated_genre | ||
|
|
||
|
|
||
| @router.delete("/{genre_id}") | ||
| async def delete_genre( | ||
| genre_id: int, | ||
| db: Session = Depends(get_db), | ||
| current_admin: dict = Depends(get_current_admin) | ||
| ): | ||
| """Delete a genre - admin only""" | ||
| if not genre_exists(db, genre_id): | ||
| raise HTTPException( | ||
| status_code=status.HTTP_404_NOT_FOUND, | ||
| detail="Genre not found" | ||
| ) | ||
|
|
||
| success = disable_genre(db, genre_id) | ||
| if not success: | ||
| raise HTTPException( | ||
| status_code=status.HTTP_404_NOT_FOUND, | ||
| detail="Genre not found" | ||
| ) | ||
|
|
||
| return {"message": "Genre disabled successfully"} | ||
|
|
||
|
|
||
| @router.post("/{genre_id}/disable") | ||
| async def disable_genre_endpoint( | ||
| genre_id: int, | ||
| db: Session = Depends(get_db), | ||
| current_admin: dict = Depends(get_current_admin) | ||
| ): | ||
| """Disable a genre - admin only""" | ||
| if not genre_exists(db, genre_id): | ||
| raise HTTPException( | ||
| status_code=status.HTTP_404_NOT_FOUND, | ||
| detail="Genre not found" | ||
| ) | ||
|
|
||
| success = disable_genre(db, genre_id) | ||
| if not success: | ||
| raise HTTPException( | ||
| status_code=status.HTTP_404_NOT_FOUND, | ||
| detail="Genre not found" | ||
| ) | ||
|
|
||
| return {"message": "Genre disabled successfully"} | ||
|
|
||
|
|
||
| @router.post("/{genre_id}/enable") | ||
| async def enable_genre_endpoint( | ||
| genre_id: int, | ||
| db: Session = Depends(get_db), | ||
| current_admin: dict = Depends(get_current_admin) | ||
| ): | ||
| """Enable a genre - admin only""" | ||
| if not genre_exists(db, genre_id): | ||
| raise HTTPException( | ||
| status_code=status.HTTP_404_NOT_FOUND, | ||
| detail="Genre not found" | ||
| ) | ||
|
|
||
| success = enable_genre(db, genre_id) | ||
| if not success: | ||
| raise HTTPException( | ||
| status_code=status.HTTP_404_NOT_FOUND, | ||
| detail="Genre not found" | ||
| ) | ||
|
|
||
| return {"message": "Genre enabled successfully"} | ||
|
|
||
|
|
||
| @router.get("/admin/all", response_model=List[GenreOut]) | ||
| async def get_all_genres_admin( | ||
| db: Session = Depends(get_db), | ||
| current_admin: dict = Depends(get_current_admin) | ||
| ): | ||
| """Get all genres including inactive ones - admin only""" | ||
| return get_all_genres(db) | ||
|
|
||
|
|
||
| @router.get("/admin/statistics", response_model=GenreStats) | ||
| async def get_genre_statistics_endpoint( | ||
| db: Session = Depends(get_db), | ||
| current_admin: dict = Depends(get_current_admin) | ||
| ): | ||
| """Get genre statistics - admin only""" | ||
| stats = get_genre_statistics(db) | ||
| return GenreStats(**stats) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this API. Use a query-param to the GET genre API
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pushed updates and changes