diff --git a/app/api/api_v1/api.py b/app/api/api_v1/api.py
index 93e29a7..4d9a457 100644
--- a/app/api/api_v1/api.py
+++ b/app/api/api_v1/api.py
@@ -4,9 +4,13 @@ from app.api.api_v1.endpoints import users
from app.api.api_v1.endpoints import login
from app.api.api_v1.endpoints import player
from app.api.api_v1.endpoints import team
+from app.api.api_v1.endpoints import match
+from app.api.api_v1.endpoints import matchday
api_router = APIRouter()
api_router.include_router(login.router, tags=["login"])
api_router.include_router(users.router, prefix="/users", tags=["users"])
api_router.include_router(player.router, prefix="/player", tags=["player"])
api_router.include_router(team.router, prefix="/team", tags=["team"])
+api_router.include_router(matchday.router, prefix="/matchday", tags=["matchday"])
+#api_router.include_router(match.router, prefix="/match", tags=["match"])
diff --git a/app/api/api_v1/endpoints/login.py b/app/api/api_v1/endpoints/login.py
index 783971d..8765553 100644
--- a/app/api/api_v1/endpoints/login.py
+++ b/app/api/api_v1/endpoints/login.py
@@ -5,11 +5,14 @@ from fastapi import APIRouter, Body, Depends, HTTPException
from fastapi.security import OAuth2PasswordRequestForm
from sqlalchemy.orm import Session
-from app import crud, models, schemas
+from app import crud
from app.api import deps
from app.core import security
from app.core.config import settings
from app.core.security import get_password_hash
+from app.models.msg import Msg
+from app.models.token import Token
+from app.models.user import User
from app.utils import (
generate_password_reset_token,
send_reset_password_email,
@@ -19,7 +22,7 @@ from app.utils import (
router = APIRouter()
-@router.post("/login/access-token", response_model=schemas.Token)
+@router.post("/login/access-token", response_model=Token)
def login_access_token(
db: Session = Depends(deps.get_db),
form_data: OAuth2PasswordRequestForm = Depends(),
@@ -47,9 +50,9 @@ def login_access_token(
}
-@router.post("/login/test-token", response_model=schemas.User)
+@router.post("/login/test-token", response_model=User)
def test_token(
- current_user: models.User = Depends(deps.get_current_user),
+ current_user: User = Depends(deps.get_current_user),
) -> Any:
"""
Test access token
@@ -57,7 +60,7 @@ def test_token(
return current_user
-@router.post("/password-recovery/{email}", response_model=schemas.Msg)
+@router.post("/password-recovery/{email}", response_model=Msg)
def recover_password(email: str, db: Session = Depends(deps.get_db)) -> Any:
"""
Password Recovery
@@ -76,7 +79,7 @@ def recover_password(email: str, db: Session = Depends(deps.get_db)) -> Any:
return {"msg": "Password recovery email sent"}
-@router.post("/reset-password/", response_model=schemas.Msg)
+@router.post("/reset-password/", response_model=Msg)
def reset_password(
token: str = Body(...),
new_password: str = Body(...),
diff --git a/app/api/api_v1/endpoints/match.py b/app/api/api_v1/endpoints/match.py
new file mode 100644
index 0000000..1f43fed
--- /dev/null
+++ b/app/api/api_v1/endpoints/match.py
@@ -0,0 +1,96 @@
+from typing import Any, List
+
+from fastapi import APIRouter, Body, Depends, HTTPException
+from fastapi.encoders import jsonable_encoder
+from pydantic.networks import EmailStr
+from sqlalchemy.orm import Session
+
+from app import crud
+from app.api import deps
+
+from app.models.player import Player, PlayerCreate, PlayerUpdate
+from app.models.user import User
+
+router = APIRouter()
+
+
+@router.get("/{id}", response_model=Player)
+def read_player(
+ *,
+ db: Session = Depends(deps.get_db),
+ firstname: str,
+ lastname: str,
+ current_user: User = Depends(deps.get_current_active_user),
+) -> Any:
+ """
+ Get player by firstname and lastname.
+ """
+ player = crud.player.get_player_by_name(
+ db=db, firstname=firstname, lastname=lastname
+ )
+ if not player:
+ raise HTTPException(status_code=404, detail="player not found")
+ if not crud.user.is_superuser(current_user):
+ raise HTTPException(status_code=400, detail="Not enough permissions")
+ return player
+
+
+@router.post("/", response_model=List[Player])
+def create_player(
+ *,
+ db: Session = Depends(deps.get_db),
+ players_in: list[PlayerCreate],
+ current_user: User = Depends(deps.get_current_active_superuser),
+) -> Any:
+ """
+ Create new user.
+ """
+ player_out = []
+ for player_in in players_in:
+ player = crud.player.get_player_by_name(
+ db, firstname=player_in.firstname, lastname=player_in.lastname
+ )
+ if player:
+ raise HTTPException(
+ status_code=400,
+ detail=f"The user with this username already exists in the "
+ f"system. Player is {player}",
+ )
+ player = crud.player.create(db, obj_in=player_in)
+ player_out.append(player)
+
+ return player_out
+
+
+@router.get("/", response_model=List[Player])
+def get_players(
+ db: Session = Depends(deps.get_db),
+ skip: int = 0,
+ limit: int = 100,
+ current_user: User = Depends(deps.get_current_active_superuser),
+) -> Any:
+ """
+ Retrieve all players.
+ """
+ player = crud.player.get_multi(db, skip=skip, limit=limit)
+ return player
+
+
+@router.post("/{id}", response_model=Player)
+def update_player(
+ *,
+ db: Session = Depends(deps.get_db),
+ id: int,
+ player_in: PlayerUpdate,
+ current_user: User = Depends(deps.get_current_active_user),
+) -> Any:
+ """
+ Update player.
+ """
+
+ player = crud.player.get(db=db, id=id)
+ if not player:
+ raise HTTPException(status_code=404, detail="Player not found")
+
+ player = crud.player.update(db=db, db_obj=player, obj_in=player_in)
+ return player
diff --git a/app/api/api_v1/endpoints/matchday.py b/app/api/api_v1/endpoints/matchday.py
new file mode 100644
index 0000000..ce32531
--- /dev/null
+++ b/app/api/api_v1/endpoints/matchday.py
@@ -0,0 +1,114 @@
+from typing import Any, List
+
+from fastapi import APIRouter, Depends, HTTPException
+from sqlalchemy.orm import Session
+
+from app import crud
+from app.api import deps
+
+from app.models.matchday import Matchday, MatchdayCreate, MatchdayUpdate, \
+ MatchdayWithPlayers
+from app.models.user import User
+
+router = APIRouter()
+
+
+@router.get("/{matchday_id}", response_model=MatchdayWithPlayers)
+def read_matchday(
+ *,
+ db: Session = Depends(deps.get_db),
+ matchday_id: int,
+ current_user: User = Depends(deps.get_current_active_user),
+) -> Any:
+ """
+ Get matchday by firstname and lastname.
+ """
+ matchday = crud.matchday.get(
+ db=db, id=matchday_id
+ )
+ if not matchday:
+ raise HTTPException(status_code=404, detail="matchday not found")
+ if not crud.user.is_superuser(current_user):
+ raise HTTPException(status_code=400, detail="Not enough permissions")
+ return matchday
+
+
+@router.post("/", response_model=Matchday)
+def create_matchday(
+ *,
+ db: Session = Depends(deps.get_db),
+ matchday_in: MatchdayCreate,
+ current_user: User = Depends(deps.get_current_active_superuser),
+) -> Any:
+ """
+ Create new user.
+ """
+ matchday = crud.matchday.get_unique_day(db, obj_in=matchday_in)
+ if matchday:
+ raise HTTPException(
+ status_code=400,
+ detail=f"The matchday with this day already exists in the "
+ f"system. Matchday is {matchday}",
+ )
+ matchday = crud.matchday.create(db, obj_in=matchday_in)
+
+ return matchday
+
+
+@router.get("/", response_model=List[MatchdayWithPlayers])
+def get_matchdays(
+ db: Session = Depends(deps.get_db),
+ skip: int = 0,
+ limit: int = 100,
+ current_user: User = Depends(deps.get_current_active_superuser),
+) -> Any:
+ """
+ Retrieve all matchdays.
+ """
+ matchday = crud.matchday.get_multi(db, skip=skip, limit=limit)
+ return matchday
+
+
+@router.post("/{matchday_id}", response_model=Matchday)
+def update_matchday(
+ *,
+ db: Session = Depends(deps.get_db),
+ matchday_id: int,
+ matchday_in: MatchdayUpdate,
+ current_user: User = Depends(deps.get_current_active_user),
+) -> Any:
+ """
+ Update matchday.
+ """
+
+ matchday = crud.matchday.get(db=db, id=matchday_id)
+ if not matchday:
+ raise HTTPException(status_code=404, detail="Matchday not found")
+
+ matchday = crud.matchday.update(db=db, db_obj=matchday, obj_in=matchday_in)
+ return matchday
+
+
+@router.put("/players/{matchday_id}", response_model=Matchday)
+def add_player_matchday(
+ *,
+ db: Session = Depends(deps.get_db),
+ player_id: int,
+ matchday_id: int,
+ current_user: User = Depends(deps.get_current_active_superuser),
+) -> Any:
+ """
+ Add player to matchday.
+ """
+ if crud.player.get(db, id=player_id) is None:
+ raise HTTPException(status_code=404, detail="Player not found")
+ if crud.matchday.get(db=db, id=matchday_id) is None:
+ raise HTTPException(status_code=404, detail="Matchday not found")
+ if crud.matchday.is_player_in_matchday(
+ db=db, player_id=player_id, matchday_id=matchday_id
+ ):
+ raise HTTPException(
+ status_code=404, detail="Player is already in team"
+ )
+ matchday = crud.matchday.add_player_in_matchday(db, matchday_id, player_id)
+ return matchday
diff --git a/app/api/api_v1/endpoints/player.py b/app/api/api_v1/endpoints/player.py
index 3a53ea5..0078c02 100644
--- a/app/api/api_v1/endpoints/player.py
+++ b/app/api/api_v1/endpoints/player.py
@@ -1,31 +1,30 @@
from typing import Any, List
-from fastapi import APIRouter, Body, Depends, HTTPException
-from fastapi.encoders import jsonable_encoder
-from pydantic.networks import EmailStr
+from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
-from app import crud, models, schemas
+from app import crud
from app.api import deps
-from app.core.config import settings
-from app.schemas.player import PlayerUpdate
+
+from app.models.player import Player, PlayerCreate, PlayerUpdate, \
+ PlayerTeamsMatchdays
+from app.models.user import User
router = APIRouter()
-@router.get("/{id}", response_model=schemas.Player)
+@router.get("/{player_id}", response_model=PlayerTeamsMatchdays)
def read_player(
*,
db: Session = Depends(deps.get_db),
- firstname: str,
- lastname: str,
- current_user: models.User = Depends(deps.get_current_active_user),
+ player_id: int,
+ current_user: User = Depends(deps.get_current_active_user),
) -> Any:
"""
- Get player by firstname and lastname.
+ Get player by id.
"""
- player = crud.player.get_player_by_name(
- db=db, firstname=firstname, lastname=lastname
+ player = crud.player.get(
+ db=db, id=player_id
)
if not player:
raise HTTPException(status_code=404, detail="player not found")
@@ -34,56 +33,60 @@ def read_player(
return player
-@router.post("/", response_model=schemas.Player)
+@router.post("/", response_model=List[Player])
def create_player(
*,
db: Session = Depends(deps.get_db),
- player_in: schemas.PlayerCreate,
- current_user: models.User = Depends(deps.get_current_active_superuser),
+ players_in: list[PlayerCreate],
+ current_user: User = Depends(deps.get_current_active_superuser),
) -> Any:
"""
Create new user.
"""
- player = crud.player.get_player_by_name(
- db, firstname=player_in.firstname, lastname=player_in.lastname
- )
- if player:
- raise HTTPException(
- status_code=400,
- detail="The user with this username already exists in the system.",
+ player_out = []
+ for player_in in players_in:
+ player = crud.player.get_player_by_name(
+ db, firstname=player_in.firstname, lastname=player_in.lastname
)
- player = crud.player.create(db, obj_in=player_in)
+ if player:
+ raise HTTPException(
+ status_code=400,
+ detail=f"The user with this username already exists in the "
+ f"system. Player is {player}",
+ )
+ player = crud.player.create(db, obj_in=player_in)
+ player_out.append(player)
- return player
+ return player_out
-@router.get("/", response_model=List[schemas.Player])
+@router.get("/", response_model=List[PlayerTeamsMatchdays])
def get_players(
db: Session = Depends(deps.get_db),
skip: int = 0,
limit: int = 100,
- current_user: models.User = Depends(deps.get_current_active_superuser),
+ current_user: User = Depends(deps.get_current_active_superuser),
) -> Any:
"""
Retrieve all players.
"""
- player = crud.player.get_players(db, skip=skip, limit=limit)
+ player = crud.player.get_multi(db, skip=skip, limit=limit)
return player
-@router.post("/{id}", response_model=schemas.Player)
+@router.post("/{player_id}", response_model=Player)
def update_player(
*,
db: Session = Depends(deps.get_db),
- id: int,
+ player_id: int,
player_in: PlayerUpdate,
- current_user: models.User = Depends(deps.get_current_active_user),
+ current_user: User = Depends(deps.get_current_active_user),
) -> Any:
"""
Update player.
"""
- player = crud.player.get(db=db, id=id)
+ player = crud.player.get(db=db, id=player_id)
if not player:
raise HTTPException(status_code=404, detail="Player not found")
diff --git a/app/api/api_v1/endpoints/team.py b/app/api/api_v1/endpoints/team.py
index 0d87c92..2650111 100644
--- a/app/api/api_v1/endpoints/team.py
+++ b/app/api/api_v1/endpoints/team.py
@@ -4,24 +4,25 @@ from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
-from app import crud, models, schemas
+from app import crud
from app.api import deps
-
+from app.models.team import Team, TeamCreate, TeamWithPlayers
+from app.models.user import User
router = APIRouter()
-@router.get("/{id}", response_model=schemas.Team)
+@router.get("/{team_id}", response_model=Team)
def get_team(
*,
db: Session = Depends(deps.get_db),
- id: int,
- current_user: models.User = Depends(deps.get_current_active_user),
+ team_id: int,
+ current_user: User = Depends(deps.get_current_active_user),
) -> Any:
"""
Get team by id.
"""
- team = crud.team.get_team(db=db, team_id=id)
+ team = crud.team.get_team(db=db, team_id=team_id)
if not team:
raise HTTPException(status_code=404, detail="player not found")
if not crud.user.is_superuser(current_user):
@@ -29,26 +30,26 @@ def get_team(
return team
-@router.get("/", response_model=List[schemas.Team])
+@router.get("/", response_model=List[TeamWithPlayers])
def get_teams(
db: Session = Depends(deps.get_db),
skip: int = 0,
limit: int = 100,
- current_user: models.User = Depends(deps.get_current_active_superuser),
+ current_user: User = Depends(deps.get_current_active_superuser),
) -> Any:
"""
Retrieve teams.
"""
- team = crud.team.get_teams(db, skip=skip, limit=limit)
+ team = crud.team.get_multi( db, skip=skip, limit=limit)
return team
-@router.post("/", response_model=schemas.Team)
+@router.post("/", response_model=Team)
def create_team(
*,
db: Session = Depends(deps.get_db),
- team_in: schemas.TeamCreate,
- current_user: models.User = Depends(deps.get_current_active_superuser),
+ team_in: TeamCreate,
+ current_user: User = Depends(deps.get_current_active_superuser),
) -> Any:
"""
Create team.
@@ -59,20 +60,20 @@ def create_team(
return team
-@router.put("/players/{team_id}", response_model=schemas.Team)
+@router.put("/players/{team_id}", response_model=Team)
def add_player_team(
*,
db: Session = Depends(deps.get_db),
player_id: int,
team_id: int,
- current_user: models.User = Depends(deps.get_current_active_superuser),
+ current_user: User = Depends(deps.get_current_active_superuser),
) -> Any:
"""
Add player to team.
"""
- if crud.player.get_player(db, player_id=player_id) is None:
+ if crud.player.get(db, id=player_id) is None:
raise HTTPException(status_code=404, detail="Player not found")
- if crud.team.get_team(db=db, team_id=team_id) is None:
+ if crud.team.get(db=db, id=team_id) is None:
raise HTTPException(status_code=404, detail="Team not found")
if crud.team.is_player_in_team(
db=db, player_id=player_id, team_id=team_id
diff --git a/app/api/api_v1/endpoints/users.py b/app/api/api_v1/endpoints/users.py
index ef5e9a0..6e4c92d 100644
--- a/app/api/api_v1/endpoints/users.py
+++ b/app/api/api_v1/endpoints/users.py
@@ -5,20 +5,20 @@ from fastapi.encoders import jsonable_encoder
from pydantic.networks import EmailStr
from sqlalchemy.orm import Session
-from app import crud, models, schemas
+from app import crud, models
from app.api import deps
from app.core.config import settings
-
+from app.models.user import UserUpdate, User, UserCreate
router = APIRouter()
-@router.get("/", response_model=List[schemas.User])
+@router.get("/", response_model=List[User])
def read_users(
db: Session = Depends(deps.get_db),
skip: int = 0,
limit: int = 100,
- current_user: models.User = Depends(deps.get_current_active_superuser),
+ current_user: User = Depends(deps.get_current_active_superuser),
) -> Any:
"""
Retrieve users.
@@ -27,12 +27,12 @@ def read_users(
return users
-@router.post("/", response_model=schemas.User)
+@router.post("/", response_model=User)
def create_user(
*,
db: Session = Depends(deps.get_db),
- user_in: schemas.UserCreate,
- current_user: models.User = Depends(deps.get_current_active_superuser),
+ user_in: UserCreate,
+ current_user: User = Depends(deps.get_current_active_superuser),
) -> Any:
"""
Create new user.
@@ -48,20 +48,20 @@ def create_user(
return user
-@router.put("/me", response_model=schemas.User)
+@router.put("/me", response_model=User)
def update_user_me(
*,
db: Session = Depends(deps.get_db),
password: str = Body(None),
full_name: str = Body(None),
email: EmailStr = Body(None),
- current_user: models.User = Depends(deps.get_current_active_user),
+ current_user: User = Depends(deps.get_current_active_user),
) -> Any:
"""
Update own user.
"""
current_user_data = jsonable_encoder(current_user)
- user_in = schemas.UserUpdate(**current_user_data)
+ user_in = UserUpdate(**current_user_data)
if password is not None:
user_in.password = password
if full_name is not None:
@@ -72,10 +72,10 @@ def update_user_me(
return user
-@router.get("/me", response_model=schemas.User)
+@router.get("/me", response_model=User)
def read_user_me(
db: Session = Depends(deps.get_db),
- current_user: models.User = Depends(deps.get_current_active_user),
+ current_user: User = Depends(deps.get_current_active_user),
) -> Any:
"""
Get current user.
@@ -83,7 +83,7 @@ def read_user_me(
return current_user
-@router.post("/open", response_model=schemas.User)
+@router.post("/open", response_model=User)
def create_user_open(
*,
db: Session = Depends(deps.get_db),
@@ -105,17 +105,17 @@ def create_user_open(
status_code=400,
detail="The user with this username already exists in the system",
)
- user_in = schemas.UserCreate(
+ user_in = UserCreate(
password=password, email=email, full_name=full_name
)
user = crud.user.create(db, obj_in=user_in)
return user
-@router.get("/{user_id}", response_model=schemas.User)
+@router.get("/{user_id}", response_model=User)
def read_user_by_id(
user_id: int,
- current_user: models.User = Depends(deps.get_current_active_user),
+ current_user: User = Depends(deps.get_current_active_user),
db: Session = Depends(deps.get_db),
) -> Any:
"""
@@ -131,13 +131,13 @@ def read_user_by_id(
return user
-@router.put("/{user_id}", response_model=schemas.User)
+@router.put("/{user_id}", response_model=User)
def update_user(
*,
db: Session = Depends(deps.get_db),
user_id: int,
- user_in: schemas.UserUpdate,
- current_user: models.User = Depends(deps.get_current_active_superuser),
+ user_in: UserUpdate,
+ current_user: User = Depends(deps.get_current_active_superuser),
) -> Any:
"""
Update a user.
diff --git a/app/api/deps.py b/app/api/deps.py
index 304650e..59d2b78 100644
--- a/app/api/deps.py
+++ b/app/api/deps.py
@@ -6,7 +6,9 @@ from jose import jwt
from pydantic import ValidationError
from sqlalchemy.orm import Session
-from app import crud, models, schemas
+from app import crud
+from app.models.token import TokenPayload
+from app.models.user import User
from app.core import security
from app.core.config import settings
from app.db.session import SessionLocal
@@ -26,12 +28,12 @@ def get_db() -> Generator:
def get_current_user(
db: Session = Depends(get_db), token: str = Depends(reusable_oauth2)
-) -> models.User:
+) -> User:
try:
payload = jwt.decode(
token, settings.SECRET_KEY, algorithms=[security.ALGORITHM]
)
- token_data = schemas.TokenPayload(**payload)
+ token_data = TokenPayload(**payload)
except (jwt.JWTError, ValidationError):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
@@ -44,16 +46,17 @@ def get_current_user(
def get_current_active_user(
- current_user: models.User = Depends(get_current_user),
-) -> models.User:
+ current_user: User = Depends(get_current_user),
+) -> User:
if not crud.user.is_active(current_user):
raise HTTPException(status_code=400, detail="Inactive user")
return current_user
def get_current_active_superuser(
- current_user: models.User = Depends(get_current_user),
-) -> models.User:
+ current_user: User = Depends(get_current_user),
+) -> User:
+
if not crud.user.is_superuser(current_user):
raise HTTPException(
status_code=400, detail="The user doesn't have enough privileges"
diff --git a/app/crud/__init__.py b/app/crud/__init__.py
index fa14f0f..7275570 100644
--- a/app/crud/__init__.py
+++ b/app/crud/__init__.py
@@ -1,3 +1,4 @@
from .crud_user import user
from .crud_player import player
from .crud_team import team
+from .crud_matchday import matchday
diff --git a/app/crud/base.py b/app/crud/base.py
index aff4e9c..83ef4a0 100644
--- a/app/crud/base.py
+++ b/app/crud/base.py
@@ -3,6 +3,7 @@ from typing import Any, Dict, Generic, List, Optional, Type, TypeVar, Union
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel
from sqlalchemy.orm import Session
+from sqlmodel import select
from app.db.base_class import Base
@@ -22,12 +23,14 @@ class CRUDBase(Generic[ModelType, CreateSchemaType, UpdateSchemaType]):
self.model = model
def get(self, db: Session, id: Any) -> Optional[ModelType]:
- return db.query(self.model).filter(self.model.id == id).first()
+ statement = select(self.model).where(self.model.id == id)
+ return db.execute(statement).scalar_one_or_none()
def get_multi(
self, db: Session, *, skip: int = 0, limit: int = 100
) -> List[ModelType]:
- return db.query(self.model).offset(skip).limit(limit).all()
+ statement = select(self.model).offset(skip).limit(limit)
+ return db.execute(statement).scalars().all()
def create(self, db: Session, *, obj_in: CreateSchemaType) -> ModelType:
obj_in_data = jsonable_encoder(obj_in)
@@ -58,7 +61,7 @@ class CRUDBase(Generic[ModelType, CreateSchemaType, UpdateSchemaType]):
return db_obj
def remove(self, db: Session, *, id: int) -> ModelType:
- obj = db.query(self.model).get(id)
+ obj = db.execute(self.model).get(id)
db.delete(obj)
db.commit()
return obj
diff --git a/app/crud/crud_matchday.py b/app/crud/crud_matchday.py
new file mode 100644
index 0000000..5ae875e
--- /dev/null
+++ b/app/crud/crud_matchday.py
@@ -0,0 +1,45 @@
+from typing import Any, Dict, Union, Optional
+
+from sqlmodel import select
+from sqlalchemy.orm import Session
+
+from app.crud import player as crud_player
+from app.crud.base import CRUDBase
+from app.models.matchday import Matchday, MatchdayCreate, MatchdayUpdate
+
+
+class CRUDMatchday(CRUDBase[Matchday, MatchdayCreate, MatchdayUpdate]):
+
+ def create(self, db: Session, *, obj_in: MatchdayCreate) -> Matchday:
+ db_obj = Matchday(
+ day=obj_in.day)
+
+ db.add(db_obj)
+ db.commit()
+ db.refresh(db_obj)
+ return db_obj
+
+ def get_unique_day(self, db: Session, *, obj_in: Matchday) -> Any:
+ day = obj_in.day
+ statement = select(Matchday).where(Matchday.day == day)
+ result = db.execute(statement).all()
+ return result
+
+ def add_player_in_matchday(self, db: Session, matchday_id: int, player_id: int
+ ) -> Matchday:
+ matchday_in = self.get(db=db, id=matchday_id)
+ db_player = crud_player.get(db=db, id=player_id)
+ matchday_in.players.append(db_player)
+ db.commit()
+ return matchday_in
+
+ def is_player_in_matchday(
+ self, db: Session, *, player_id: int, matchday_id: int
+ ) -> bool:
+ matchday = self.get(db=db, id=matchday_id)
+ if matchday is None:
+ return False
+ db_player = crud_player.get(db=db, id=player_id)
+ return db_player in matchday.players
+
+matchday = CRUDMatchday(Matchday)
\ No newline at end of file
diff --git a/app/crud/crud_player.py b/app/crud/crud_player.py
index a098b2e..5a60cef 100644
--- a/app/crud/crud_player.py
+++ b/app/crud/crud_player.py
@@ -3,8 +3,7 @@ from typing import Any, Dict, Optional, Union
from sqlalchemy.orm import Session
from app.crud.base import CRUDBase
-from app.models.player import Player
-from app.schemas.player import PlayerCreate, PlayerUpdate, PlayerUpdateTeam
+from app.models.player import Player, PlayerCreate, PlayerUpdate
class CRUDPlayer(CRUDBase[Player, PlayerCreate, PlayerUpdate]):
@@ -21,12 +20,6 @@ class CRUDPlayer(CRUDBase[Player, PlayerCreate, PlayerUpdate]):
.first()
)
- def get_player(self, db: Session, *, player_id: int) -> Optional[Player]:
- return db.query(Player).filter(Player.id == player_id).first()
-
- def get_players(self, db: Session, skip: int = 0, limit: int = 100):
- return db.query(Player).offset(skip).limit(limit).all()
-
def create(self, db: Session, *, obj_in: PlayerCreate) -> Player:
db_obj = Player(
firstname=obj_in.firstname,
@@ -38,4 +31,5 @@ class CRUDPlayer(CRUDBase[Player, PlayerCreate, PlayerUpdate]):
return db_obj
+
player = CRUDPlayer(Player)
diff --git a/app/crud/crud_team.py b/app/crud/crud_team.py
index cf5c0ba..6e7162c 100644
--- a/app/crud/crud_team.py
+++ b/app/crud/crud_team.py
@@ -1,22 +1,14 @@
from typing import Any, Dict, Optional, Union, List
from sqlalchemy.orm import Session
+from sqlmodel import select
from app.crud.base import CRUDBase
from app.crud import player as crud_player
-from app.models.team import Team
-
-from app.schemas.team import TeamCreate, TeamUpdate
+from app.models.team import Team, TeamCreate, TeamUpdate
class CRUDTeam(CRUDBase[Team, TeamCreate, TeamUpdate]):
- def get_team(self, db: Session, *, team_id: int) -> Optional[Team]:
- return db.query(Team).filter(Team.team_id == team_id).first()
-
- def get_teams(
- self, db: Session, skip: int = 0, limit: int = 100
- ) -> List[Team]:
- return db.query(Team).offset(skip).limit(limit).all()
def create(self, db: Session, *, obj_in: TeamCreate) -> Team:
db_obj = Team(teamname=obj_in.teamname)
@@ -28,19 +20,19 @@ class CRUDTeam(CRUDBase[Team, TeamCreate, TeamUpdate]):
def add_player_in_team(
self, db: Session, team_id: int, player_id: int
) -> Team:
- team = self.get_team(db=db, team_id=team_id)
- db_player = crud_player.get_player(db=db, player_id=player_id)
- team.players.append(db_player)
+ team_in = self.get(db=db, id=team_id)
+ db_player = crud_player.get(db=db, id=player_id)
+ team_in.players.append(db_player)
db.commit()
- return team
+ return team_in
def is_player_in_team(
self, db: Session, *, player_id: int, team_id: int
) -> bool:
- team = self.get_team(db=db, team_id=team_id)
+ team = self.get(db=db, id=team_id)
if team is None:
return False
- db_player = crud_player.get_player(db=db, player_id=player_id)
+ db_player = crud_player.get(db=db, id=player_id)
return db_player in team.players
diff --git a/app/crud/crud_user.py b/app/crud/crud_user.py
index 0e99461..514182c 100644
--- a/app/crud/crud_user.py
+++ b/app/crud/crud_user.py
@@ -4,8 +4,8 @@ from sqlalchemy.orm import Session
from app.core.security import get_password_hash, verify_password
from app.crud.base import CRUDBase
-from app.models.user import User
-from app.schemas.user import UserCreate, UserUpdate
+from app.models.user import User, UserCreate, UserUpdate
+
class CRUDUser(CRUDBase[User, UserCreate, UserUpdate]):
diff --git a/app/db/base_class.py b/app/db/base_class.py
index 29f272d..e78f140 100644
--- a/app/db/base_class.py
+++ b/app/db/base_class.py
@@ -1,13 +1,12 @@
-from typing import Any
+from typing import Optional
-from sqlalchemy.ext.declarative import as_declarative, declared_attr
+from sqlalchemy.ext.declarative import declared_attr
+from sqlmodel import Field, SQLModel
-@as_declarative()
-class Base:
- id: Any
+class Base(SQLModel):
+ id: Optional[int] = Field(default=None, primary_key=True, index=True)
__name__: str
# Generate __tablename__ automatically
- @declared_attr
- def __tablename__(cls) -> str:
- return cls.__name__.lower()
+
+
diff --git a/app/db/init_db.py b/app/db/init_db.py
index 5d553e7..78d8445 100644
--- a/app/db/init_db.py
+++ b/app/db/init_db.py
@@ -1,6 +1,6 @@
from sqlalchemy.orm import Session
-from app import crud, schemas
+from app import crud
from app.core.config import settings
from app.db import base # noqa: F401
@@ -9,6 +9,9 @@ from app.db import base # noqa: F401
# for more details: https://github.com/tiangolo/full-stack-fastapi-postgresql/issues/28
from app.db.base_class import Base
from app.db.session import engine
+from app.models.player import Player, PlayerCreate
+from app.models.team import TeamCreate, TeamWithPlayers
+from app.models.user import UserCreate
def init_db(db: Session) -> None:
@@ -19,9 +22,34 @@ def init_db(db: Session) -> None:
user = crud.user.get_by_email(db, email=settings.FIRST_SUPERUSER)
if not user:
- user_in = schemas.UserCreate(
+ user_in = UserCreate(
email=settings.FIRST_SUPERUSER,
password=settings.FIRST_SUPERUSER_PASSWORD,
is_superuser=True,
)
user = crud.user.create(db, obj_in=user_in) # noqa: F841
+
+ players = crud.player.get_multi(db=db)
+
+ if not players:
+
+ player_in = PlayerCreate(
+ firstname="Simon",
+ lastname="Milvert",
+ )
+
+ player = crud.player.create(db=db, obj_in=player_in) # noqa: F841
+ player_in = PlayerCreate(
+ firstname="Johan",
+ lastname="Moden")
+
+
+ player = crud.player.create(db=db, obj_in=player_in) # noqa: F841
+
+ teams = crud.team.get_multi(db=db)
+
+ if not True:
+ print("Create Team")
+ player = crud.player.get(db, id=1)
+ team_in = TeamWithPlayers(teamname='1', players=[player])
+ team = crud.team.create(db, obj_in=team_in) # noqa: F841
\ No newline at end of file
diff --git a/app/db/session.py b/app/db/session.py
index 0c38a58..1d434f2 100644
--- a/app/db/session.py
+++ b/app/db/session.py
@@ -1,7 +1,13 @@
-from sqlalchemy import create_engine
+
from sqlalchemy.orm import sessionmaker
from app.core.config import settings
+from sqlmodel import create_engine, SQLModel
+
engine = create_engine(settings.SQLALCHEMY_DATABASE_URI, pool_pre_ping=True)
+def create_db_and_tables():
+ SQLModel.metadata.create_all(engine)
+
+
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
diff --git a/app/main.py b/app/main.py
index ce938c1..3a1b06d 100644
--- a/app/main.py
+++ b/app/main.py
@@ -1,12 +1,18 @@
+import logging
+
+import uvicorn
from fastapi import FastAPI
+from loguru import logger
from starlette.middleware.cors import CORSMiddleware
from app.api.api_v1.api import api_router
from app.core.config import settings
from app.db.init_db import init_db
-from app.db.session import SessionLocal
+from app.db.session import SessionLocal, create_db_and_tables
+from app.utils import configure_log_handler
db = SessionLocal()
+configure_log_handler(log_level=logging.DEBUG)
init_db(db)
@@ -14,6 +20,10 @@ app = FastAPI(
title=settings.PROJECT_NAME,
openapi_url=f"{settings.API_V1_STR}/openapi.json",
)
+@app.on_event("startup")
+def on_startup():
+ create_db_and_tables()
+
# Set all CORS enabled origins
if settings.BACKEND_CORS_ORIGINS:
@@ -28,3 +38,4 @@ if settings.BACKEND_CORS_ORIGINS:
)
app.include_router(api_router, prefix=settings.API_V1_STR)
+
diff --git a/app/models/__init__.py b/app/models/__init__.py
index a7cfcae..1631f42 100644
--- a/app/models/__init__.py
+++ b/app/models/__init__.py
@@ -1,5 +1,13 @@
-# from .match import Match
-# from .matchday import Matchday
-from .player import Player
-from .team import Team
-from .user import User
+from app.models.matchday import Matchday, MatchdayWithPlayers
+from app.models.player import Player, PlayerTeamsMatchdays
+from app.models.team import Team, TeamWithPlayers
+
+
+Player.update_forward_refs(Team=Team, Matchday=Matchday)
+PlayerTeamsMatchdays.update_forward_refs(Team=Team, Matchday=Matchday)
+
+Team.update_forward_refs(Player=Player)
+TeamWithPlayers.update_forward_refs(Player=Player)
+
+Matchday.update_forward_refs(Player=Player)
+MatchdayWithPlayers.update_forward_refs(Player=Player)
\ No newline at end of file
diff --git a/app/models/match.py b/app/models/match.py
index 8474189..9f014f5 100644
--- a/app/models/match.py
+++ b/app/models/match.py
@@ -1,11 +1,14 @@
-from sqlalchemy import Column, DateTime, ForeignKey, Integer, String
-from sqlalchemy.orm import relationship
+from typing import Optional
-from app.db.database import Base
+from sqlmodel import SQLModel, Field
+
+from app.db.base_class import Base
-class Match(Base):
+class Match(SQLModel, Base, table=True):
+ matchname: Optional[str] = Field(nullable=False)
+"""
match_id = Column(Integer, primary_key=True)
team_1 = Column(ForeignKey("team.id"), nullable=False)
team_2 = Column(ForeignKey("team.id"), nullable=False)
@@ -18,3 +21,4 @@ class Match(Base):
team = relationship("Team", primaryjoin="Match.team_1 == Team.team_id")
team1 = relationship("Team", primaryjoin="Match.team_2 == Team.team_id")
team2 = relationship("Team", primaryjoin="Match.winner == Team.team_id")
+"""
\ No newline at end of file
diff --git a/app/models/matchday.py b/app/models/matchday.py
index d43da4a..46fce98 100644
--- a/app/models/matchday.py
+++ b/app/models/matchday.py
@@ -1,17 +1,36 @@
-from sqlalchemy import Column, DateTime, ForeignKey, Integer, String
-from sqlalchemy.orm import relationship
+from datetime import date, datetime
+from typing import List, Optional, TYPE_CHECKING
+
+from sqlalchemy import Date
+from sqlmodel import SQLModel, Relationship, Field, Column, func
from app.db.base_class import Base
+from app.models.matchdayplayer import MatchdayPlayerLink
+
+if TYPE_CHECKING:
+ from app.models.player import Player
-class MatchdayPlayer(Base):
-
- player_id = Column("players_id", ForeignKey("players.id"), primary_key=True)
- matchday_id = Column("teams_id", ForeignKey("teams.id"), primary_key=True)
+class MatchdayBase(SQLModel):
+ day: date
-class Matchday(Base):
+class Matchday(MatchdayBase, Base, table=True):
+ day: date = Field(
+ default=None,
+ sa_column=Column(Date, server_default=func.now()))
+ players: List["Player"] = Relationship(back_populates="matchdays",
+ link_model=MatchdayPlayerLink)
- matchday_id = Column(Integer, primary_key=True)
- day = Column(DateTime, nullable=False)
- players = relationship("Player", secondary="matchdayplayer")
\ No newline at end of file
+
+class MatchdayCreate(MatchdayBase):
+ day: date
+
+
+class MatchdayUpdate(MatchdayBase):
+ day: date
+
+
+class MatchdayWithPlayers(MatchdayBase):
+ day: date
+ players: Optional[List["Player"]]
diff --git a/app/models/matchdayplayer.py b/app/models/matchdayplayer.py
new file mode 100644
index 0000000..876fbfa
--- /dev/null
+++ b/app/models/matchdayplayer.py
@@ -0,0 +1,11 @@
+from typing import Optional
+from sqlmodel import SQLModel, Field
+
+class MatchdayPlayerLink(SQLModel, table=True):
+
+ player_id: Optional[int] = Field(
+ default=None, foreign_key="player.id", primary_key=True
+ )
+ matchday_id: Optional[int] = Field(
+ default=None, foreign_key="matchday.id", primary_key=True
+ )
diff --git a/app/schemas/msg.py b/app/models/msg.py
similarity index 100%
rename from app/schemas/msg.py
rename to app/models/msg.py
diff --git a/app/models/player.py b/app/models/player.py
index 1e9b3e7..8964612 100644
--- a/app/models/player.py
+++ b/app/models/player.py
@@ -1,16 +1,35 @@
-from sqlalchemy import Column, Integer, String, ForeignKey
-from sqlalchemy.orm import relationship
+from typing import Optional, List, TYPE_CHECKING
+from sqlmodel import SQLModel, Field, Relationship
from app.db.base_class import Base
+from app.models.matchdayplayer import MatchdayPlayerLink
+from app.models.teamplayers import TeamPlayerLink
-class Player(Base):
+if TYPE_CHECKING:
+ from app.models import Team, Matchday
+class PlayerBase(SQLModel):
+ firstname: str = Field(nullable=False)
+ lastname: str = Field(nullable=False)
- id = Column(Integer, primary_key=True, index=True)
- firstname = Column(String, nullable=True)
- lastname = Column(String, nullable=True)
- team_id = Column(Integer, ForeignKey("team.team_id"))
- team = relationship("Team", back_populates="players")
- team_id = Column(Integer, ForeignKey("team.team_id"))
- team = relationship("Team", back_populates="players")
+class Player(PlayerBase, Base, table=True):
+ teams: List["Team"] = Relationship(back_populates="players",
+ link_model=TeamPlayerLink)
+ matchdays: List["Matchday"] = Relationship(back_populates="players",
+ link_model=MatchdayPlayerLink)
+
+
+class PlayerCreate(PlayerBase):
+ firstname: str
+ lastname: str
+
+
+class PlayerUpdate(PlayerBase):
+ firstname: str
+ lastname: str
+
+class PlayerTeamsMatchdays(PlayerBase):
+ matchdays: List["Matchday"]
+ teams: List["Team"]
+
diff --git a/app/models/team.py b/app/models/team.py
index b925a5c..14d53cd 100644
--- a/app/models/team.py
+++ b/app/models/team.py
@@ -1,11 +1,34 @@
-from sqlalchemy import Column, DateTime, ForeignKey, Integer, String
-from sqlalchemy.orm import relationship
+from typing import Optional, List, TYPE_CHECKING
+
+from sqlmodel import SQLModel, Field, Relationship
from app.db.base_class import Base
+from app.models.teamplayers import TeamPlayerLink
+
+if TYPE_CHECKING:
+ from app.models.player import Player
+
+class TeamBase(SQLModel):
+ teamname: Optional[str] = Field(nullable=False)
+
+
+class Team(TeamBase, Base, table=True):
+ players: List["Player"] = Relationship(back_populates="teams",
+ link_model=TeamPlayerLink
+ )
+
+
+class TeamCreate(TeamBase):
+ teamname: str
+
+
+class TeamWithPlayers(TeamBase):
+ teamname: str
+ players: List["Player"]
+
+
+class TeamUpdate(TeamBase):
+ teamname: str
-class Team(Base):
- team_id = Column(Integer, primary_key=True, index=True)
- teamname = Column(String, nullable=False)
- players = relationship("Player", back_populates="team")
diff --git a/app/models/teamplayers.py b/app/models/teamplayers.py
new file mode 100644
index 0000000..575bb74
--- /dev/null
+++ b/app/models/teamplayers.py
@@ -0,0 +1,12 @@
+from typing import Optional
+
+from sqlmodel import SQLModel, Field, Relationship
+
+
+class TeamPlayerLink(SQLModel, table=True):
+ team_id: Optional[int] = Field(
+ default=None, foreign_key="team.id", primary_key=True
+ )
+ player_id: Optional[int] = Field(
+ default=None, foreign_key="player.id", primary_key=True
+ )
diff --git a/app/schemas/token.py b/app/models/token.py
similarity index 93%
rename from app/schemas/token.py
rename to app/models/token.py
index c7fd517..980924a 100644
--- a/app/schemas/token.py
+++ b/app/models/token.py
@@ -1,8 +1,6 @@
from typing import Optional
-
from pydantic import BaseModel
-
class Token(BaseModel):
access_token: str
token_type: str
diff --git a/app/models/user.py b/app/models/user.py
index 5c42cbf..6f5b089 100644
--- a/app/models/user.py
+++ b/app/models/user.py
@@ -1,12 +1,29 @@
-from sqlalchemy import Column, DateTime, ForeignKey, Integer, String, Boolean
+from typing import Optional
+from pydantic import EmailStr
+from sqlmodel import SQLModel, Field
from app.db.base_class import Base
-class User(Base):
- id = Column(Integer, primary_key=True, index=True)
- full_name = Column(String, index=True)
- email = Column(String, unique=True, index=True, nullable=False)
- hashed_password = Column(String, nullable=False)
- is_active = Column(Boolean(), default=True)
- is_superuser = Column(Boolean(), default=False)
+class UserBase(SQLModel):
+
+ full_name: Optional[str] = Field(index=True)
+ email: Optional[EmailStr] = Field(unique=True, index=True, nullable=False)
+ hashed_password: Optional[str] = Field(nullable=False)
+ is_active: Optional[bool] = Field(default=True)
+ is_superuser: bool = Field(default=False)
+
+
+class User(UserBase, Base, table=True):
+ pass
+
+
+class UserCreate(UserBase):
+ email: EmailStr
+ password: str
+
+
+# Properties to receive via API on update
+class UserUpdate(UserBase):
+ password: Optional[str] = None
+
diff --git a/app/schemas/__init__.py b/app/schemas/__init__.py
index e69031b..3bd4c33 100644
--- a/app/schemas/__init__.py
+++ b/app/schemas/__init__.py
@@ -1,5 +1,3 @@
-from .user import User, UserCreate, UserInDB, UserUpdate
-from .token import Token, TokenPayload
-from .msg import Msg
-from .player import Player, PlayerCreate, PlayerInDB
-from .team import Team, TeamCreate, TeamInDBBase
+#from .user import User, UserCreate, UserInDB, UserUpdate
+#from .player import Player, PlayerCreate, PlayerInDB
+#from .team import Team, TeamCreate, TeamInDBBase
diff --git a/app/schemas/player.py b/app/schemas/player.py
deleted file mode 100644
index e6a0f16..0000000
--- a/app/schemas/player.py
+++ /dev/null
@@ -1,41 +0,0 @@
-from typing import Optional
-
-from pydantic import BaseModel, EmailStr
-
-
-# Shared properties
-class PlayerBase(BaseModel):
- firstname: Optional[str] = None
- lastname: Optional[str] = None
-
-
-# Properties to receive via API on creation
-class PlayerCreate(PlayerBase):
- firstname: str
- lastname: str
-
-
-class PlayerInDBBase(PlayerBase):
- id: Optional[int] = None
-
- class Config:
- orm_mode = True
-
-
-class PlayerUpdate(PlayerBase):
- firstname: str
- lastname: str
-
-
-class PlayerUpdateTeam(PlayerBase):
- team_id: Optional[int]
-
-
-# Additional properties to return via API
-class Player(PlayerInDBBase):
- pass
-
-
-# Additional properties stored in DB
-class PlayerInDB(PlayerInDBBase):
- pass
diff --git a/app/schemas/team.py b/app/schemas/team.py
deleted file mode 100644
index bf7abb7..0000000
--- a/app/schemas/team.py
+++ /dev/null
@@ -1,39 +0,0 @@
-from typing import Optional
-
-from pydantic import BaseModel
-
-
-# Shared properties
-from app.schemas import Player
-
-
-class TeamBase(BaseModel):
- teamname: Optional[str] = None
-
-
-# Properties to receive via API on creation
-class TeamCreate(TeamBase):
- teamname: Optional[str]
-
-
-class TeamInDBBase(TeamBase):
- players: list[Player] = []
-
- class Config:
- orm_mode = True
-
-
-class TeamUpdate(TeamBase):
- pass
-
-
-# Additional properties to return via API
-class Team(TeamInDBBase):
-
- team_id: Optional[int] = None
- players: list[Player] = []
-
-
-# Additional properties stored in DB
-class TeamInDB(TeamInDBBase):
- pass
diff --git a/app/schemas/user.py b/app/schemas/user.py
deleted file mode 100644
index aa18316..0000000
--- a/app/schemas/user.py
+++ /dev/null
@@ -1,39 +0,0 @@
-from typing import Optional
-
-from pydantic import BaseModel, EmailStr
-
-
-# Shared properties
-class UserBase(BaseModel):
- email: Optional[EmailStr] = None
- is_active: Optional[bool] = True
- is_superuser: bool = False
- full_name: Optional[str] = None
-
-
-# Properties to receive via API on creation
-class UserCreate(UserBase):
- email: EmailStr
- password: str
-
-
-# Properties to receive via API on update
-class UserUpdate(UserBase):
- password: Optional[str] = None
-
-
-class UserInDBBase(UserBase):
- id: Optional[int] = None
-
- class Config:
- orm_mode = True
-
-
-# Additional properties to return via API
-class User(UserInDBBase):
- pass
-
-
-# Additional properties stored in DB
-class UserInDB(UserInDBBase):
- hashed_password: str
diff --git a/app/utils.py b/app/utils.py
index 723e9d8..9577423 100644
--- a/app/utils.py
+++ b/app/utils.py
@@ -8,6 +8,44 @@ from emails.template import JinjaTemplate
from jose import jwt
from app.core.config import settings
+import sys
+import logging
+from loguru import logger
+
+logger.remove()
+logger.add(
+ sys.stdout,
+ format="{time:YYYY/MM/DD HH:mm:ss} {level: <5} {name} {message}",
+ level="DEBUG",
+)
+
+
+class InterceptHandler(logging.Handler):
+ def emit(self, record):
+ # Get corresponding Loguru level if it exists.
+ try:
+ level = logger.level(record.levelname).name
+ except ValueError:
+ level = record.levelno
+
+ # Find caller from where originated the logged message.
+ frame, depth = sys._getframe(6), 6
+ while frame and frame.f_code.co_filename == logging.__file__:
+ frame = frame.f_back
+ depth += 1
+
+ logger.opt(
+ depth=depth, exception=record.exc_info
+ ).log(
+ "DEBUG", record.getMessage()
+ )
+
+
+def configure_log_handler(*, log_level=logging.WARNING):
+ logging.basicConfig(handlers=[InterceptHandler()],
+ level=logging.NOTSET, force=True)
+ for target in ['sqlalchemy.engine.Engine', 'sqlalchemy.engine']:
+ logging.getLogger(target).setLevel(log_level)
def send_email(
diff --git a/debug_run.py b/debug_run.py
new file mode 100644
index 0000000..c68ab44
--- /dev/null
+++ b/debug_run.py
@@ -0,0 +1,13 @@
+import uvicorn
+from loguru import logger
+
+from app.main import app
+
+
+def main():
+ uvicorn.run("debug_run:app", host="0.0.0.0", port=1234, reload=True)
+
+if __name__ == "__main__":
+ logger.info("begin")
+ main()
+ logger.info("done")
diff --git a/floorball.db b/floorball.db
index 929cf18..66e9dff 100644
Binary files a/floorball.db and b/floorball.db differ
diff --git a/poetry.lock b/poetry.lock
index f18f0c8..9720289 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -383,6 +383,21 @@ category = "dev"
optional = false
python-versions = ">=3.6"
+[[package]]
+name = "loguru"
+version = "0.6.0"
+description = "Python logging made (stupidly) simple"
+category = "main"
+optional = false
+python-versions = ">=3.5"
+
+[package.dependencies]
+colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""}
+win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""}
+
+[package.extras]
+dev = ["Sphinx (>=4.1.1)", "black (>=19.10b0)", "colorama (>=0.3.4)", "docutils (==0.16)", "flake8 (>=3.7.7)", "isort (>=5.1.1)", "pytest (>=4.6.2)", "pytest-cov (>=2.7.1)", "sphinx-autobuild (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)", "tox (>=3.9.0)"]
+
[[package]]
name = "lxml"
version = "4.9.1"
@@ -754,6 +769,30 @@ postgresql_psycopg2cffi = ["psycopg2cffi"]
pymysql = ["pymysql", "pymysql (<1)"]
sqlcipher = ["sqlcipher3-binary"]
+[[package]]
+name = "sqlalchemy2-stubs"
+version = "0.0.2a27"
+description = "Typing Stubs for SQLAlchemy 1.4"
+category = "main"
+optional = false
+python-versions = ">=3.6"
+
+[package.dependencies]
+typing-extensions = ">=3.7.4"
+
+[[package]]
+name = "sqlmodel"
+version = "0.0.8"
+description = "SQLModel, SQL databases in Python, designed for simplicity, compatibility, and robustness."
+category = "main"
+optional = false
+python-versions = ">=3.6.1,<4.0.0"
+
+[package.dependencies]
+pydantic = ">=1.8.2,<2.0.0"
+SQLAlchemy = ">=1.4.17,<=1.4.41"
+sqlalchemy2-stubs = "*"
+
[[package]]
name = "starlette"
version = "0.19.1"
@@ -868,6 +907,17 @@ platformdirs = ">=2.4,<3"
docs = ["proselint (>=0.13)", "sphinx (>=5.1.1)", "sphinx-argparse (>=0.3.1)", "sphinx-rtd-theme (>=1)", "towncrier (>=21.9)"]
testing = ["coverage (>=6.2)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=21.3)", "pytest (>=7.0.1)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.6.1)", "pytest-randomly (>=3.10.3)", "pytest-timeout (>=2.1)"]
+[[package]]
+name = "win32-setctime"
+version = "1.1.0"
+description = "A small Python utility to set file creation time on Windows"
+category = "main"
+optional = false
+python-versions = ">=3.5"
+
+[package.extras]
+dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"]
+
[[package]]
name = "wrapt"
version = "1.14.1"
@@ -879,7 +929,7 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
[metadata]
lock-version = "1.1"
python-versions = "^3.9"
-content-hash = "875e82447867f92eb96260ad048da2e4967d2c8285ecaac9dca37dd839d7d78f"
+content-hash = "f51b93ad173b06640d39b5143150dd0219b20bfcd5c3c9a0a4036b5638d12925"
[metadata.files]
anyio = [
@@ -1257,6 +1307,10 @@ lazy-object-proxy = [
{file = "lazy_object_proxy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:677ea950bef409b47e51e733283544ac3d660b709cfce7b187f5ace137960d61"},
{file = "lazy_object_proxy-1.7.1-pp37.pp38-none-any.whl", hash = "sha256:d66906d5785da8e0be7360912e99c9188b70f52c422f9fc18223347235691a84"},
]
+loguru = [
+ {file = "loguru-0.6.0-py3-none-any.whl", hash = "sha256:4e2414d534a2ab57573365b3e6d0234dfb1d84b68b7f3b948e6fb743860a77c3"},
+ {file = "loguru-0.6.0.tar.gz", hash = "sha256:066bd06758d0a513e9836fd9c6b5a75bfb3fd36841f4b996bc60b547a309d41c"},
+]
lxml = [
{file = "lxml-4.9.1-cp27-cp27m-macosx_10_15_x86_64.whl", hash = "sha256:98cafc618614d72b02185ac583c6f7796202062c41d2eeecdf07820bad3295ed"},
{file = "lxml-4.9.1-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c62e8dd9754b7debda0c5ba59d34509c4688f853588d75b53c3791983faa96fc"},
@@ -1536,6 +1590,14 @@ sqlalchemy = [
{file = "SQLAlchemy-1.4.40-cp39-cp39-win_amd64.whl", hash = "sha256:bf073c619b5a7f7cd731507d0fdc7329bee14b247a63b0419929e4acd24afea8"},
{file = "SQLAlchemy-1.4.40.tar.gz", hash = "sha256:44a660506080cc975e1dfa5776fe5f6315ddc626a77b50bf0eee18b0389ea265"},
]
+sqlalchemy2-stubs = [
+ {file = "sqlalchemy2-stubs-0.0.2a27.tar.gz", hash = "sha256:f79bce50b7837a2c2374ef4480b41e2b8a8226f313f347dc2a70526a4191db93"},
+ {file = "sqlalchemy2_stubs-0.0.2a27-py3-none-any.whl", hash = "sha256:6cea12fec3c261f6e0e14a95d2cc4914e373095e68ec4fc2eb473183ac2b17a2"},
+]
+sqlmodel = [
+ {file = "sqlmodel-0.0.8-py3-none-any.whl", hash = "sha256:0fd805719e0c5d4f22be32eb3ffc856eca3f7f20e8c7aa3e117ad91684b518ee"},
+ {file = "sqlmodel-0.0.8.tar.gz", hash = "sha256:3371b4d1ad59d2ffd0c530582c2140b6c06b090b32af9b9c6412986d7b117036"},
+]
starlette = [
{file = "starlette-0.19.1-py3-none-any.whl", hash = "sha256:5a60c5c2d051f3a8eb546136aa0c9399773a689595e099e0877704d5888279bf"},
{file = "starlette-0.19.1.tar.gz", hash = "sha256:c6d21096774ecb9639acad41b86b7706e52ba3bf1dc13ea4ed9ad593d47e24c7"},
@@ -1572,6 +1634,10 @@ virtualenv = [
{file = "virtualenv-20.16.3-py2.py3-none-any.whl", hash = "sha256:4193b7bc8a6cd23e4eb251ac64f29b4398ab2c233531e66e40b19a6b7b0d30c1"},
{file = "virtualenv-20.16.3.tar.gz", hash = "sha256:d86ea0bb50e06252d79e6c241507cb904fcd66090c3271381372d6221a3970f9"},
]
+win32-setctime = [
+ {file = "win32_setctime-1.1.0-py3-none-any.whl", hash = "sha256:231db239e959c2fe7eb1d7dc129f11172354f98361c4fa2d6d2d7e278baa8aad"},
+ {file = "win32_setctime-1.1.0.tar.gz", hash = "sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2"},
+]
wrapt = [
{file = "wrapt-1.14.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3"},
{file = "wrapt-1.14.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef"},
diff --git a/pyproject.toml b/pyproject.toml
index 26852b0..e3ae939 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -14,6 +14,8 @@ python-jose = {extras = ["cryptography"], version = "^3.3.0"}
pydantic = {extras = ["email"], version = "^1.10.0"}
python-multipart = "^0.0.5"
emails = "^0.6"
+sqlmodel = "^0.0.8"
+loguru = "^0.6.0"
[tool.poetry.dev-dependencies]
pytest = "^7.1.2"
@@ -30,6 +32,8 @@ isort = "^5.10.1"
line-length = 79
target-version = [ "py39",]
+[tool.poetry.scripts]
+web = "app.main:"
[build-system]
requires = ["poetry-core>=1.0.0"]