diff --git a/med_backend/auth/schemas.py b/med_backend/auth/schemas.py index 8f87eab..d69f87f 100644 --- a/med_backend/auth/schemas.py +++ b/med_backend/auth/schemas.py @@ -1,6 +1,7 @@ -from datetime import datetime +from datetime import date, datetime -from pydantic import BaseModel, EmailStr +from dateutil.relativedelta import relativedelta +from pydantic import BaseModel, EmailStr, root_validator class Token(BaseModel): @@ -31,6 +32,13 @@ class UserPublicInfo(UserBase): id: int fullname: str | None disabled: bool + born: date + + @root_validator(pre=False) + def _set_fields(cls, values): + values["age"] = relativedelta(datetime.now(), values["born"]).years + values.pop("born") + return values class Config: orm_mode = True diff --git a/med_backend/db/models/posts.py b/med_backend/db/models/posts.py new file mode 100644 index 0000000..1a9a8bf --- /dev/null +++ b/med_backend/db/models/posts.py @@ -0,0 +1,23 @@ +from sqlalchemy import Column, ForeignKey, Integer, String +from sqlalchemy.orm import relationship + +from med_backend.db.base import Base +from med_backend.db.models.users import UserScheme + + +class PostScheme(Base): + __tablename__ = "posts" + + id: int = Column( + Integer, + primary_key=True, + autoincrement=True, + unique=True, + index=True, + ) + name: str = Column(String, nullable=False) + description: str = Column(String, nullable=True) + + # creator + user_id: int = Column(Integer, ForeignKey(UserScheme.id), primary_key=True) + user: UserScheme = relationship("UserScheme", foreign_keys="PostScheme.user_id") diff --git a/med_backend/posts/__init__.py b/med_backend/posts/__init__.py new file mode 100644 index 0000000..9e63636 --- /dev/null +++ b/med_backend/posts/__init__.py @@ -0,0 +1,5 @@ +"""API for posts by doctors""" + +from med_backend.posts.views import router + +__all__ = ["router"] diff --git a/med_backend/posts/crud.py b/med_backend/posts/crud.py new file mode 100644 index 0000000..b03d3a3 --- /dev/null +++ b/med_backend/posts/crud.py @@ -0,0 +1,48 @@ +from typing import List + +from fastapi import HTTPException +from sqlalchemy import select +from sqlalchemy.ext.asyncio import AsyncSession +from sqlalchemy.orm import selectinload + +from med_backend.db.models.posts import PostScheme +from med_backend.posts.schemas import PostCreate +from med_backend.users.crud import get_user + + +async def get_posts( + session: AsyncSession, + skip: int = 0, + limit: int = 100, +) -> List[PostScheme] | None: + r = await session.execute( + select(PostScheme).offset(skip).limit(limit), + ) + posts = r.scalars().all() + return posts + + +async def get_post(session: AsyncSession, post_id: int) -> PostScheme | None: + r = await session.execute( + select(PostScheme) + .options(selectinload(PostScheme.user)) + .where(PostScheme.id == post_id), + ) + post = r.scalars().first() + return post + + +async def create_post( + session: AsyncSession, + data: PostCreate, + user_id: int, +) -> PostScheme: + user = await get_user(session, user_id) + if not user or not user.is_manager: + raise HTTPException(status_code=422, detail="User can't be used") + + obj = PostScheme(name=data.name, description=data.description, user_id=user_id) + session.add(obj) + await session.commit() + await session.refresh(obj) + return obj diff --git a/med_backend/posts/schemas.py b/med_backend/posts/schemas.py new file mode 100644 index 0000000..969fb48 --- /dev/null +++ b/med_backend/posts/schemas.py @@ -0,0 +1,27 @@ +from pydantic import BaseModel + +from med_backend.auth.schemas import UserPublicInfo + + +class BasePost(BaseModel): + name: str + + +class PostCreate(BasePost): + description: str + + +class PostList(BasePost): + id: int + + class Config: + orm_mode = True + + +class Post(BasePost): + id: int + description: str + user: UserPublicInfo + + class Config: + orm_mode = True diff --git a/med_backend/posts/views.py b/med_backend/posts/views.py new file mode 100644 index 0000000..ed19f42 --- /dev/null +++ b/med_backend/posts/views.py @@ -0,0 +1,41 @@ +from fastapi import APIRouter, Depends +from sqlalchemy.ext.asyncio import AsyncSession + +from med_backend.auth.schemas import User +from med_backend.auth.services import get_current_active_user +from med_backend.db.dependencies import get_db_session +from med_backend.posts import crud +from med_backend.posts.schemas import Post, PostCreate, PostList + +router = APIRouter() + + +@router.get("/all", response_model=list[PostList]) +async def get_all_posts( + skip: int = 0, + limit: int = 100, + current_user: User = Depends(get_current_active_user), + session: AsyncSession = Depends(get_db_session), +): + posts = await crud.get_posts(session, skip, limit) + return posts + + +@router.get("/{post_id}", response_model=Post) +async def get_post( + post_id: int, + current_user: User = Depends(get_current_active_user), + session: AsyncSession = Depends(get_db_session), +): + form = await crud.get_post(session, post_id) + return form + + +@router.post("/create", response_model=Post) +async def create_post( + data: PostCreate, + current_user: User = Depends(get_current_active_user), + session: AsyncSession = Depends(get_db_session), +): + post = await crud.create_post(session, data, current_user.id) + return post diff --git a/med_backend/web/api/router.py b/med_backend/web/api/router.py index 0191c21..5a3e947 100644 --- a/med_backend/web/api/router.py +++ b/med_backend/web/api/router.py @@ -1,8 +1,9 @@ from fastapi.routing import APIRouter -from med_backend import auth, forms, users +from med_backend import auth, forms, posts, users api_router = APIRouter() api_router.include_router(auth.router, prefix="/auth", tags=["auth"]) +api_router.include_router(posts.router, prefix="/posts", tags=["posts"]) api_router.include_router(users.router, prefix="/users", tags=["users"]) api_router.include_router(forms.router, prefix="/forms", tags=["forms"]) diff --git a/med_backend/web/application.py b/med_backend/web/application.py index 72e048a..9b6d238 100644 --- a/med_backend/web/application.py +++ b/med_backend/web/application.py @@ -2,6 +2,7 @@ from importlib import metadata from fastapi import FastAPI from fastapi.responses import UJSONResponse +from starlette.middleware.cors import CORSMiddleware from med_backend.web.api.router import api_router from med_backend.web.lifetime import register_shutdown_event, register_startup_event @@ -32,4 +33,11 @@ def get_app() -> FastAPI: # Main router for the API. app.include_router(router=api_router, prefix="/api") + app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], + ) return app