Skip to content

Commit 8c68668

Browse files
committed
architect
1 parent 366eb58 commit 8c68668

16 files changed

Lines changed: 502 additions & 230 deletions

File tree

backend/app/api/routes/items.py

Lines changed: 36 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,33 @@
11
import uuid
2-
from typing import Any
2+
from typing import Any, NoReturn
33

44
from fastapi import APIRouter, HTTPException
5-
from sqlmodel import col, func, select
65

76
from app.api.deps import CurrentUser, SessionDep
8-
from app.models import Item, ItemCreate, ItemPublic, ItemsPublic, ItemUpdate, Message
7+
from app.models import ItemCreate, ItemPublic, ItemsPublic, ItemUpdate, Message
8+
from app.services import item_service
9+
from app.services.exceptions import ServiceError
910

1011
router = APIRouter(prefix="/items", tags=["items"])
1112

1213

14+
def _raise_http_from_service_error(exc: ServiceError) -> NoReturn:
15+
raise HTTPException(status_code=exc.status_code, detail=exc.detail)
16+
17+
1318
@router.get("/", response_model=ItemsPublic)
1419
def read_items(
1520
session: SessionDep, current_user: CurrentUser, skip: int = 0, limit: int = 100
1621
) -> Any:
1722
"""
1823
Retrieve items.
1924
"""
20-
21-
if current_user.is_superuser:
22-
count_statement = select(func.count()).select_from(Item)
23-
count = session.exec(count_statement).one()
24-
statement = (
25-
select(Item).order_by(col(Item.created_at).desc()).offset(skip).limit(limit)
26-
)
27-
items = session.exec(statement).all()
28-
else:
29-
count_statement = (
30-
select(func.count())
31-
.select_from(Item)
32-
.where(Item.owner_id == current_user.id)
33-
)
34-
count = session.exec(count_statement).one()
35-
statement = (
36-
select(Item)
37-
.where(Item.owner_id == current_user.id)
38-
.order_by(col(Item.created_at).desc())
39-
.offset(skip)
40-
.limit(limit)
41-
)
42-
items = session.exec(statement).all()
43-
25+
items, count = item_service.list_items_for_user(
26+
session=session,
27+
current_user=current_user,
28+
skip=skip,
29+
limit=limit,
30+
)
4431
return ItemsPublic(data=items, count=count)
4532

4633

@@ -49,12 +36,12 @@ def read_item(session: SessionDep, current_user: CurrentUser, id: uuid.UUID) ->
4936
"""
5037
Get item by ID.
5138
"""
52-
item = session.get(Item, id)
53-
if not item:
54-
raise HTTPException(status_code=404, detail="Item not found")
55-
if not current_user.is_superuser and (item.owner_id != current_user.id):
56-
raise HTTPException(status_code=403, detail="Not enough permissions")
57-
return item
39+
try:
40+
return item_service.get_item_for_user(
41+
session=session, current_user=current_user, item_id=id
42+
)
43+
except ServiceError as exc:
44+
_raise_http_from_service_error(exc)
5845

5946

6047
@router.post("/", response_model=ItemPublic)
@@ -64,11 +51,9 @@ def create_item(
6451
"""
6552
Create new item.
6653
"""
67-
item = Item.model_validate(item_in, update={"owner_id": current_user.id})
68-
session.add(item)
69-
session.commit()
70-
session.refresh(item)
71-
return item
54+
return item_service.create_item_for_user(
55+
session=session, current_user=current_user, item_in=item_in
56+
)
7257

7358

7459
@router.put("/{id}", response_model=ItemPublic)
@@ -82,17 +67,12 @@ def update_item(
8267
"""
8368
Update an item.
8469
"""
85-
item = session.get(Item, id)
86-
if not item:
87-
raise HTTPException(status_code=404, detail="Item not found")
88-
if not current_user.is_superuser and (item.owner_id != current_user.id):
89-
raise HTTPException(status_code=403, detail="Not enough permissions")
90-
update_dict = item_in.model_dump(exclude_unset=True)
91-
item.sqlmodel_update(update_dict)
92-
session.add(item)
93-
session.commit()
94-
session.refresh(item)
95-
return item
70+
try:
71+
return item_service.update_item_for_user(
72+
session=session, current_user=current_user, item_id=id, item_in=item_in
73+
)
74+
except ServiceError as exc:
75+
_raise_http_from_service_error(exc)
9676

9777

9878
@router.delete("/{id}")
@@ -102,11 +82,11 @@ def delete_item(
10282
"""
10383
Delete an item.
10484
"""
105-
item = session.get(Item, id)
106-
if not item:
107-
raise HTTPException(status_code=404, detail="Item not found")
108-
if not current_user.is_superuser and (item.owner_id != current_user.id):
109-
raise HTTPException(status_code=403, detail="Not enough permissions")
110-
session.delete(item)
111-
session.commit()
85+
try:
86+
item_service.delete_item_for_user(
87+
session=session, current_user=current_user, item_id=id
88+
)
89+
except ServiceError as exc:
90+
_raise_http_from_service_error(exc)
91+
11292
return Message(message="Item deleted successfully")

backend/app/api/routes/login.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
from fastapi.responses import HTMLResponse
66
from fastapi.security import OAuth2PasswordRequestForm
77

8-
from app import crud
98
from app.api.deps import CurrentUser, SessionDep, get_current_active_superuser
109
from app.core import security
1110
from app.core.config import settings
1211
from app.models import Message, NewPassword, Token, UserPublic, UserUpdate
12+
from app.services import auth_service, user_service
1313
from app.utils import (
1414
generate_password_reset_token,
1515
generate_reset_password_email,
@@ -27,7 +27,7 @@ def login_access_token(
2727
"""
2828
OAuth2 compatible token login, get an access token for future requests
2929
"""
30-
user = crud.authenticate(
30+
user = auth_service.authenticate(
3131
session=session, email=form_data.username, password=form_data.password
3232
)
3333
if not user:
@@ -55,7 +55,7 @@ def recover_password(email: str, session: SessionDep) -> Message:
5555
"""
5656
Password Recovery
5757
"""
58-
user = crud.get_user_by_email(session=session, email=email)
58+
user = user_service.get_user_by_email(session=session, email=email)
5959

6060
# Always return the same response to prevent email enumeration attacks
6161
# Only send email if user actually exists
@@ -82,14 +82,14 @@ def reset_password(session: SessionDep, body: NewPassword) -> Message:
8282
email = verify_password_reset_token(token=body.token)
8383
if not email:
8484
raise HTTPException(status_code=400, detail="Invalid token")
85-
user = crud.get_user_by_email(session=session, email=email)
85+
user = user_service.get_user_by_email(session=session, email=email)
8686
if not user:
8787
# Don't reveal that the user doesn't exist - use same error as invalid token
8888
raise HTTPException(status_code=400, detail="Invalid token")
8989
elif not user.is_active:
9090
raise HTTPException(status_code=400, detail="Inactive user")
9191
user_in_update = UserUpdate(password=body.new_password)
92-
crud.update_user(
92+
user_service.update_user(
9393
session=session,
9494
db_user=user,
9595
user_in=user_in_update,
@@ -106,7 +106,7 @@ def recover_password_html_content(email: str, session: SessionDep) -> Any:
106106
"""
107107
HTML Content for Password Recovery
108108
"""
109-
user = crud.get_user_by_email(session=session, email=email)
109+
user = user_service.get_user_by_email(session=session, email=email)
110110

111111
if not user:
112112
raise HTTPException(

backend/app/api/routes/private.py

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,8 @@
44
from pydantic import BaseModel
55

66
from app.api.deps import SessionDep
7-
from app.core.security import get_password_hash
8-
from app.models import (
9-
User,
10-
UserPublic,
11-
)
7+
from app.models import UserPublic
8+
from app.services import user_service
129

1310
router = APIRouter(tags=["private"], prefix="/private")
1411

@@ -25,14 +22,9 @@ def create_user(user_in: PrivateUserCreate, session: SessionDep) -> Any:
2522
"""
2623
Create a new user.
2724
"""
28-
29-
user = User(
25+
return user_service.create_private_user(
26+
session=session,
3027
email=user_in.email,
28+
password=user_in.password,
3129
full_name=user_in.full_name,
32-
hashed_password=get_password_hash(user_in.password),
3330
)
34-
35-
session.add(user)
36-
session.commit()
37-
38-
return user

0 commit comments

Comments
 (0)