Skip to content

Commit 409f1d4

Browse files
committed
Refactored everything (again)
1 parent 6b42ec6 commit 409f1d4

32 files changed

+1374
-894
lines changed

backend/app/alembic/env.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ def get_url() -> str:
2626

2727

2828
def run_migrations_offline() -> None:
29-
"""Run migrations in 'offline' mode.
29+
"""
30+
Run migrations in 'offline' mode.
3031
3132
This configures the context with just a URL
3233
and not an Engine, though an Engine is acceptable
@@ -50,7 +51,8 @@ def run_migrations_offline() -> None:
5051

5152

5253
def run_migrations_online() -> None:
53-
"""Run migrations in 'online' mode.
54+
"""
55+
Run migrations in 'online' mode.
5456
5557
In this scenario we need to create an Engine
5658
and associate a connection with the context.

backend/app/alembic/versions/1a31ce608336_add_cascade_delete_relationships.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
"""Add cascade delete relationships.
1+
"""
2+
Add cascade delete relationships.
23
34
Revision ID: 1a31ce608336
45
Revises: d98dd8ec85a3

backend/app/alembic/versions/9c0a54914c78_add_max_length_for_string_varchar_.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
"""Add max length for string(varchar) fields in User and Items models.
1+
"""
2+
Add max length for string(varchar) fields in User and Items models.
23
34
Revision ID: 9c0a54914c78
45
Revises: e2412789c190

backend/app/alembic/versions/d98dd8ec85a3_edit_replace_id_integers_in_all_models_.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
"""Edit replace id integers in all models to use UUID instead.
1+
"""
2+
Edit replace id integers in all models to use UUID instead.
23
34
Revision ID: d98dd8ec85a3
45
Revises: 9c0a54914c78

backend/app/alembic/versions/e2412789c190_initialize_models.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
"""Initialize models.
1+
"""
2+
Initialize models.
23
34
Revision ID: e2412789c190
45
Revises:

backend/app/api/deps.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from app.models import TokenPayload, User
1616

1717
reusable_oauth2 = OAuth2PasswordBearer(
18-
tokenUrl=f"{config.settings.API_V1_STR}/login/access-token", # noqa: WPS237
18+
tokenUrl=f"{config.settings.API_V1_STR}/login/access-token",
1919
)
2020

2121

backend/app/api/routes/items.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
"""Item management API endpoints."""
22

33
import uuid
4+
from mailbox import Message
45

5-
# Removed unused Any import
66
from fastapi import APIRouter, HTTPException
77
from sqlmodel import func, select
88

99
from app.api.deps import CurrentUser, SessionDep
1010
from app.constants import BAD_REQUEST_CODE, NOT_FOUND_CODE
11-
from app.models import Item, ItemCreate, ItemPublic, ItemsPublic, ItemUpdate, Message
11+
12+
# Removed unused Any import
13+
from app.models import Item, ItemCreate, ItemPublic, ItemsPublic, ItemUpdate
1214

1315
router = APIRouter(prefix="/items", tags=["items"])
1416

backend/app/api/routes/private.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@
77

88
from app.api.deps import SessionDep
99
from app.core.security import get_password_hash
10-
from app.models import (
11-
User,
12-
UserPublic,
13-
)
10+
from app.models import User, UserPublic
1411

1512
router = APIRouter(tags=["private"], prefix="/private")
1613

@@ -21,7 +18,6 @@ class PrivateUserCreate(BaseModel): # type: ignore[explicit-any]
2118
email: str
2219
password: str
2320
full_name: str
24-
is_verified: bool = False
2521

2622

2723
@router.post("/users/")

backend/app/api/routes/users.py

Lines changed: 9 additions & 225 deletions
Original file line numberDiff line numberDiff line change
@@ -1,229 +1,13 @@
1-
"""models.User management API endpoints."""
1+
"""User management API endpoints - consolidated router."""
22

3-
import uuid
3+
from fastapi import APIRouter
44

5-
from fastapi import APIRouter, Depends, HTTPException
6-
from sqlmodel import col, delete, func, select
5+
from app.api.routes.users_admin import router as admin_router
6+
from app.api.routes.users_auth import router as auth_router
7+
from app.api.routes.users_profile import router as profile_router
78

8-
from app import crud, models
9-
from app.api.deps import (
10-
SessionDep,
11-
get_current_active_superuser,
12-
)
13-
from app.constants import (
14-
BAD_REQUEST_CODE,
15-
CONFLICT_CODE,
16-
FORBIDDEN_CODE,
17-
NOT_FOUND_CODE,
18-
)
19-
from app.core.config import settings
20-
from app.core.security import get_password_hash, verify_password
21-
from app.email_utils import generate_new_account_email, send_email
9+
router = APIRouter()
2210

23-
router = APIRouter(prefix="/users", tags=["users"])
24-
25-
26-
@router.get(
27-
"/",
28-
dependencies=[Depends(get_current_active_superuser)],
29-
)
30-
def read_users(
31-
session: SessionDep,
32-
skip: int = 0,
33-
limit: int = 100,
34-
) -> models.UsersPublic:
35-
"""Retrieve users."""
36-
count_statement = select(func.count()).select_from(models.User)
37-
count = session.exec(count_statement).one()
38-
39-
statement = select(models.User).offset(skip).limit(limit)
40-
users = session.exec(statement).all()
41-
42-
return models.UsersPublic(user_data=users, count=count)
43-
44-
45-
@router.post(
46-
"/",
47-
dependencies=[Depends(get_current_active_superuser)],
48-
)
49-
def create_user(
50-
*,
51-
session: SessionDep,
52-
user_in: models.UserCreate,
53-
) -> models.UserPublic:
54-
"""Create new user."""
55-
user = crud.get_user_by_email(session=session, email=user_in.email)
56-
if user:
57-
raise HTTPException(
58-
status_code=BAD_REQUEST_CODE,
59-
detail="The user with this email already exists in the system.",
60-
)
61-
62-
user = crud.create_user(session=session, user_create=user_in)
63-
if not settings.emails_enabled and user_in.email:
64-
email_data = generate_new_account_email(
65-
email_to=user_in.email,
66-
username=user_in.email,
67-
password=user_in.password,
68-
)
69-
send_email(
70-
email_to=user_in.email,
71-
subject=email_data.subject,
72-
html_content=email_data.html_content,
73-
)
74-
return models.UserPublic.model_validate(user)
75-
76-
77-
@router.patch("/me")
78-
def update_user_me(
79-
*,
80-
session: SessionDep,
81-
user_in: models.UserUpdateMe,
82-
current_user: models.User,
83-
) -> models.UserPublic:
84-
"""Update own user."""
85-
if user_in.email:
86-
existing_user = crud.get_user_by_email(session=session, email=user_in.email)
87-
if existing_user and existing_user.id != current_user.id:
88-
raise HTTPException(
89-
status_code=CONFLICT_CODE,
90-
detail="models.User with this email already exists",
91-
)
92-
user_data = user_in.model_dump(exclude_unset=True)
93-
current_user.sqlmodel_update(user_data)
94-
session.add(current_user)
95-
session.commit()
96-
session.refresh(current_user)
97-
return models.UserPublic.model_validate(current_user)
98-
99-
100-
@router.patch("/me/password")
101-
def update_password_me(
102-
*,
103-
session: SessionDep,
104-
body: models.UpdatePassword,
105-
current_user: models.User,
106-
) -> models.Message:
107-
"""Update own password."""
108-
if not verify_password(body.current_password, current_user.hashed_password):
109-
raise HTTPException(status_code=BAD_REQUEST_CODE, detail="Incorrect password")
110-
if body.current_password == body.new_password:
111-
raise HTTPException(
112-
status_code=BAD_REQUEST_CODE,
113-
detail="New password cannot be the same as the current one",
114-
)
115-
hashed_password = get_password_hash(body.new_password)
116-
current_user.hashed_password = hashed_password
117-
session.add(current_user)
118-
session.commit()
119-
return models.Message(message="Password updated successfully")
120-
121-
122-
@router.get("/me")
123-
def read_user_me(current_user: models.User) -> models.UserPublic:
124-
"""Get current user."""
125-
return models.UserPublic.model_validate(current_user)
126-
127-
128-
@router.delete("/me")
129-
def delete_user_me(
130-
session: SessionDep,
131-
current_user: models.User,
132-
) -> models.Message:
133-
"""Delete own user."""
134-
if current_user.is_superuser:
135-
raise HTTPException(
136-
status_code=FORBIDDEN_CODE,
137-
detail="Super users are not allowed to delete themselves",
138-
)
139-
session.delete(current_user)
140-
session.commit()
141-
return models.Message(message="models.User deleted successfully")
142-
143-
144-
@router.post("/signup")
145-
def register_user(
146-
session: SessionDep,
147-
user_in: models.UserRegister,
148-
) -> models.UserPublic:
149-
"""Create new user without the need to be logged in."""
150-
user = crud.get_user_by_email(session=session, email=user_in.email)
151-
if user:
152-
raise HTTPException(
153-
status_code=BAD_REQUEST_CODE,
154-
detail="The user with this email already exists in the system",
155-
)
156-
user_create = models.UserCreate.model_validate(user_in)
157-
user = crud.create_user(session=session, user_create=user_create)
158-
return models.UserPublic.model_validate(user)
159-
160-
161-
@router.get("/{user_id}")
162-
def read_user_by_id(
163-
user_id: uuid.UUID,
164-
session: SessionDep,
165-
current_user: models.User,
166-
) -> models.UserPublic:
167-
"""Get a specific user by id."""
168-
user = session.get(models.User, user_id)
169-
if not user:
170-
raise HTTPException(status_code=NOT_FOUND_CODE, detail="models.User not found")
171-
if user == current_user:
172-
return models.UserPublic.model_validate(user)
173-
if not current_user.is_superuser:
174-
raise HTTPException(
175-
status_code=FORBIDDEN_CODE,
176-
detail="The user doesn't have enough privileges",
177-
)
178-
return models.UserPublic.model_validate(user)
179-
180-
181-
@router.patch(
182-
"/{user_id}",
183-
dependencies=[Depends(get_current_active_superuser)],
184-
)
185-
def update_user(
186-
*,
187-
session: SessionDep,
188-
user_id: uuid.UUID,
189-
user_in: models.UserUpdate,
190-
) -> models.UserPublic:
191-
"""Update a user."""
192-
db_user = session.get(models.User, user_id)
193-
if not db_user:
194-
raise HTTPException(
195-
status_code=NOT_FOUND_CODE,
196-
detail="The user with this id does not exist in the system",
197-
)
198-
if user_in.email:
199-
existing_user = crud.get_user_by_email(session=session, email=user_in.email)
200-
if existing_user and existing_user.id != user_id:
201-
raise HTTPException(
202-
status_code=CONFLICT_CODE,
203-
detail="models.User with this email already exists",
204-
)
205-
206-
db_user = crud.update_user(session=session, db_user=db_user, user_in=user_in)
207-
return models.UserPublic.model_validate(db_user)
208-
209-
210-
@router.delete("/{user_id}", dependencies=[Depends(get_current_active_superuser)])
211-
def delete_user(
212-
session: SessionDep,
213-
current_user: models.User,
214-
user_id: uuid.UUID,
215-
) -> models.Message:
216-
"""Delete a user."""
217-
user = session.get(models.User, user_id)
218-
if not user:
219-
raise HTTPException(status_code=NOT_FOUND_CODE, detail="models.User not found")
220-
if user == current_user:
221-
raise HTTPException(
222-
status_code=FORBIDDEN_CODE,
223-
detail="Super users are not allowed to delete themselves",
224-
)
225-
statement = delete(models.Item).where(col(models.Item.owner_id) == user_id) # noqa: WPS221
226-
session.execute(statement) # type: ignore[deprecated]
227-
session.delete(user)
228-
session.commit()
229-
return models.Message(message="models.User deleted successfully")
11+
router.include_router(admin_router)
12+
router.include_router(auth_router)
13+
router.include_router(profile_router)

0 commit comments

Comments
 (0)