Shop registration works now

This commit is contained in:
Thastertyn 2025-03-14 13:40:50 +01:00
parent a0d238c840
commit d87c280109
15 changed files with 98 additions and 727 deletions

View File

@ -5,7 +5,7 @@ from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jwt.exceptions import InvalidTokenError from jwt.exceptions import InvalidTokenError
from pydantic import ValidationError from pydantic import ValidationError
from sqlmodel import Session from sqlmodel import Session, select
from app.core import security from app.core import security
from app.core.config import settings from app.core.config import settings
@ -19,7 +19,7 @@ reusable_oauth2 = OAuth2PasswordBearer(
SessionDep = Annotated[Session, Depends(get_session)] SessionDep = Annotated[Session, Depends(get_session)]
TokenDep = Annotated[str, Depends(reusable_oauth2)] TokenDep = Annotated[str, Depends(reusable_oauth2)]
LoginDep = Annotated[OAuth2PasswordRequestForm, Depends()] LoginDep = Annotated[OAuth2PasswordRequestForm, Depends(OAuth2PasswordRequestForm)]
def get_current_user(session: SessionDep, token: TokenDep) -> User: def get_current_user(session: SessionDep, token: TokenDep) -> User:
@ -33,11 +33,10 @@ def get_current_user(session: SessionDep, token: TokenDep) -> User:
status_code=status.HTTP_403_FORBIDDEN, status_code=status.HTTP_403_FORBIDDEN,
detail="Could not validate credentials", detail="Could not validate credentials",
) )
user = session.get(User, {"uuid": token_data.sub}) stmt = select(User).where(User.uuid == token_data.sub)
user = session.exec(stmt).one_or_none()
if not user: if not user:
raise HTTPException(status_code=404, detail="User not found") raise HTTPException(status_code=404, detail="User not found")
if not user.is_active:
raise HTTPException(status_code=400, detail="Inactive user")
return user return user

View File

@ -30,7 +30,7 @@ def login_access_token(
""" """
user = None user = None
user = user_crud.authenticate( user = user_crud.authenticate(
session=session, email=form_data.username, password=form_data.password, shop_id=None session=session, email=form_data.username, password=form_data.password, shop_uuid=None
) )
if not user: if not user:
raise HTTPException(status_code=400, detail="Incorrect email or password") raise HTTPException(status_code=400, detail="Incorrect email or password")
@ -39,6 +39,6 @@ def login_access_token(
access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES) access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
return Token( return Token(
access_token=security.create_access_token( access_token=security.create_access_token(
user.id, expires_delta=access_token_expires user.uuid, expires_delta=access_token_expires
) )
) )

View File

@ -1,18 +1,18 @@
from fastapi import APIRouter from fastapi import APIRouter, HTTPException, status
from app.api.dependencies import CurrentOwnerUser, SessionDep from app.api.dependencies import CurrentOwnerUser, SessionDep
from app.schemas.shop_schemas import ShopCreate from app.schemas.shop_schemas import ShopCreate
from app.schemas.user_schemas import Token from app.schemas.user_schemas import Token
from app.crud.shop_crud import create_shop
router = APIRouter(prefix="/shop", tags=["Shop"]) router = APIRouter(prefix="/shop", tags=["Dashboard"])
@router.post("") @router.post("", response_model=bool, status_code=201)
def register_new_shop( def register_new_shop(
session: SessionDep, session: SessionDep,
current_user: CurrentOwnerUser, current_user: CurrentOwnerUser,
shop_data: ShopCreate shop_data: ShopCreate
) -> Token: ) -> Token:
""" create_shop(session, shop_data, current_user)
OAuth2 compatible token login, get an access token for future requests return True
"""

View File

@ -1,38 +1,35 @@
import logging import logging
import re import re
from fastapi import APIRouter, Body, HTTPException, status from fastapi import APIRouter, HTTPException, status
from sqlalchemy.exc import IntegrityError from sqlalchemy.exc import IntegrityError
from app.api.dependencies import SessionDep from app.api.dependencies import CurrentOwnerUser, SessionDep
from app.crud import user_crud from app.crud import user_crud
from app.database.models.user_model import UserRole from app.database.models.user_model import UserRole
from app.schemas.user_schemas import UserRegister from app.schemas.user_schemas import UserRegister, UserUpdate
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
INTERNAL_SERVER_ERROR = HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Internal server error")
router = APIRouter( router = APIRouter(
prefix="/user", prefix="/user",
tags=["User"] tags=["User", "Dashboard"]
) )
@router.delete("/delete", summary="Delete user") @router.get("", summary="Get information about currently logged in user")
async def delete_user(): async def get_user(session: SessionDep, current_user: CurrentOwnerUser):
raise NotImplementedError("delete_user() needs to be implemented.") pass
@router.delete("/logout", summary="User logout") @router.post("", summary="Register new user", status_code=status.HTTP_201_CREATED, response_model=bool)
async def logout():
raise NotImplementedError("logout() needs to be implemented.")
@router.post("/register", summary="Register new user")
async def register(session: SessionDep, user_data: UserRegister): async def register(session: SessionDep, user_data: UserRegister):
try: try:
user_crud.create_user(session, user_data, None, UserRole.OWNER) user_crud.create_user(session, user_data, None, UserRole.OWNER)
return {"detail": "Registered succeesfully"} return True
except IntegrityError as e: except IntegrityError as e:
field_mapping = {"uuid": "email"} # If a UUID is duplicate, it means email is in use field_mapping = {"uuid": "email"} # If a UUID is duplicate, it means email is in use
@ -49,10 +46,17 @@ async def register(session: SessionDep, user_data: UserRegister):
detail=detail detail=detail
) )
except Exception as e: except Exception as e:
if isinstance(e, HTTPException):
raise
logger.error(e) logger.error(e)
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to register") raise INTERNAL_SERVER_ERROR
@router.put("/update", summary="Update user details") @router.delete("", summary="Delete user")
async def update_user(data: dict = Body(...)): async def delete_user():
raise NotImplementedError("update_user() needs to be implemented.") raise HTTPException(status_code=status.HTTP_501_NOT_IMPLEMENTED, detail="delete_user() not implemented")
@router.put("", summary="Update user details")
async def update_user(data: UserUpdate):
raise HTTPException(status_code=status.HTTP_501_NOT_IMPLEMENTED, detail="update_user() not implemented")

View File

@ -34,6 +34,14 @@ class ShopBusinessHours(BaseModel):
hours: list[ShopBusinessHourEntry] hours: list[ShopBusinessHourEntry]
class ShopAddress(SQLModel):
street: str = Field(max_length=255, nullable=False)
city: str = Field(max_length=100, nullable=False)
state: str = Field(max_length=100, nullable=True)
postal_code: str = Field(max_length=20, nullable=False)
country: str = Field(max_length=100, nullable=False)
class Shop(SQLModel, table=True): class Shop(SQLModel, table=True):
__tablename__ = 'shop' __tablename__ = 'shop'
@ -48,16 +56,11 @@ class Shop(SQLModel, table=True):
logo: Optional[str] = Field(max_length=100) logo: Optional[str] = Field(max_length=100)
contact_email: str = Field(max_length=128, nullable=False, unique=True) contact_email: str = Field(max_length=128, nullable=False, unique=True)
phone_number: str = Field(max_length=15, nullable=False) phone_number: str = Field(max_length=15, nullable=False)
address: str = Field(nullable=True) address: ShopAddress = Field(sa_column=Column(JSONB, nullable=False, default=lambda: {}))
business_hours: ShopBusinessHours = Field(sa_column=Column(JSONB, nullable=False, default=lambda: {}))
links: ShopLinks = Field(sa_column=Column(JSONB, nullable=False, default=lambda: {}))
currency: str = Field(max_length=3, nullable=False) currency: str = Field(max_length=3, nullable=False)
business_hours: ShopBusinessHours = Field(
sa_column=Column(JSONB, nullable=False, default=lambda: {})
)
links: ShopLinks = Field(
sa_column=Column(JSONB, nullable=False, default=lambda: {})
)
owner: Optional["User"] = Relationship( owner: Optional["User"] = Relationship(
back_populates='owned_shop', back_populates='owned_shop',
sa_relationship_kwargs={"foreign_keys": "[Shop.owner_id]"} sa_relationship_kwargs={"foreign_keys": "[Shop.owner_id]"}
@ -68,10 +71,11 @@ class Shop(SQLModel, table=True):
sa_relationship_kwargs={"foreign_keys": "[User.shop_id]"} sa_relationship_kwargs={"foreign_keys": "[User.shop_id]"}
) )
__table_args__ = ( # __table_args__ = (
CheckConstraint("business_hours ? 'hours'", name="check_business_hours_keys"), # CheckConstraint("business_hours ? 'hours'", name="check_business_hours_keys"),
CheckConstraint("links ? 'links'", name="check_links_keys"), # CheckConstraint("links ? 'links'", name="check_links_keys"),
) # CheckConstraint("address ? 'address'", name="check_address_keys")
# )
__all__ = ["Shop", "ShopBusinessHours", "ShopLinks", "ShopStatus"] __all__ = ["Shop", "ShopBusinessHours", "ShopLinks", "ShopStatus"]

View File

@ -1,8 +1,14 @@
from pydantic import EmailStr
from sqlmodel import Field, SQLModel from sqlmodel import Field, SQLModel
from app.database.models.shop_model import ShopAddress
class ShopCreate(SQLModel): class ShopCreate(SQLModel):
name: str = Field(max_length=100, nullable=False, unique=True) name: str = Field(max_length=100, nullable=False, unique=True)
description: str = Field(max_length=500, nullable=False) description: str = Field(max_length=500, nullable=False)
currency: str = Field(max_length=3, nullable=False) currency: str = Field(max_length=3, nullable=False)
contact_email: EmailStr = Field()
contact_phone_number: str = Field(min_length=2, max_length=16, schema_extra={"pattern": r'^\+[1-9]\d{1,14}$'})
address: ShopAddress

View File

@ -1,14 +1,15 @@
import re import re
from pydantic import EmailStr, model_validator from typing import Optional
from sqlmodel import Field, SQLModel
from pydantic import BaseModel, EmailStr, Field, model_validator
class UserRegister(SQLModel): class UserRegister(BaseModel):
username: str = Field(min_length=3, max_length=64) username: str = Field(min_length=3, max_length=64)
email: EmailStr = Field() email: EmailStr = Field()
phone_number: str = Field(min_length=2, max_length=16, schema_extra={"pattern": r'^\+[1-9]\d{1,14}$'}) phone_number: str = Field(min_length=2, max_length=16, pattern=r'^\+[1-9]\d{1,14}$')
password: str = Field(min_length=8, max_length=128, password: str = Field(min_length=8, max_length=128, examples=["Abc123#!"],
description="Password must be at least 8 and at most 128 characters long, contain a lower case, upper case letter, a number and a special character (#?!@$ %^&*-)") description="Password must conform to this regex: \n```\n^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$ %^&*-]).{8,128}$\n```")
@model_validator(mode="after") @model_validator(mode="after")
def validate_using_regex(self): def validate_using_regex(self):
@ -20,11 +21,29 @@ class UserRegister(SQLModel):
if not re.match(password_regex, self.password): if not re.match(password_regex, self.password):
raise ValueError("Password is too weak") raise ValueError("Password is too weak")
class UserUpdate(BaseModel):
username: Optional[str] = Field(None, min_length=3, max_length=64)
first_name: Optional[str] = Field(None, max_length=64)
last_name: Optional[str] = Field(None, max_length=64)
email: Optional[EmailStr] = Field(None)
phone_number: Optional[str] = Field(None, min_length=2, max_length=16, pattern=r'^\+[1-9]\d{1,14}$')
password: Optional[str] = Field(None, min_length=8, max_length=128, examples=["Abc123#!"],
description="Password must conform to this regex: \n```\n^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$ %^&*-]).{8,128}$\n```")
class Token(SQLModel): @model_validator(mode="after")
def validate_using_regex(self):
self.__validate_password()
return self
def __validate_password(self):
password_regex = r"^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$ %^&*-]).{8,128}$"
if not re.match(password_regex, self.password):
raise ValueError("Password is too weak")
class Token(BaseModel):
access_token: str access_token: str
token_type: str = "bearer" token_type: str = "bearer"
class TokenPayload(SQLModel): class TokenPayload(BaseModel):
sub: str | None = None sub: str | None = None

View File

@ -1,27 +1,19 @@
import logging
from functools import wraps from functools import wraps
from fastapi import HTTPException from fastapi import HTTPException, status
from sqlalchemy.exc import DatabaseError as SqlAlchemyDatabaseError logger = logging.getLogger(__name__)
from app.core.errors import RepositoryError, ServiceError
def propagate_db_error_to_service(func): def raise_http_errors(func):
@wraps(func) @wraps(func)
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
try: try:
return func(*args, **kwargs) return func(*args, **kwargs)
except (SqlAlchemyDatabaseError, RepositoryError) as e: except Exception as e:
raise ServiceError(str(e)) from e if isinstance(e, HTTPException):
return wrapper raise
logger.error(e)
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Internal server error")
def propagate_service_errors_to_http_errors(func):
@wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except ServiceError as e:
raise HTTPException(status_code=500, detail=str(e)) from e
return wrapper return wrapper

View File

@ -32,6 +32,7 @@ ignore = [
"B008", # do not perform function calls in argument defaults "B008", # do not perform function calls in argument defaults
"W191", # indentation contains tabs "W191", # indentation contains tabs
"B904", # Allow raising exceptions without from e, for HTTPException "B904", # Allow raising exceptions without from e, for HTTPException
"UP007",
] ]
[tool.autopep8] [tool.autopep8]

View File

@ -1,18 +0,0 @@
// This file is auto-generated by @hey-api/openapi-ts
import type { ClientOptions } from './types.gen';
import { type Config, type ClientOptions as DefaultClientOptions, createClient, createConfig } from '@hey-api/client-axios';
/**
* The `createClientConfig()` function will be called on client initialization
* and the returned object will become the client's initial configuration.
*
* You may want to initialize your client this way instead of calling
* `setConfig()`. This is useful for example if you're using Next.js
* to ensure your client always has the correct values.
*/
export type CreateClientConfig<T extends DefaultClientOptions = ClientOptions> = (override?: Config<DefaultClientOptions & T>) => Config<Required<DefaultClientOptions> & T>;
export const client = createClient(createConfig<ClientOptions>({
baseURL: 'http://localhost:8000'
}));

View File

@ -1,3 +0,0 @@
// This file is auto-generated by @hey-api/openapi-ts
export * from './types.gen';
export * from './sdk.gen';

View File

@ -1,217 +0,0 @@
// This file is auto-generated by @hey-api/openapi-ts
import { type Options as ClientOptions, type TDataShape, type Client, urlSearchParamsBodySerializer } from '@hey-api/client-axios';
import type { CartShowCartData, CartAddToCartData, CartAddToCartError, CartRemoveFromCartData, CartRemoveFromCartError, CartUpdateCountInCartData, CartUpdateCountInCartError, CartPurchaseData, UserDeleteUserData, UserLogoutData, UserRegisterData, UserRegisterError, UserUpdateUserData, UserUpdateUserError, UtilsHealthCheckData, UtilsHealthCheckResponse, UtilsTestDbData, UtilsTestDbResponse, LoginLoginAccessTokenData, LoginLoginAccessTokenResponse, LoginLoginAccessTokenError, ShopLoginAccessTokenData, ShopLoginAccessTokenResponse, ShopLoginAccessTokenError, ShopDeleteUserData, ShopDeleteUserError, ShopLogoutData, ShopRegisterData, ShopRegisterError, ShopUpdateUserData, ShopUpdateUserError } from './types.gen';
import { client as _heyApiClient } from './client.gen';
export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean> = ClientOptions<TData, ThrowOnError> & {
/**
* You can provide a client instance returned by `createClient()` instead of
* individual options. This might be also useful if you want to implement a
* custom client.
*/
client?: Client;
/**
* You can pass arbitrary values through the `meta` object. This can be
* used to access values that aren't defined as part of the SDK function.
*/
meta?: Record<string, unknown>;
};
/**
* Show Cart
*/
export const cartShowCart = <ThrowOnError extends boolean = false>(options?: Options<CartShowCartData, ThrowOnError>) => {
return (options?.client ?? _heyApiClient).get<unknown, unknown, ThrowOnError>({
url: '/cart/',
...options
});
};
/**
* Add To Cart
*/
export const cartAddToCart = <ThrowOnError extends boolean = false>(options: Options<CartAddToCartData, ThrowOnError>) => {
return (options.client ?? _heyApiClient).put<unknown, CartAddToCartError, ThrowOnError>({
url: '/cart/add/{product_id}',
...options
});
};
/**
* Remove From Cart
*/
export const cartRemoveFromCart = <ThrowOnError extends boolean = false>(options: Options<CartRemoveFromCartData, ThrowOnError>) => {
return (options.client ?? _heyApiClient).delete<unknown, CartRemoveFromCartError, ThrowOnError>({
url: '/cart/remove/{product_id}',
...options
});
};
/**
* Update Count In Cart
*/
export const cartUpdateCountInCart = <ThrowOnError extends boolean = false>(options: Options<CartUpdateCountInCartData, ThrowOnError>) => {
return (options.client ?? _heyApiClient).put<unknown, CartUpdateCountInCartError, ThrowOnError>({
url: '/cart/update/{product_id}',
...options
});
};
/**
* Purchase
*/
export const cartPurchase = <ThrowOnError extends boolean = false>(options?: Options<CartPurchaseData, ThrowOnError>) => {
return (options?.client ?? _heyApiClient).get<unknown, unknown, ThrowOnError>({
url: '/cart/purchase',
...options
});
};
/**
* Delete user
*/
export const userDeleteUser = <ThrowOnError extends boolean = false>(options?: Options<UserDeleteUserData, ThrowOnError>) => {
return (options?.client ?? _heyApiClient).delete<unknown, unknown, ThrowOnError>({
url: '/user/delete',
...options
});
};
/**
* User logout
*/
export const userLogout = <ThrowOnError extends boolean = false>(options?: Options<UserLogoutData, ThrowOnError>) => {
return (options?.client ?? _heyApiClient).delete<unknown, unknown, ThrowOnError>({
url: '/user/logout',
...options
});
};
/**
* Register new user
*/
export const userRegister = <ThrowOnError extends boolean = false>(options: Options<UserRegisterData, ThrowOnError>) => {
return (options.client ?? _heyApiClient).post<unknown, UserRegisterError, ThrowOnError>({
url: '/user/register',
...options,
headers: {
'Content-Type': 'application/json',
...options?.headers
}
});
};
/**
* Update user details
*/
export const userUpdateUser = <ThrowOnError extends boolean = false>(options: Options<UserUpdateUserData, ThrowOnError>) => {
return (options.client ?? _heyApiClient).put<unknown, UserUpdateUserError, ThrowOnError>({
url: '/user/update',
...options,
headers: {
'Content-Type': 'application/json',
...options?.headers
}
});
};
/**
* Health Check
*/
export const utilsHealthCheck = <ThrowOnError extends boolean = false>(options?: Options<UtilsHealthCheckData, ThrowOnError>) => {
return (options?.client ?? _heyApiClient).get<UtilsHealthCheckResponse, unknown, ThrowOnError>({
url: '/utils/health-check/',
...options
});
};
/**
* Test Db
*/
export const utilsTestDb = <ThrowOnError extends boolean = false>(options?: Options<UtilsTestDbData, ThrowOnError>) => {
return (options?.client ?? _heyApiClient).get<UtilsTestDbResponse, unknown, ThrowOnError>({
url: '/utils/test-db/',
...options
});
};
/**
* Login Access Token
* OAuth2 compatible token login, get an access token for future requests
*/
export const loginLoginAccessToken = <ThrowOnError extends boolean = false>(options: Options<LoginLoginAccessTokenData, ThrowOnError>) => {
return (options.client ?? _heyApiClient).post<LoginLoginAccessTokenResponse, LoginLoginAccessTokenError, ThrowOnError>({
...urlSearchParamsBodySerializer,
url: '/login/access-token',
...options,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
...options?.headers
}
});
};
/**
* Login Access Token
* OAuth2 compatible token login, get an access token for future requests
*/
export const shopLoginAccessToken = <ThrowOnError extends boolean = false>(options: Options<ShopLoginAccessTokenData, ThrowOnError>) => {
return (options.client ?? _heyApiClient).post<ShopLoginAccessTokenResponse, ShopLoginAccessTokenError, ThrowOnError>({
...urlSearchParamsBodySerializer,
url: '/shop/{shop_uuid}/login/access-token',
...options,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
...options?.headers
}
});
};
/**
* Delete user
*/
export const shopDeleteUser = <ThrowOnError extends boolean = false>(options: Options<ShopDeleteUserData, ThrowOnError>) => {
return (options.client ?? _heyApiClient).delete<unknown, ShopDeleteUserError, ThrowOnError>({
url: '/shop/{shop_uuid}/user/delete',
...options
});
};
/**
* User logout
*/
export const shopLogout = <ThrowOnError extends boolean = false>(options?: Options<ShopLogoutData, ThrowOnError>) => {
return (options?.client ?? _heyApiClient).delete<unknown, unknown, ThrowOnError>({
url: '/shop/{shop_uuid}/user/logout',
...options
});
};
/**
* Register new user
*/
export const shopRegister = <ThrowOnError extends boolean = false>(options: Options<ShopRegisterData, ThrowOnError>) => {
return (options.client ?? _heyApiClient).post<unknown, ShopRegisterError, ThrowOnError>({
url: '/shop/{shop_uuid}/user/register',
...options,
headers: {
'Content-Type': 'application/json',
...options?.headers
}
});
};
/**
* Update user details
*/
export const shopUpdateUser = <ThrowOnError extends boolean = false>(options: Options<ShopUpdateUserData, ThrowOnError>) => {
return (options.client ?? _heyApiClient).put<unknown, ShopUpdateUserError, ThrowOnError>({
url: '/shop/{shop_uuid}/user/update',
...options,
headers: {
'Content-Type': 'application/json',
...options?.headers
}
});
};

View File

@ -1,408 +0,0 @@
// This file is auto-generated by @hey-api/openapi-ts
export type BodyLoginLoginAccessToken = {
grant_type?: string | null;
username: string;
password: string;
scope?: string;
client_id?: string | null;
client_secret?: string | null;
};
export type BodyShopLoginAccessToken = {
grant_type?: string | null;
username: string;
password: string;
scope?: string;
client_id?: string | null;
client_secret?: string | null;
};
export type HttpValidationError = {
detail?: Array<ValidationError>;
};
export type Token = {
access_token: string;
token_type?: string;
};
export type UserRegister = {
username: string;
email: string;
phone_number: string;
/**
* Password must be at least 8 and at most 128 characters long, contain a lower case, upper case letter, a number and a special character (#?!@$ %^&*-)
*/
password: string;
};
export type ValidationError = {
loc: Array<string | number>;
msg: string;
type: string;
};
export type CartShowCartData = {
body?: never;
path?: never;
query?: never;
url: '/cart/';
};
export type CartShowCartResponses = {
/**
* Successful Response
*/
200: unknown;
};
export type CartAddToCartData = {
body?: never;
path: {
product_id: number;
};
query?: {
/**
* Count must be greater than or equal to 1
*/
count?: number;
};
url: '/cart/add/{product_id}';
};
export type CartAddToCartErrors = {
/**
* Validation Error
*/
422: HttpValidationError;
};
export type CartAddToCartError = CartAddToCartErrors[keyof CartAddToCartErrors];
export type CartAddToCartResponses = {
/**
* Successful Response
*/
200: unknown;
};
export type CartRemoveFromCartData = {
body?: never;
path: {
product_id: number;
};
query?: never;
url: '/cart/remove/{product_id}';
};
export type CartRemoveFromCartErrors = {
/**
* Validation Error
*/
422: HttpValidationError;
};
export type CartRemoveFromCartError = CartRemoveFromCartErrors[keyof CartRemoveFromCartErrors];
export type CartRemoveFromCartResponses = {
/**
* Successful Response
*/
200: unknown;
};
export type CartUpdateCountInCartData = {
body?: never;
path: {
product_id: number;
};
query: {
/**
* Count must be provided
*/
count: number;
};
url: '/cart/update/{product_id}';
};
export type CartUpdateCountInCartErrors = {
/**
* Validation Error
*/
422: HttpValidationError;
};
export type CartUpdateCountInCartError = CartUpdateCountInCartErrors[keyof CartUpdateCountInCartErrors];
export type CartUpdateCountInCartResponses = {
/**
* Successful Response
*/
200: unknown;
};
export type CartPurchaseData = {
body?: never;
path?: never;
query?: never;
url: '/cart/purchase';
};
export type CartPurchaseResponses = {
/**
* Successful Response
*/
200: unknown;
};
export type UserDeleteUserData = {
body?: never;
path?: never;
query?: never;
url: '/user/delete';
};
export type UserDeleteUserResponses = {
/**
* Successful Response
*/
200: unknown;
};
export type UserLogoutData = {
body?: never;
path?: never;
query?: never;
url: '/user/logout';
};
export type UserLogoutResponses = {
/**
* Successful Response
*/
200: unknown;
};
export type UserRegisterData = {
body: UserRegister;
path?: never;
query?: never;
url: '/user/register';
};
export type UserRegisterErrors = {
/**
* Validation Error
*/
422: HttpValidationError;
};
export type UserRegisterError = UserRegisterErrors[keyof UserRegisterErrors];
export type UserRegisterResponses = {
/**
* Successful Response
*/
200: unknown;
};
export type UserUpdateUserData = {
body: {
[key: string]: unknown;
};
path?: never;
query?: never;
url: '/user/update';
};
export type UserUpdateUserErrors = {
/**
* Validation Error
*/
422: HttpValidationError;
};
export type UserUpdateUserError = UserUpdateUserErrors[keyof UserUpdateUserErrors];
export type UserUpdateUserResponses = {
/**
* Successful Response
*/
200: unknown;
};
export type UtilsHealthCheckData = {
body?: never;
path?: never;
query?: never;
url: '/utils/health-check/';
};
export type UtilsHealthCheckResponses = {
/**
* Successful Response
*/
200: boolean;
};
export type UtilsHealthCheckResponse = UtilsHealthCheckResponses[keyof UtilsHealthCheckResponses];
export type UtilsTestDbData = {
body?: never;
path?: never;
query?: never;
url: '/utils/test-db/';
};
export type UtilsTestDbResponses = {
/**
* Successful Response
*/
200: boolean;
};
export type UtilsTestDbResponse = UtilsTestDbResponses[keyof UtilsTestDbResponses];
export type LoginLoginAccessTokenData = {
body: BodyLoginLoginAccessToken;
path?: never;
query?: never;
url: '/login/access-token';
};
export type LoginLoginAccessTokenErrors = {
/**
* Validation Error
*/
422: HttpValidationError;
};
export type LoginLoginAccessTokenError = LoginLoginAccessTokenErrors[keyof LoginLoginAccessTokenErrors];
export type LoginLoginAccessTokenResponses = {
/**
* Successful Response
*/
200: Token;
};
export type LoginLoginAccessTokenResponse = LoginLoginAccessTokenResponses[keyof LoginLoginAccessTokenResponses];
export type ShopLoginAccessTokenData = {
body: BodyShopLoginAccessToken;
path?: never;
query?: never;
url: '/shop/{shop_uuid}/login/access-token';
};
export type ShopLoginAccessTokenErrors = {
/**
* Validation Error
*/
422: HttpValidationError;
};
export type ShopLoginAccessTokenError = ShopLoginAccessTokenErrors[keyof ShopLoginAccessTokenErrors];
export type ShopLoginAccessTokenResponses = {
/**
* Successful Response
*/
200: Token;
};
export type ShopLoginAccessTokenResponse = ShopLoginAccessTokenResponses[keyof ShopLoginAccessTokenResponses];
export type ShopDeleteUserData = {
body?: never;
path: {
shop_uuid: unknown;
};
query?: never;
url: '/shop/{shop_uuid}/user/delete';
};
export type ShopDeleteUserErrors = {
/**
* Validation Error
*/
422: HttpValidationError;
};
export type ShopDeleteUserError = ShopDeleteUserErrors[keyof ShopDeleteUserErrors];
export type ShopDeleteUserResponses = {
/**
* Successful Response
*/
200: unknown;
};
export type ShopLogoutData = {
body?: never;
path?: never;
query?: never;
url: '/shop/{shop_uuid}/user/logout';
};
export type ShopLogoutResponses = {
/**
* Successful Response
*/
200: unknown;
};
export type ShopRegisterData = {
body: UserRegister;
path: {
shop_uuid: unknown;
};
query?: never;
url: '/shop/{shop_uuid}/user/register';
};
export type ShopRegisterErrors = {
/**
* Validation Error
*/
422: HttpValidationError;
};
export type ShopRegisterError = ShopRegisterErrors[keyof ShopRegisterErrors];
export type ShopRegisterResponses = {
/**
* Successful Response
*/
200: unknown;
};
export type ShopUpdateUserData = {
body: {
[key: string]: unknown;
};
path?: never;
query?: never;
url: '/shop/{shop_uuid}/user/update';
};
export type ShopUpdateUserErrors = {
/**
* Validation Error
*/
422: HttpValidationError;
};
export type ShopUpdateUserError = ShopUpdateUserErrors[keyof ShopUpdateUserErrors];
export type ShopUpdateUserResponses = {
/**
* Successful Response
*/
200: unknown;
};
export type ClientOptions = {
baseURL: 'http://localhost:8000' | (string & {});
};

View File

@ -56,7 +56,7 @@ const MainNavbar = () => {
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem> <DropdownMenuItem>
<Button variant="secondary" className="w-full text-sm"> <Button variant="secondary" className="w-full text-sm">
Login Sign in
</Button> </Button>
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem> <DropdownMenuItem>

View File

@ -2,15 +2,7 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"
import { useNavigate } from "@tanstack/react-router" import { useNavigate } from "@tanstack/react-router"
import { useState } from "react" import { useState } from "react"
import { import { handleServerError } from "@/utils/handle-server-error"
type BodyLoginLoginAccessToken as AccessToken,
type ApiError,
LoginService,
type UserPublic,
type UserRegister,
UsersService,
} from "@/client"
import { handleError } from "@/utils"
const isLoggedIn = () => { const isLoggedIn = () => {
return localStorage.getItem("access_token") !== null return localStorage.getItem("access_token") !== null
@ -31,10 +23,10 @@ const useAuth = () => {
UsersService.registerUser({ requestBody: data }), UsersService.registerUser({ requestBody: data }),
onSuccess: () => { onSuccess: () => {
navigate({ to: "/login" }) navigate({ to: "/sign-in" })
}, },
onError: (err: ApiError) => { onError: (err: ApiError) => {
handleError(err) handleServerError(err)
}, },
onSettled: () => { onSettled: () => {
queryClient.invalidateQueries({ queryKey: ["users"] }) queryClient.invalidateQueries({ queryKey: ["users"] })
@ -60,7 +52,7 @@ const useAuth = () => {
const logout = () => { const logout = () => {
localStorage.removeItem("access_token") localStorage.removeItem("access_token")
navigate({ to: "/login" }) navigate({ to: "/sign-in" })
} }
return { return {