Skip to content
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

Merge develop #8

Merged
merged 13 commits into from
May 15, 2024
Merged
25 changes: 22 additions & 3 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,32 @@ on:
pull_request:
branches: ["main", "develop"]

permissions:
contents: read
env:
DB_NAME: db
DB_USER: user
DB_PASSWORD: postgres
DB_HOST: localhost
DB_PORT: 5432

jobs:
ci:
runs-on: ubuntu-latest

services:
postgres:
image: postgres
env:
POSTGRES_DB: ${{ env.DB_NAME }}
POSTGRES_USER: ${{ env.DB_USER }}
POSTGRES_PASSWORD: ${{ env.DB_PASSWORD }}
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432

steps:
- name: Checkout
uses: actions/checkout@v3
Expand All @@ -38,4 +57,4 @@ jobs:
run: poetry install --no-interaction --no-root

- name: Run tests
run: make test
run: poetry run pytest -v .
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ lint:

test:
rm test.db 2> /dev/null || true
poetry run pytest -sv .
DB_NAME="./test.db" poetry run pytest -sv .

run: install
poetry run uvicorn src.main:app --host localhost --port 8000 --reload
25 changes: 24 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ fastapi = "^0.111.0"
sqlalchemy = "^2.0.30"
uvicorn = "^0.29.0"
flake8 = "^7.0.0"
psycopg2 = "^2.9.9"


[tool.poetry.group.dev.dependencies]
Expand Down
23 changes: 23 additions & 0 deletions src/crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
import hashlib


def get_user_by_id(db: Session, id: int):
return db.query(models.User).filter(models.User.id == id).first()


def get_user_by_email(db: Session, email: str):
return db.query(models.User).filter(models.User.email == email).first()

Expand All @@ -14,3 +18,22 @@ def create_user(db: Session, user: schemas.UserCreate):
db.commit()
db.refresh(db_user)
return db_user


def create_group(db: Session, group: schemas.GroupCreate, user_id: int):
db_group = models.Group(
owner_id=user_id, name=group.name, description=group.description
)
db.add(db_group)
db.commit()
db.refresh(db_group)
return db_group


def get_groups_by_owner_id(db: Session, owner_id: int):
return (
db.query(models.Group)
.filter(models.Group.owner_id == owner_id)
.limit(100)
.all()
)
33 changes: 27 additions & 6 deletions src/database.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,33 @@
from sqlalchemy import create_engine
from logging import info
import os
from sqlalchemy import create_engine, URL
from sqlalchemy.orm import DeclarativeBase, sessionmaker

SQLALCHEMY_DATABASE_URL = "sqlite:///./sql_app.db"
# SQLALCHEMY_DATABASE_URL = "postgresql://user:password@postgresserver/db"

engine = create_engine(
SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)
DB_NAME = os.environ.get("DB_NAME", "./sql_app.db")
DB_USER = os.environ.get("DB_USER")
DB_PASS = os.environ.get("DB_PASSWORD")

# set automatically by kubernetes
# resolves to postgres service's host/port
DB_HOST = os.environ.get("DB_HOST")
DB_PORT = os.environ.get("DB_PORT")


SQLALCHEMY_DATABASE_URL = f"sqlite:///{DB_NAME}"

if DB_HOST is not None:
info("Using PostgreSQL database")
SQLALCHEMY_DATABASE_URL = URL.create(
"postgresql",
username=DB_USER,
password=DB_PASS,
host=DB_HOST,
port=DB_PORT,
database=DB_NAME,
)

engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)


Expand Down
50 changes: 41 additions & 9 deletions src/main.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from fastapi import Depends, FastAPI, HTTPException
from http import HTTPStatus
from typing import Annotated
from fastapi import Depends, FastAPI, HTTPException, Header
from . import crud, models, schemas
from .database import SessionLocal, engine
from sqlalchemy.orm import Session
Expand All @@ -7,7 +9,6 @@
models.Base.metadata.create_all(bind=engine)


# Dependency
def get_db():
db = SessionLocal()
try:
Expand All @@ -16,31 +17,62 @@ def get_db():
db.close()


DbDependency = Annotated[Session, Depends(get_db)]


def get_user(db: DbDependency, x_user: Annotated[int, Header()]) -> models.User:
db_user = crud.get_user_by_id(db, x_user)
if db_user is None:
raise HTTPException(
status_code=HTTPStatus.UNAUTHORIZED,
detail="Necesita loguearse para continuar",
)
return db_user


app = FastAPI(dependencies=[Depends(get_db)])

UserDependency = Annotated[models.User, Depends(get_user)]

@app.post("/user/register")
def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)):

@app.post("/user/register", status_code=HTTPStatus.CREATED)
def create_user(user: schemas.UserCreate, db: DbDependency):
db_user = crud.get_user_by_email(db, email=user.email)

if db_user is not None:
raise HTTPException(status_code=400, detail="Email already registered")
raise HTTPException(
status_code=HTTPStatus.BAD_REQUEST, detail="Email ya existente"
)

db_user = crud.create_user(db, user)

return {"id": db_user.id}


@app.post("/user/login")
def login(user: schemas.UserLogin, db: Session = Depends(get_db)):
@app.post("/user/login", status_code=HTTPStatus.CREATED)
def login(user: schemas.UserLogin, db: DbDependency):
db_user = crud.get_user_by_email(db, email=user.email)

if db_user is None:
raise HTTPException(status_code=404, detail="User not found")
raise HTTPException(
status_code=HTTPStatus.NOT_FOUND, detail="Usuario no existe"
)

hashed_password = hashlib.sha256(user.password.encode(encoding="utf-8")).hexdigest()

if db_user.password != hashed_password:
raise HTTPException(status_code=404, detail="Verify your credentials")
raise HTTPException(
status_code=HTTPStatus.UNAUTHORIZED, detail="Contraseña incorrecta"
)

return {"token": db_user.id}


@app.post("/group", status_code=HTTPStatus.CREATED)
def create_group(group: schemas.GroupCreate, db: DbDependency, user: UserDependency):
return crud.create_group(db, group, user.id)


@app.get("/group")
def list_groups(db: DbDependency, user: UserDependency):
return crud.get_groups_by_owner_id(db, user.id)
9 changes: 9 additions & 0 deletions src/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,12 @@ class User(Base):
id = Column(Integer, primary_key=True)
email = Column(String, unique=True, index=True)
password = Column(String)


class Group(Base):
__tablename__ = "groups"

id = Column(Integer, primary_key=True)
owner_id = Column(ForeignKey("users.id"))
name = Column(String)
description = Column(String)
14 changes: 14 additions & 0 deletions src/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,17 @@ class UserCreate(UserBase):

class User(UserBase):
id: int


class GroupBase(BaseModel):
name: str
description: str


class GroupCreate(GroupBase):
pass


class Group(GroupBase):
id: int
owner_id: int
Loading
Loading