Skip to content

Commit 176b6fb

Browse files
authored
♻️ Refactor update endpoints and regenerate client for new-frontend (#602)
1 parent fe95750 commit 176b6fb

File tree

8 files changed

+121
-45
lines changed

8 files changed

+121
-45
lines changed

src/backend/app/app/api/api_v1/endpoints/users.py

Lines changed: 49 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010
get_current_active_superuser,
1111
)
1212
from app.core.config import settings
13+
from app.core.security import get_password_hash, verify_password
1314
from app.models import (
1415
Message,
16+
UpdatePassword,
1517
User,
1618
UserCreate,
1719
UserCreateOpen,
@@ -60,24 +62,40 @@ def create_user(*, session: SessionDep, user_in: UserCreate) -> Any:
6062
return user
6163

6264

63-
@router.put("/me", response_model=UserOut)
65+
@router.patch("/me", response_model=UserOut)
6466
def update_user_me(
65-
*, session: SessionDep, body: UserUpdateMe, current_user: CurrentUser
67+
*, session: SessionDep, user_in: UserUpdateMe, current_user: CurrentUser
6668
) -> Any:
6769
"""
6870
Update own user.
6971
"""
70-
# TODO: Refactor when SQLModel has update
71-
# current_user_data = jsonable_encoder(current_user)
72-
# user_in = UserUpdate(**current_user_data)
73-
# if password is not None:
74-
# user_in.password = password
75-
# if full_name is not None:
76-
# user_in.full_name = full_name
77-
# if email is not None:
78-
# user_in.email = email
79-
# user = crud.user.update(session, session_obj=current_user, obj_in=user_in)
80-
# return user
72+
73+
user_data = user_in.model_dump(exclude_unset=True)
74+
current_user.sqlmodel_update(user_data)
75+
session.add(current_user)
76+
session.commit()
77+
session.refresh(current_user)
78+
return current_user
79+
80+
81+
@router.patch("/me/password", response_model=Message)
82+
def update_password_me(
83+
*, session: SessionDep, body: UpdatePassword, current_user: CurrentUser
84+
) -> Any:
85+
"""
86+
Update own password.
87+
"""
88+
if not verify_password(body.current_password, current_user.hashed_password):
89+
raise HTTPException(status_code=400, detail="Incorrect password")
90+
if body.current_password == body.new_password:
91+
raise HTTPException(
92+
status_code=400, detail="New password cannot be the same as the current one"
93+
)
94+
hashed_password = get_password_hash(body.new_password)
95+
current_user.hashed_password = hashed_password
96+
session.add(current_user)
97+
session.commit()
98+
return Message(message="Password updated successfully")
8199

82100

83101
@router.get("/me", response_model=UserOut)
@@ -128,7 +146,7 @@ def read_user_by_id(
128146
return user
129147

130148

131-
@router.put(
149+
@router.patch(
132150
"/{user_id}",
133151
dependencies=[Depends(get_current_active_superuser)],
134152
response_model=UserOut,
@@ -143,15 +161,23 @@ def update_user(
143161
Update a user.
144162
"""
145163

146-
# TODO: Refactor when SQLModel has update
147-
# user = session.get(User, user_id)
148-
# if not user:
149-
# raise HTTPException(
150-
# status_code=404,
151-
# detail="The user with this username does not exist in the system",
152-
# )
153-
# user = crud.user.update(session, db_obj=user, obj_in=user_in)
154-
# return user
164+
db_user = session.get(User, user_id)
165+
if not db_user:
166+
raise HTTPException(
167+
status_code=404,
168+
detail="The user with this username does not exist in the system",
169+
)
170+
user_data = user_in.model_dump(exclude_unset=True)
171+
extra_data = {}
172+
if "password" in user_data:
173+
password = user_data["password"]
174+
hashed_password = get_password_hash(password)
175+
extra_data["hashed_password"] = hashed_password
176+
db_user.sqlmodel_update(user_data, update=extra_data)
177+
session.add(db_user)
178+
session.commit()
179+
session.refresh(db_user)
180+
return db_user
155181

156182

157183
@router.delete("/{user_id}")

src/backend/app/app/models.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,15 @@ class UserUpdate(UserBase):
3030

3131

3232
class UserUpdateMe(SQLModel):
33-
password: Union[str, None] = None
3433
full_name: Union[str, None] = None
3534
email: Union[EmailStr, None] = None
3635

3736

37+
class UpdatePassword(SQLModel):
38+
current_password: str
39+
new_password: str
40+
41+
3842
# Database model, database table inferred from class name
3943
class User(UserBase, table=True):
4044
id: Union[int, None] = Field(default=None, primary_key=True)

src/new-frontend/src/client/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export type { ItemUpdate } from './models/ItemUpdate';
1515
export type { Message } from './models/Message';
1616
export type { NewPassword } from './models/NewPassword';
1717
export type { Token } from './models/Token';
18+
export type { UpdatePassword } from './models/UpdatePassword';
1819
export type { UserCreate } from './models/UserCreate';
1920
export type { UserCreateOpen } from './models/UserCreateOpen';
2021
export type { UserOut } from './models/UserOut';
@@ -30,6 +31,7 @@ export { $ItemUpdate } from './schemas/$ItemUpdate';
3031
export { $Message } from './schemas/$Message';
3132
export { $NewPassword } from './schemas/$NewPassword';
3233
export { $Token } from './schemas/$Token';
34+
export { $UpdatePassword } from './schemas/$UpdatePassword';
3335
export { $UserCreate } from './schemas/$UserCreate';
3436
export { $UserCreateOpen } from './schemas/$UserCreateOpen';
3537
export { $UserOut } from './schemas/$UserOut';
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/* generated using openapi-typescript-codegen -- do no edit */
2+
/* istanbul ignore file */
3+
/* tslint:disable */
4+
/* eslint-disable */
5+
6+
export type UpdatePassword = {
7+
current_password: string;
8+
new_password: string;
9+
};

src/new-frontend/src/client/models/UserUpdateMe.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
/* eslint-disable */
55

66
export type UserUpdateMe = {
7-
password?: string;
87
full_name?: string;
98
email?: string;
109
};
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/* generated using openapi-typescript-codegen -- do no edit */
2+
/* istanbul ignore file */
3+
/* tslint:disable */
4+
/* eslint-disable */
5+
export const $UpdatePassword = {
6+
properties: {
7+
current_password: {
8+
type: 'string',
9+
isRequired: true,
10+
},
11+
new_password: {
12+
type: 'string',
13+
isRequired: true,
14+
},
15+
},
16+
} as const;

src/new-frontend/src/client/schemas/$UserUpdateMe.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,6 @@
44
/* eslint-disable */
55
export const $UserUpdateMe = {
66
properties: {
7-
password: {
8-
type: 'string',
9-
},
107
full_name: {
118
type: 'string',
129
},

src/new-frontend/src/client/services/UsersService.ts

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
/* tslint:disable */
44
/* eslint-disable */
55
import type { Message } from '../models/Message';
6+
import type { UpdatePassword } from '../models/UpdatePassword';
67
import type { UserCreate } from '../models/UserCreate';
78
import type { UserCreateOpen } from '../models/UserCreateOpen';
89
import type { UserOut } from '../models/UserOut';
@@ -88,7 +89,7 @@ requestBody,
8889
requestBody: UserUpdateMe,
8990
}): CancelablePromise<UserOut> {
9091
return __request(OpenAPI, {
91-
method: 'PUT',
92+
method: 'PATCH',
9293
url: '/api/v1/users/me',
9394
body: requestBody,
9495
mediaType: 'application/json',
@@ -98,6 +99,28 @@ requestBody: UserUpdateMe,
9899
});
99100
}
100101

102+
/**
103+
* Update Password Me
104+
* Update own password.
105+
* @returns Message Successful Response
106+
* @throws ApiError
107+
*/
108+
public static updatePasswordMe({
109+
requestBody,
110+
}: {
111+
requestBody: UpdatePassword,
112+
}): CancelablePromise<Message> {
113+
return __request(OpenAPI, {
114+
method: 'PATCH',
115+
url: '/api/v1/users/me/password',
116+
body: requestBody,
117+
mediaType: 'application/json',
118+
errors: {
119+
422: `Validation Error`,
120+
},
121+
});
122+
}
123+
101124
/**
102125
* Create User Open
103126
* Create new user without the need to be logged in.
@@ -144,49 +167,49 @@ userId: number,
144167
}
145168

146169
/**
147-
* Update User
148-
* Update a user.
149-
* @returns UserOut Successful Response
170+
* Delete User
171+
* Delete a user.
172+
* @returns Message Successful Response
150173
* @throws ApiError
151174
*/
152-
public static updateUser({
175+
public static deleteUser({
153176
userId,
154-
requestBody,
155177
}: {
156178
userId: number,
157-
requestBody: UserUpdate,
158-
}): CancelablePromise<UserOut> {
179+
}): CancelablePromise<Message> {
159180
return __request(OpenAPI, {
160-
method: 'PUT',
181+
method: 'DELETE',
161182
url: '/api/v1/users/{user_id}',
162183
path: {
163184
'user_id': userId,
164185
},
165-
body: requestBody,
166-
mediaType: 'application/json',
167186
errors: {
168187
422: `Validation Error`,
169188
},
170189
});
171190
}
172191

173192
/**
174-
* Delete User
175-
* Delete a user.
176-
* @returns Message Successful Response
193+
* Update User
194+
* Update a user.
195+
* @returns UserOut Successful Response
177196
* @throws ApiError
178197
*/
179-
public static deleteUser({
198+
public static updateUser({
180199
userId,
200+
requestBody,
181201
}: {
182202
userId: number,
183-
}): CancelablePromise<Message> {
203+
requestBody: UserUpdate,
204+
}): CancelablePromise<UserOut> {
184205
return __request(OpenAPI, {
185-
method: 'DELETE',
206+
method: 'PATCH',
186207
url: '/api/v1/users/{user_id}',
187208
path: {
188209
'user_id': userId,
189210
},
211+
body: requestBody,
212+
mediaType: 'application/json',
190213
errors: {
191214
422: `Validation Error`,
192215
},

0 commit comments

Comments
 (0)