Skip to content

Commit

Permalink
Feature/user and group history
Browse files Browse the repository at this point in the history
* fix: change func name

* req: add fastapi-pagination

* feat: add pag to app

* feat: add pag to read users

* req: update req

* feat: add pag to replenishments

* feat: add pag to expenses

* ref: replace query with select

* ref: replace query with select

* feat: add user history schema

* feat: add user history service

* feat: add user history router

* feat: add group history schema

* feat: add group history service

* feat: add group history router
  • Loading branch information
RezenkovD authored Aug 13, 2023
1 parent 7bdab76 commit e6c6585
Show file tree
Hide file tree
Showing 20 changed files with 511 additions and 235 deletions.
11 changes: 6 additions & 5 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
alembic==1.9.4
Authlib==1.2.0
fastapi==0.92.0
alembic~=1.9.4
Authlib~=1.2.0
fastapi~=0.101.0
httpx==0.23.3
itsdangerous==2.1.2
psycopg2==2.9.5
psycopg2~=2.9.5
pydantic==1.10.5
SQLAlchemy==2.0.4
SQLAlchemy-Utils==0.40.0
starlette==0.25.0
starlette~=0.27.0
uvicorn==0.20.0
python-dateutil~=2.8.2
fastapi-pagination~=0.12.6
6 changes: 6 additions & 0 deletions src/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@

from authlib.integrations.starlette_client import OAuth
from fastapi import Depends, HTTPException
from fastapi_pagination import Page
from pydantic.schema import date
from pydantic import Field
from sqlalchemy.orm import Session
from starlette import status
from starlette.config import Config
Expand All @@ -26,6 +28,10 @@
},
)

Page = Page.with_custom_options(
size=Field(8, ge=1, le=500),
)


def get_current_user(request: Request, db: Session = Depends(get_db)) -> User:
try:
Expand Down
3 changes: 3 additions & 0 deletions src/main.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import uvicorn
from fastapi import FastAPI
from fastapi_pagination import add_pagination
from fastapi.middleware.cors import CORSMiddleware
from starlette.middleware.sessions import SessionMiddleware

Expand Down Expand Up @@ -33,6 +34,8 @@
app.include_router(expense.router)
app.include_router(replenishment.router)

add_pagination(app)

if __name__ == "__main__":
uvicorn.run(
"main:app",
Expand Down
62 changes: 41 additions & 21 deletions src/routers/expense.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from typing import List, Optional

from fastapi import APIRouter, Depends
from fastapi_pagination.ext.sqlalchemy import paginate
from sqlalchemy.orm import Session
from starlette import status
from starlette.exceptions import HTTPException
Expand All @@ -12,6 +13,7 @@
get_current_user,
transform_date_or_422,
transform_exact_date_or_422,
Page,
)
from models import User
from schemas import ExpenseCreate, ExpenseModel, UserExpense
Expand Down Expand Up @@ -56,7 +58,7 @@ def delete_expense(
services.delete_expense(db, current_user.id, group_id, expense_id)


@router.get("/{group_id}/expenses/", response_model=List[UserExpense])
@router.get("/{group_id}/expenses/", response_model=Page[UserExpense])
def read_expenses_by_group(
*,
db: Session = Depends(get_db),
Expand All @@ -65,7 +67,7 @@ def read_expenses_by_group(
year_month: Optional[str] = None,
start_date: Optional[str] = None,
end_date: Optional[str] = None,
) -> List[UserExpense]:
) -> Page[UserExpense]:
if year_month and (start_date or end_date):
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
Expand All @@ -78,32 +80,44 @@ def read_expenses_by_group(
)
elif year_month:
filter_date = transform_date_or_422(year_month)
return services.read_expenses(
db=db, user_id=current_user.id, group_id=group_id, filter_date=filter_date
return paginate(
db,
services.read_expenses(
db=db,
user_id=current_user.id,
group_id=group_id,
filter_date=filter_date,
),
)
elif start_date and end_date:
start_date = transform_exact_date_or_422(start_date)
end_date = transform_exact_date_or_422(end_date)
return services.read_expenses(
db=db,
user_id=current_user.id,
group_id=group_id,
start_date=start_date,
end_date=end_date,
return paginate(
db,
services.read_expenses(
db=db,
user_id=current_user.id,
group_id=group_id,
start_date=start_date,
end_date=end_date,
),
)
else:
return services.read_expenses(db=db, user_id=current_user.id, group_id=group_id)
return paginate(
db,
services.read_expenses(db=db, user_id=current_user.id, group_id=group_id),
)


@router.get("/expenses/", response_model=List[UserExpense])
@router.get("/expenses/", response_model=Page[UserExpense])
def read_expenses(
*,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
year_month: Optional[str] = None,
start_date: Optional[str] = None,
end_date: Optional[str] = None,
) -> List[UserExpense]:
) -> Page[UserExpense]:
if year_month and (start_date or end_date):
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
Expand All @@ -116,17 +130,23 @@ def read_expenses(
)
elif year_month:
filter_date = transform_date_or_422(year_month)
return services.read_expenses(
db=db, user_id=current_user.id, filter_date=filter_date
return paginate(
db,
services.read_expenses(
db=db, user_id=current_user.id, filter_date=filter_date
),
)
elif start_date and end_date:
start_date = transform_exact_date_or_422(start_date)
end_date = transform_exact_date_or_422(end_date)
return services.read_expenses(
db=db,
user_id=current_user.id,
start_date=start_date,
end_date=end_date,
return paginate(
db,
services.read_expenses(
db=db,
user_id=current_user.id,
start_date=start_date,
end_date=end_date,
),
)
else:
return services.read_expenses(db=db, user_id=current_user.id)
return paginate(db, services.read_expenses(db=db, user_id=current_user.id))
13 changes: 13 additions & 0 deletions src/routers/group.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from typing import Union

from fastapi import APIRouter, Depends
from fastapi_pagination.ext.sqlalchemy import paginate
from sqlalchemy.orm import Session

import services
Expand All @@ -14,14 +15,26 @@
UsersGroup,
UserGroups,
GroupInfo,
GroupHistory,
)
from dependencies import Page

router = APIRouter(
prefix="/groups",
tags=["groups"],
)


@router.get("/{group_id}/history/", response_model=Page[GroupHistory])
def read_user_history(
*,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
group_id: int,
) -> Page[GroupHistory]:
return paginate(db, services.group_history(db, current_user.id, group_id))


@router.get("/{group_id}/info/", response_model=GroupInfo)
def read_group_info(
*,
Expand Down
27 changes: 17 additions & 10 deletions src/routers/replenishment.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from typing import List, Optional

from fastapi import APIRouter, Depends
from fastapi_pagination.ext.sqlalchemy import paginate
from sqlalchemy.orm import Session
from starlette import status
from starlette.exceptions import HTTPException
Expand All @@ -12,6 +13,7 @@
get_current_user,
transform_date_or_422,
transform_exact_date_or_422,
Page,
)
from models import User
from schemas import ReplenishmentCreate, ReplenishmentModel, UserReplenishment
Expand Down Expand Up @@ -55,15 +57,15 @@ def delete_replenishment(
services.delete_replenishment(db, current_user.id, replenishment_id)


@router.get("/", response_model=List[UserReplenishment])
@router.get("/", response_model=Page[UserReplenishment])
def read_replenishments(
*,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
year_month: Optional[str] = None,
start_date: Optional[str] = None,
end_date: Optional[str] = None,
) -> List[UserReplenishment]:
) -> Page[UserReplenishment]:
if year_month and (start_date or end_date):
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
Expand All @@ -76,17 +78,22 @@ def read_replenishments(
)
elif year_month:
filter_date = transform_date_or_422(year_month)
return services.read_replenishments(
db=db, user_id=current_user.id, filter_date=filter_date
return paginate(
db,
services.read_replenishments(
user_id=current_user.id, filter_date=filter_date
),
)
elif start_date and end_date:
start_date = transform_exact_date_or_422(start_date)
end_date = transform_exact_date_or_422(end_date)
return services.read_replenishments(
db=db,
user_id=current_user.id,
start_date=start_date,
end_date=end_date,
return paginate(
db,
services.read_replenishments(
user_id=current_user.id,
start_date=start_date,
end_date=end_date,
),
)
else:
return services.read_replenishments(db=db, user_id=current_user.id)
return paginate(db, services.read_replenishments(user_id=current_user.id))
29 changes: 23 additions & 6 deletions src/routers/user.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from typing import List, Optional

from fastapi import APIRouter, Depends
from fastapi_pagination.ext.sqlalchemy import paginate
from sqlalchemy.orm import Session
from sqlalchemy import select
from starlette import status
from starlette.exceptions import HTTPException

Expand All @@ -11,19 +13,26 @@
get_current_user,
transform_date_or_422,
transform_exact_date_or_422,
Page,
)
from models import User, Expense
from schemas import (
UserBalance,
UserModel,
UserTotalExpenses,
UserTotalReplenishments,
UserHistory,
)
from models import User
from schemas import UserBalance, UserModel, UserTotalExpenses, UserTotalReplenishments

router = APIRouter(
prefix="/users",
tags=["users"],
)


@router.get("/", response_model=List[UserModel])
def read_users(db: Session = Depends(get_db)) -> List[UserModel]:
return db.query(User).all()
@router.get("/", response_model=Page[UserModel])
def read_users(db: Session = Depends(get_db)) -> Page[UserModel]:
return paginate(db, select(User))


@router.get("/user-balance/", response_model=UserBalance)
Expand All @@ -42,6 +51,14 @@ def read_user_info(
return db.query(User).filter_by(id=current_user.id).one()


@router.get("/history/", response_model=Page[UserHistory])
def read_user_history(
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
) -> Page[UserHistory]:
return paginate(db, services.user_history(current_user.id))


@router.get("/total-expenses/", response_model=UserTotalExpenses)
def read_user_total_expenses(
db: Session = Depends(get_db),
Expand Down Expand Up @@ -79,7 +96,7 @@ def read_user_total_expenses(


@router.get("/total-replenishments/", response_model=UserTotalReplenishments)
def read_user_total_expenses(
def read_user_total_replenishments(
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
year_month: Optional[str] = None,
Expand Down
9 changes: 8 additions & 1 deletion src/schemas/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
from .user import BaseUser, UserModel, UserTotalExpenses, UserTotalReplenishments
from .user import (
BaseUser,
UserModel,
UserTotalExpenses,
UserTotalReplenishments,
UserHistory,
)
from .group import (
AboutCategory,
AboutUser,
Expand All @@ -9,6 +15,7 @@
UserGroups,
UsersGroup,
GroupInfo,
GroupHistory,
)
from .invintation import BaseInvitation, InvitationCreate, InvitationModel
from .category import CategoryModel, CategoryCreate, IconColor
Expand Down
19 changes: 17 additions & 2 deletions src/schemas/group.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from datetime import date
from typing import List
from datetime import date, datetime
from typing import List, Optional

from schemas import UserModel
from schemas.base_model import BaseModel
Expand Down Expand Up @@ -66,3 +66,18 @@ class CategoriesGroup(BaseModel):
class GroupInfo(GroupModel):
members: int
expenses: int


class GroupHistory(BaseModel):
id: int
descriptions: str
amount: float
time: datetime
category_id: Optional[int] = None
color_code_category: Optional[str] = None
title_category: Optional[str] = None
user_id: int
user_login: str
user_first_name: str
user_last_name: str
user_picture: str
Loading

0 comments on commit e6c6585

Please sign in to comment.