From 176b6fb1c9502bb516d27c166812b2ea706c8a8e Mon Sep 17 00:00:00 2001 From: Alejandra <90076947+alejsdev@users.noreply.github.com> Date: Wed, 21 Feb 2024 15:55:19 -0500 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor=20update=20endpoi?= =?UTF-8?q?nts=20and=20regenerate=20client=20for=20new-frontend=20(#602)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/app/api/api_v1/endpoints/users.py | 72 +++++++++++++------ src/backend/app/app/models.py | 6 +- src/new-frontend/src/client/index.ts | 2 + .../src/client/models/UpdatePassword.ts | 9 +++ .../src/client/models/UserUpdateMe.ts | 1 - .../src/client/schemas/$UpdatePassword.ts | 16 +++++ .../src/client/schemas/$UserUpdateMe.ts | 3 - .../src/client/services/UsersService.ts | 57 ++++++++++----- 8 files changed, 121 insertions(+), 45 deletions(-) create mode 100644 src/new-frontend/src/client/models/UpdatePassword.ts create mode 100644 src/new-frontend/src/client/schemas/$UpdatePassword.ts diff --git a/src/backend/app/app/api/api_v1/endpoints/users.py b/src/backend/app/app/api/api_v1/endpoints/users.py index e3ec0fd..f3ddd35 100644 --- a/src/backend/app/app/api/api_v1/endpoints/users.py +++ b/src/backend/app/app/api/api_v1/endpoints/users.py @@ -10,8 +10,10 @@ from app.api.deps import ( get_current_active_superuser, ) from app.core.config import settings +from app.core.security import get_password_hash, verify_password from app.models import ( Message, + UpdatePassword, User, UserCreate, UserCreateOpen, @@ -60,24 +62,40 @@ def create_user(*, session: SessionDep, user_in: UserCreate) -> Any: return user -@router.put("/me", response_model=UserOut) +@router.patch("/me", response_model=UserOut) def update_user_me( - *, session: SessionDep, body: UserUpdateMe, current_user: CurrentUser + *, session: SessionDep, user_in: UserUpdateMe, current_user: CurrentUser ) -> Any: """ Update own user. """ - # TODO: Refactor when SQLModel has update - # current_user_data = jsonable_encoder(current_user) - # user_in = UserUpdate(**current_user_data) - # if password is not None: - # user_in.password = password - # if full_name is not None: - # user_in.full_name = full_name - # if email is not None: - # user_in.email = email - # user = crud.user.update(session, session_obj=current_user, obj_in=user_in) - # return user + + user_data = user_in.model_dump(exclude_unset=True) + current_user.sqlmodel_update(user_data) + session.add(current_user) + session.commit() + session.refresh(current_user) + return current_user + + +@router.patch("/me/password", response_model=Message) +def update_password_me( + *, session: SessionDep, body: UpdatePassword, current_user: CurrentUser +) -> Any: + """ + Update own password. + """ + if not verify_password(body.current_password, current_user.hashed_password): + raise HTTPException(status_code=400, detail="Incorrect password") + if body.current_password == body.new_password: + raise HTTPException( + status_code=400, detail="New password cannot be the same as the current one" + ) + hashed_password = get_password_hash(body.new_password) + current_user.hashed_password = hashed_password + session.add(current_user) + session.commit() + return Message(message="Password updated successfully") @router.get("/me", response_model=UserOut) @@ -128,7 +146,7 @@ def read_user_by_id( return user -@router.put( +@router.patch( "/{user_id}", dependencies=[Depends(get_current_active_superuser)], response_model=UserOut, @@ -143,15 +161,23 @@ def update_user( Update a user. """ - # TODO: Refactor when SQLModel has update - # user = session.get(User, user_id) - # if not user: - # raise HTTPException( - # status_code=404, - # detail="The user with this username does not exist in the system", - # ) - # user = crud.user.update(session, db_obj=user, obj_in=user_in) - # return user + db_user = session.get(User, user_id) + if not db_user: + raise HTTPException( + status_code=404, + detail="The user with this username does not exist in the system", + ) + user_data = user_in.model_dump(exclude_unset=True) + extra_data = {} + if "password" in user_data: + password = user_data["password"] + hashed_password = get_password_hash(password) + extra_data["hashed_password"] = hashed_password + db_user.sqlmodel_update(user_data, update=extra_data) + session.add(db_user) + session.commit() + session.refresh(db_user) + return db_user @router.delete("/{user_id}") diff --git a/src/backend/app/app/models.py b/src/backend/app/app/models.py index 505f8b9..9186b58 100644 --- a/src/backend/app/app/models.py +++ b/src/backend/app/app/models.py @@ -30,11 +30,15 @@ class UserUpdate(UserBase): class UserUpdateMe(SQLModel): - password: Union[str, None] = None full_name: Union[str, None] = None email: Union[EmailStr, None] = None +class UpdatePassword(SQLModel): + current_password: str + new_password: str + + # Database model, database table inferred from class name class User(UserBase, table=True): id: Union[int, None] = Field(default=None, primary_key=True) diff --git a/src/new-frontend/src/client/index.ts b/src/new-frontend/src/client/index.ts index 59b2403..adc379d 100644 --- a/src/new-frontend/src/client/index.ts +++ b/src/new-frontend/src/client/index.ts @@ -15,6 +15,7 @@ export type { ItemUpdate } from './models/ItemUpdate'; export type { Message } from './models/Message'; export type { NewPassword } from './models/NewPassword'; export type { Token } from './models/Token'; +export type { UpdatePassword } from './models/UpdatePassword'; export type { UserCreate } from './models/UserCreate'; export type { UserCreateOpen } from './models/UserCreateOpen'; export type { UserOut } from './models/UserOut'; @@ -30,6 +31,7 @@ export { $ItemUpdate } from './schemas/$ItemUpdate'; export { $Message } from './schemas/$Message'; export { $NewPassword } from './schemas/$NewPassword'; export { $Token } from './schemas/$Token'; +export { $UpdatePassword } from './schemas/$UpdatePassword'; export { $UserCreate } from './schemas/$UserCreate'; export { $UserCreateOpen } from './schemas/$UserCreateOpen'; export { $UserOut } from './schemas/$UserOut'; diff --git a/src/new-frontend/src/client/models/UpdatePassword.ts b/src/new-frontend/src/client/models/UpdatePassword.ts new file mode 100644 index 0000000..f0c4b69 --- /dev/null +++ b/src/new-frontend/src/client/models/UpdatePassword.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +export type UpdatePassword = { + current_password: string; + new_password: string; +}; diff --git a/src/new-frontend/src/client/models/UserUpdateMe.ts b/src/new-frontend/src/client/models/UserUpdateMe.ts index bfed1a4..84ee306 100644 --- a/src/new-frontend/src/client/models/UserUpdateMe.ts +++ b/src/new-frontend/src/client/models/UserUpdateMe.ts @@ -4,7 +4,6 @@ /* eslint-disable */ export type UserUpdateMe = { - password?: string; full_name?: string; email?: string; }; diff --git a/src/new-frontend/src/client/schemas/$UpdatePassword.ts b/src/new-frontend/src/client/schemas/$UpdatePassword.ts new file mode 100644 index 0000000..1875881 --- /dev/null +++ b/src/new-frontend/src/client/schemas/$UpdatePassword.ts @@ -0,0 +1,16 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $UpdatePassword = { + properties: { + current_password: { + type: 'string', + isRequired: true, +}, + new_password: { + type: 'string', + isRequired: true, +}, + }, +} as const; diff --git a/src/new-frontend/src/client/schemas/$UserUpdateMe.ts b/src/new-frontend/src/client/schemas/$UserUpdateMe.ts index d1408a1..0aaf6ab 100644 --- a/src/new-frontend/src/client/schemas/$UserUpdateMe.ts +++ b/src/new-frontend/src/client/schemas/$UserUpdateMe.ts @@ -4,9 +4,6 @@ /* eslint-disable */ export const $UserUpdateMe = { properties: { - password: { - type: 'string', -}, full_name: { type: 'string', }, diff --git a/src/new-frontend/src/client/services/UsersService.ts b/src/new-frontend/src/client/services/UsersService.ts index b5911d6..16481fc 100644 --- a/src/new-frontend/src/client/services/UsersService.ts +++ b/src/new-frontend/src/client/services/UsersService.ts @@ -3,6 +3,7 @@ /* tslint:disable */ /* eslint-disable */ import type { Message } from '../models/Message'; +import type { UpdatePassword } from '../models/UpdatePassword'; import type { UserCreate } from '../models/UserCreate'; import type { UserCreateOpen } from '../models/UserCreateOpen'; import type { UserOut } from '../models/UserOut'; @@ -88,7 +89,7 @@ requestBody, requestBody: UserUpdateMe, }): CancelablePromise { return __request(OpenAPI, { - method: 'PUT', + method: 'PATCH', url: '/api/v1/users/me', body: requestBody, mediaType: 'application/json', @@ -98,6 +99,28 @@ requestBody: UserUpdateMe, }); } + /** + * Update Password Me + * Update own password. + * @returns Message Successful Response + * @throws ApiError + */ + public static updatePasswordMe({ +requestBody, +}: { +requestBody: UpdatePassword, +}): CancelablePromise { + return __request(OpenAPI, { + method: 'PATCH', + url: '/api/v1/users/me/password', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } + /** * Create User Open * Create new user without the need to be logged in. @@ -144,26 +167,22 @@ userId: number, } /** - * Update User - * Update a user. - * @returns UserOut Successful Response + * Delete User + * Delete a user. + * @returns Message Successful Response * @throws ApiError */ - public static updateUser({ + public static deleteUser({ userId, -requestBody, }: { userId: number, -requestBody: UserUpdate, -}): CancelablePromise { +}): CancelablePromise { return __request(OpenAPI, { - method: 'PUT', + method: 'DELETE', url: '/api/v1/users/{user_id}', path: { 'user_id': userId, }, - body: requestBody, - mediaType: 'application/json', errors: { 422: `Validation Error`, }, @@ -171,22 +190,26 @@ requestBody: UserUpdate, } /** - * Delete User - * Delete a user. - * @returns Message Successful Response + * Update User + * Update a user. + * @returns UserOut Successful Response * @throws ApiError */ - public static deleteUser({ + public static updateUser({ userId, +requestBody, }: { userId: number, -}): CancelablePromise { +requestBody: UserUpdate, +}): CancelablePromise { return __request(OpenAPI, { - method: 'DELETE', + method: 'PATCH', url: '/api/v1/users/{user_id}', path: { 'user_id': userId, }, + body: requestBody, + mediaType: 'application/json', errors: { 422: `Validation Error`, },