diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml
new file mode 100644
index 0000000..d4a6e52
--- /dev/null
+++ b/.idea/dataSources.xml
@@ -0,0 +1,12 @@
+
+
+
+
+ postgresql
+ true
+ org.postgresql.Driver
+ jdbc:postgresql://localhost:5432/postgres
+ $ProjectFileDir$
+
+
+
\ No newline at end of file
diff --git a/.idea/data_source_mapping.xml b/.idea/data_source_mapping.xml
new file mode 100644
index 0000000..24daca9
--- /dev/null
+++ b/.idea/data_source_mapping.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/fastapi-demo-products.iml b/.idea/fastapi-demo-products.iml
new file mode 100644
index 0000000..a6b95ba
--- /dev/null
+++ b/.idea/fastapi-demo-products.iml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..db14680
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..a7351ee
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/watcherTasks.xml b/.idea/watcherTasks.xml
new file mode 100644
index 0000000..5d8e01b
--- /dev/null
+++ b/.idea/watcherTasks.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/alembic.ini b/alembic.ini
new file mode 100644
index 0000000..6bfda86
--- /dev/null
+++ b/alembic.ini
@@ -0,0 +1,147 @@
+# A generic, single database configuration.
+
+[alembic]
+# path to migration scripts.
+# this is typically a path given in POSIX (e.g. forward slashes)
+# format, relative to the token %(here)s which refers to the location of this
+# ini file
+script_location = %(here)s/alembic
+
+# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s
+# Uncomment the line below if you want the files to be prepended with date and time
+# see https://alembic.sqlalchemy.org/en/latest/tutorial.html#editing-the-ini-file
+# for all available tokens
+# file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s
+
+# sys.path path, will be prepended to sys.path if present.
+# defaults to the current working directory. for multiple paths, the path separator
+# is defined by "path_separator" below.
+prepend_sys_path = .
+
+
+# timezone to use when rendering the date within the migration file
+# as well as the filename.
+# If specified, requires the tzdata library which can be installed by adding
+# `alembic[tz]` to the pip requirements.
+# string value is passed to ZoneInfo()
+# leave blank for localtime
+# timezone =
+
+# max length of characters to apply to the "slug" field
+# truncate_slug_length = 40
+
+# set to 'true' to run the environment during
+# the 'revision' command, regardless of autogenerate
+# revision_environment = false
+
+# set to 'true' to allow .pyc and .pyo files without
+# a source .py file to be detected as revisions in the
+# versions/ directory
+# sourceless = false
+
+# version location specification; This defaults
+# to /versions. When using multiple version
+# directories, initial revisions must be specified with --version-path.
+# The path separator used here should be the separator specified by "path_separator"
+# below.
+# version_locations = %(here)s/bar:%(here)s/bat:%(here)s/alembic/versions
+
+# path_separator; This indicates what character is used to split lists of file
+# paths, including version_locations and prepend_sys_path within configparser
+# files such as alembic.ini.
+# The default rendered in new alembic.ini files is "os", which uses os.pathsep
+# to provide os-dependent path splitting.
+#
+# Note that in order to support legacy alembic.ini files, this default does NOT
+# take place if path_separator is not present in alembic.ini. If this
+# option is omitted entirely, fallback logic is as follows:
+#
+# 1. Parsing of the version_locations option falls back to using the legacy
+# "version_path_separator" key, which if absent then falls back to the legacy
+# behavior of splitting on spaces and/or commas.
+# 2. Parsing of the prepend_sys_path option falls back to the legacy
+# behavior of splitting on spaces, commas, or colons.
+#
+# Valid values for path_separator are:
+#
+# path_separator = :
+# path_separator = ;
+# path_separator = space
+# path_separator = newline
+#
+# Use os.pathsep. Default configuration used for new projects.
+path_separator = os
+
+# set to 'true' to search source files recursively
+# in each "version_locations" directory
+# new in Alembic version 1.10
+# recursive_version_locations = false
+
+# the output encoding used when revision files
+# are written from script.py.mako
+# output_encoding = utf-8
+
+# database URL. This is consumed by the user-maintained env.py script only.
+# other means of configuring database URLs may be customized within the env.py
+# file.
+sqlalchemy.url = postgresql://postgres:123@localhost:5432/inventory
+
+
+[post_write_hooks]
+# post_write_hooks defines scripts or Python functions that are run
+# on newly generated revision scripts. See the documentation for further
+# detail and examples
+
+# format using "black" - use the console_scripts runner, against the "black" entrypoint
+# hooks = black
+# black.type = console_scripts
+# black.entrypoint = black
+# black.options = -l 79 REVISION_SCRIPT_FILENAME
+
+# lint with attempts to fix using "ruff" - use the module runner, against the "ruff" module
+# hooks = ruff
+# ruff.type = module
+# ruff.module = ruff
+# ruff.options = check --fix REVISION_SCRIPT_FILENAME
+
+# Alternatively, use the exec runner to execute a binary found on your PATH
+# hooks = ruff
+# ruff.type = exec
+# ruff.executable = ruff
+# ruff.options = check --fix REVISION_SCRIPT_FILENAME
+
+# Logging configuration. This is also consumed by the user-maintained
+# env.py script only.
+[loggers]
+keys = root,sqlalchemy,alembic
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = WARNING
+handlers = console
+qualname =
+
+[logger_sqlalchemy]
+level = WARNING
+handlers =
+qualname = sqlalchemy.engine
+
+[logger_alembic]
+level = INFO
+handlers =
+qualname = alembic
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(levelname)-5.5s [%(name)s] %(message)s
+datefmt = %H:%M:%S
diff --git a/alembic/README b/alembic/README
new file mode 100644
index 0000000..98e4f9c
--- /dev/null
+++ b/alembic/README
@@ -0,0 +1 @@
+Generic single-database configuration.
\ No newline at end of file
diff --git a/alembic/env.py b/alembic/env.py
new file mode 100644
index 0000000..635fec5
--- /dev/null
+++ b/alembic/env.py
@@ -0,0 +1,87 @@
+from logging.config import fileConfig
+
+from sqlalchemy import engine_from_config
+from sqlalchemy import pool
+
+from alembic import context
+from logging.config import fileConfig
+from sqlalchemy import engine_from_config, pool
+from alembic import context
+import sys
+import os
+sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
+
+# this is the Alembic Config object, which provides
+# access to the values within the .ini file in use.
+config = context.config
+
+# Interpret the config file for Python logging.
+# This line sets up loggers basically.
+if config.config_file_name is not None:
+ fileConfig(config.config_file_name)
+
+# add your model's MetaData object here
+# for 'autogenerate' support
+# from myapp import mymodel
+# target_metadata = mymodel.Base.metadata
+from app.database import Base
+from app.models import user, company, product
+target_metadata = Base.metadata
+
+
+# other values from the config, defined by the needs of env.py,
+# can be acquired:
+# my_important_option = config.get_main_option("my_important_option")
+# ... etc.
+
+
+def run_migrations_offline() -> None:
+ """Run migrations in 'offline' mode.
+
+ This configures the context with just a URL
+ and not an Engine, though an Engine is acceptable
+ here as well. By skipping the Engine creation
+ we don't even need a DBAPI to be available.
+
+ Calls to context.execute() here emit the given string to the
+ script output.
+
+ """
+ url = config.get_main_option("sqlalchemy.url")
+ context.configure(
+ url=url,
+ target_metadata=target_metadata,
+ literal_binds=True,
+ dialect_opts={"paramstyle": "named"},
+ )
+
+ with context.begin_transaction():
+ context.run_migrations()
+
+
+def run_migrations_online() -> None:
+ """Run migrations in 'online' mode.
+
+ In this scenario we need to create an Engine
+ and associate a connection with the context.
+
+ """
+ connectable = engine_from_config(
+ config.get_section(config.config_ini_section, {}),
+ prefix="sqlalchemy.",
+ poolclass=pool.NullPool,
+ )
+
+ with connectable.connect() as connection:
+ context.configure(
+ connection=connection, target_metadata=target_metadata
+ )
+
+ with context.begin_transaction():
+ context.run_migrations()
+
+
+if context.is_offline_mode():
+ run_migrations_offline()
+else:
+ run_migrations_online()
diff --git a/alembic/script.py.mako b/alembic/script.py.mako
new file mode 100644
index 0000000..1101630
--- /dev/null
+++ b/alembic/script.py.mako
@@ -0,0 +1,28 @@
+"""${message}
+
+Revision ID: ${up_revision}
+Revises: ${down_revision | comma,n}
+Create Date: ${create_date}
+
+"""
+from typing import Sequence, Union
+
+from alembic import op
+import sqlalchemy as sa
+${imports if imports else ""}
+
+# revision identifiers, used by Alembic.
+revision: str = ${repr(up_revision)}
+down_revision: Union[str, Sequence[str], None] = ${repr(down_revision)}
+branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)}
+depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)}
+
+
+def upgrade() -> None:
+ """Upgrade schema."""
+ ${upgrades if upgrades else "pass"}
+
+
+def downgrade() -> None:
+ """Downgrade schema."""
+ ${downgrades if downgrades else "pass"}
diff --git a/alembic/versions/25d8f59a1dde_initial.py b/alembic/versions/25d8f59a1dde_initial.py
new file mode 100644
index 0000000..0e3973d
--- /dev/null
+++ b/alembic/versions/25d8f59a1dde_initial.py
@@ -0,0 +1,32 @@
+"""initial
+
+Revision ID: 25d8f59a1dde
+Revises:
+Create Date: 2025-10-13 14:14:29.332627
+
+"""
+from typing import Sequence, Union
+
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision: str = '25d8f59a1dde'
+down_revision: Union[str, Sequence[str], None] = None
+branch_labels: Union[str, Sequence[str], None] = None
+depends_on: Union[str, Sequence[str], None] = None
+
+
+def upgrade() -> None:
+ """Upgrade schema."""
+ # ### commands auto generated by Alembic - please adjust! ###
+ pass
+ # ### end Alembic commands ###
+
+
+def downgrade() -> None:
+ """Downgrade schema."""
+ # ### commands auto generated by Alembic - please adjust! ###
+ pass
+ # ### end Alembic commands ###
diff --git a/alembic/versions/b6ea24863180_renamed_type_to_company_type_in_company_.py b/alembic/versions/b6ea24863180_renamed_type_to_company_type_in_company_.py
new file mode 100644
index 0000000..655051a
--- /dev/null
+++ b/alembic/versions/b6ea24863180_renamed_type_to_company_type_in_company_.py
@@ -0,0 +1,34 @@
+"""renamed type to company_type in Company model
+
+Revision ID: b6ea24863180
+Revises: e1389d54a4b4
+Create Date: 2025-10-15 16:56:05.452033
+
+"""
+from typing import Sequence, Union
+
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision: str = 'b6ea24863180'
+down_revision: Union[str, Sequence[str], None] = 'e1389d54a4b4'
+branch_labels: Union[str, Sequence[str], None] = None
+depends_on: Union[str, Sequence[str], None] = None
+
+
+def upgrade() -> None:
+ """Upgrade schema."""
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.add_column('company', sa.Column('company_type', sa.String(), nullable=True))
+ op.drop_column('company', 'type')
+ # ### end Alembic commands ###
+
+
+def downgrade() -> None:
+ """Downgrade schema."""
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.add_column('company', sa.Column('type', sa.VARCHAR(), autoincrement=False, nullable=True))
+ op.drop_column('company', 'company_type')
+ # ### end Alembic commands ###
diff --git a/alembic/versions/e1389d54a4b4_add_type_column_to_company.py b/alembic/versions/e1389d54a4b4_add_type_column_to_company.py
new file mode 100644
index 0000000..7475f33
--- /dev/null
+++ b/alembic/versions/e1389d54a4b4_add_type_column_to_company.py
@@ -0,0 +1,32 @@
+"""add type column to company
+
+Revision ID: e1389d54a4b4
+Revises: 25d8f59a1dde
+Create Date: 2025-10-13 14:20:56.229293
+
+"""
+from typing import Sequence, Union
+
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision: str = 'e1389d54a4b4'
+down_revision: Union[str, Sequence[str], None] = '25d8f59a1dde'
+branch_labels: Union[str, Sequence[str], None] = None
+depends_on: Union[str, Sequence[str], None] = None
+
+
+def upgrade() -> None:
+ """Upgrade schema."""
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.add_column('company', sa.Column('type', sa.String(), nullable=True))
+ # ### end Alembic commands ###
+
+
+def downgrade() -> None:
+ """Downgrade schema."""
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.drop_column('company', 'type')
+ # ### end Alembic commands ###
diff --git a/app/auth.py b/app/auth.py
index 0449346..d48bd3c 100644
--- a/app/auth.py
+++ b/app/auth.py
@@ -11,7 +11,7 @@
SECRET_KEY = "af3287c8391bb9f4f7a72feb3b85f72e1d5bd07cbf4fa4ad9497c78412923312"
ALGORITHM = "HS256"
-ACCESS_TOKEN_EXPIRE_MINUTES = 30
+ACCESS_TOKEN_EXPIRE_MINUTES = 7 * 24 * 60
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
bearer_scheme = HTTPBearer()
diff --git a/app/controllers/auth_controller.py b/app/controllers/auth_controller.py
index d214a06..97d4af1 100644
--- a/app/controllers/auth_controller.py
+++ b/app/controllers/auth_controller.py
@@ -3,16 +3,17 @@
from app.schemas.user import UserCreate, UserResponse
from app.services.user_service import UserService
from app.database import get_db
-from app.auth import create_access_token, verify_password
-from app.models.user import User
+from app.auth import create_access_token, verify_password, get_password_hash, get_current_user
+from app.models.user import User
router = APIRouter()
@router.post("/register", response_model=UserResponse)
def register(user: UserCreate, db: Session = Depends(get_db)):
service = UserService(db)
+ hashed_pw= get_password_hash(user.password)
try:
- return service.create_user(user)
+ return service.create_user(user.username, hashed_pw)
except ValueError as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
@@ -20,7 +21,7 @@ def register(user: UserCreate, db: Session = Depends(get_db)):
@router.post("/token")
def login(user: UserCreate, db: Session = Depends(get_db)):
- # ✅ Query using database model
+ # Query using database model
db_user = db.query(User).filter(User.username == user.username).first()
if not db_user or not verify_password(user.password, db_user.password):
@@ -28,4 +29,16 @@ def login(user: UserCreate, db: Session = Depends(get_db)):
status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid credentials")
token = create_access_token(db_user.id)
- return {"access_token": token, "token_type": "bearer"}
+ return {"access_token": token}
+
+@router.get("/me", response_model=UserResponse)
+def me(
+ db: Session = Depends(get_db),
+ current_user=Depends(get_current_user)):
+ service = UserService(db)
+ return service.get_user(current_user.id)
+
+@router.delete("/delete",dependencies=[Depends(get_current_user)])
+def delete( db: Session = Depends(get_db), current_user=Depends(get_current_user)):
+ service = UserService(db)
+ return service.delete_user(current_user.id)
diff --git a/app/controllers/company_controller.py b/app/controllers/company_controller.py
index 76d647f..3dafc3f 100644
--- a/app/controllers/company_controller.py
+++ b/app/controllers/company_controller.py
@@ -15,7 +15,7 @@ def create_company(
current_user=Depends(get_current_user)
):
service = CompanyService(db)
- return service.create_company(current_user.id, company)
+ return service.create_company(current_user.id, company.name,company.company_type, company.location)
@router.get("/me", response_model=CompanyResponse)
@@ -24,7 +24,7 @@ def get_my_company(
current_user=Depends(get_current_user)
):
service = CompanyService(db)
- return service.get_my_company(current_user.id)
+ return service.get_company(current_user.id)
@router.put("/me", response_model=CompanyResponse)
@@ -34,7 +34,7 @@ def edit_my_company(
current_user=Depends(get_current_user)
):
service = CompanyService(db)
- return service.edit_company(current_user.id, company)
+ return service.edit_company(current_user.id, company.name, company.company_type, company.location)
@router.delete("/me", dependencies=[Depends(get_current_user)])
diff --git a/app/controllers/product_controller.py b/app/controllers/product_controller.py
index 3d06d85..a8d092a 100644
--- a/app/controllers/product_controller.py
+++ b/app/controllers/product_controller.py
@@ -18,12 +18,12 @@ def create_product(
):
company_service = CompanyService(db)
product_service = ProductService(db)
- company = company_service.get_my_company(current_user.id)
+ company = company_service.get_company(current_user.id)
if not company:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="no company found")
- return product_service.create_product(company.id, product)
+ return product_service.create_product(company.id, product.name,product.price,product.description)
@router.get("/", response_model=list[ProductResponse])
@@ -52,12 +52,13 @@ def update_product_by_id(
db: Session = Depends(get_db),
current_user=Depends(get_current_user)):
product_service = ProductService(db)
- return product_service.update_product(product_id,product)
+ return product_service.update_product(product_id,product.name,product.price,product.description)
@router.delete("/{product_id}", response_model=ProductResponse)
def delete_product_by_id(
product_id: int,
db: Session = Depends(get_db),
- current_user=Depends(get_current_user)):
+current_user=Depends(get_current_user)
+ ):
product_service = ProductService(db)
return product_service.delete_product(product_id)
\ No newline at end of file
diff --git a/app/controllers/user_controller.py b/app/controllers/user_controller.py
deleted file mode 100644
index e69de29..0000000
diff --git a/app/main.py b/app/main.py
index f59d8a9..d45247e 100644
--- a/app/main.py
+++ b/app/main.py
@@ -1,9 +1,7 @@
from fastapi import FastAPI
-from app.database import Base, engine
from app.controllers import auth_controller, company_controller, product_controller
-Base.metadata.create_all(bind=engine)
version = "v1"
app = FastAPI(title="Company & Product API",
description="in which user create their company",
@@ -16,37 +14,3 @@
prefix=f"/api/{version}/company", tags=["Company"])
app.include_router(product_controller.router,
prefix=f"/api/{version}/product", tags=["Product"])
-
-
-@app.get("/")
-def root():
- return {"message": "Welcome to Company API!"}
-
-
-# from fastapi import FastAPI
-# from fastapi.middleware.cors import CORSMiddleware
-# import db.database_model as database_model
-# from app.database import engine
-# from routes import file_routes, post_routes, products_routes, user_route
-
-# version = "v1"
-# app = FastAPI(title="Fastapi ",
-# description="this is learning project.",
-# version=version,)
-
-
-# database_model.Base.metadata.create_all(bind=engine)
-
-
-# app.include_router(products_routes.router,
-# prefix=f"/api/{version}/products", tags=['Products'])
-# app.include_router(file_routes.router,
-# prefix=f"/api/{version}/files", tags=['Files'])
-# app.include_router(user_route.router,
-# prefix=f"/api/{version}/users", tags=['Users'])
-# app.include_router(post_routes.router,
-# prefix=f"/api/{version}/posts", tags=["Posts"])
-
-# @app.get("/")
-# def greet():
-# return {"message": "Hello, World!"}
diff --git a/app/models/company.py b/app/models/company.py
index 555bc5e..2c4b50a 100644
--- a/app/models/company.py
+++ b/app/models/company.py
@@ -4,12 +4,14 @@
class Company(Base):
- __tablename__ = "companies"
+ __tablename__ = "company"
id =Column(Integer, primary_key=True, index=True)
name= Column(String)
location = Column(String)
- user_id = Column(Integer, ForeignKey("users.id"))
+ company_type = Column(String, nullable=True)
+ user_id = Column(Integer, ForeignKey("user.id"))
+
user= relationship("User", back_populates="company")
products= relationship("Product", back_populates="company")
\ No newline at end of file
diff --git a/app/models/model.py b/app/models/model.py
deleted file mode 100644
index 1643234..0000000
--- a/app/models/model.py
+++ /dev/null
@@ -1,34 +0,0 @@
-from pydantic import BaseModel
-from typing import Optional
-
-class Product(BaseModel):
- id: int
- name: str
- description: str
- price: float
- quantity: int
-
- class Config:
- from_attributes = True
-
-
-class CreateUser(BaseModel):
- username: str
- password: str
-
-
-class User(BaseModel):
- id: int
- username: str
- password: str
-
-
-class Post(BaseModel):
- post_id: Optional [int]
- title: str
- description: str
-
-
-class Token(BaseModel):
- access_token: str
- token_type: str
diff --git a/app/models/product.py b/app/models/product.py
index 29bce74..b610eb1 100644
--- a/app/models/product.py
+++ b/app/models/product.py
@@ -4,12 +4,12 @@
class Product(Base):
- __tablename__ = "products"
+ __tablename__ = "product"
id = Column(Integer, primary_key=True, index=True)
name = Column(String)
price = Column(Float)
description = Column(String,nullable=True)
- company_id = Column(Integer, ForeignKey("companies.id"))
+ company_id = Column(Integer, ForeignKey("company.id"))
- company = relationship("Company", back_populates="products")
+ company = relationship("Company", back_populates="products")
\ No newline at end of file
diff --git a/app/models/user.py b/app/models/user.py
index 4b4cdfb..0033b39 100644
--- a/app/models/user.py
+++ b/app/models/user.py
@@ -4,10 +4,10 @@
class User(Base):
- __tablename__ = "users"
+ __tablename__ = "user"
id = Column(Integer, primary_key=True, index=True)
username = Column(String, unique=True)
password = Column(String)
- company= relationship("Company",back_populates="user", uselist=False)
+ company= relationship("Company",back_populates="user", uselist=False)
\ No newline at end of file
diff --git a/app/repositories/company_repository.py b/app/repositories/company_repository.py
new file mode 100644
index 0000000..6ba133a
--- /dev/null
+++ b/app/repositories/company_repository.py
@@ -0,0 +1,62 @@
+from fastapi import HTTPException,status
+from sqlalchemy.orm import Session
+from app.models.company import Company
+
+
+class CompanyRepository:
+ def __init__(self ,db: Session):
+ self.db = db
+
+
+
+ def create_my_company(self, user_id: int, name: str, company_type: str, location: str):
+ existed=self.db.query(Company).filter(Company.user_id == user_id).first()
+ company = Company(user_id=user_id, name=name, company_type=company_type, location=location)
+ if existed:
+ raise HTTPException(status_code=400, detail="Company already exists")
+ if not existed:
+ self.db.add(company)
+ self.db.commit()
+ return company
+
+
+
+
+ def get_my_company(self, user_id: int):
+ company = self.db.query(Company).filter(Company.user_id == user_id).first()
+ if not company:
+ raise HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND, detail="company not found"
+ )
+ return company
+
+
+
+ def edit_my_company(self, user_id: int,name: str, company_type: str, location: str ):
+ existed = self.db.query(Company).filter(Company.user_id == user_id).first()
+ if not existed:
+ raise HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND, detail="company not found"
+ )
+ if existed:
+ self.db.query(Company).filter(Company.user_id == user_id).update(
+ {"name": name, "company_type": company_type, "location": location}
+ )
+ self.db.commit()
+
+ return existed
+
+
+ def delete_my_company(self, user_id: int):
+ existed = self.db.query(Company).filter(Company.user_id == user_id).first()
+ if not existed:
+ raise HTTPException(
+ status_code=status.HTTP_404_NOT_FOUND, detail="company not found"
+ )
+ if existed:
+ self.db.query(Company).filter(Company.user_id == user_id).delete()
+ self.db.commit()
+
+ return existed
+
+
diff --git a/app/repositories/product_repository.py b/app/repositories/product_repository.py
new file mode 100644
index 0000000..93d1bf1
--- /dev/null
+++ b/app/repositories/product_repository.py
@@ -0,0 +1,45 @@
+from fastapi import HTTPException
+from sqlalchemy.orm import Session
+from app.models.product import Product
+
+class ProductRepository:
+ def __init__(self, db: Session):
+ self.db = db
+
+ def create_my_product(self,company_id:int, name: str, price: float, description: str) -> Product:
+ product = Product(company_id,name=name, price=price, description=description)
+ self.db.add(product)
+ self.db.commit()
+
+ return product
+
+ def list_my_product(self):
+ products = self.db.query(Product).all()
+ return products
+
+ def get_product_by_id(self, product_id: int):
+ product= self.db.query(Product).filter(Product.id == product_id).first()
+ if not product:
+ raise HTTPException(status_code=404, detail="Product not found")
+ return product
+
+ def update_my_product(self, product_id: int, name: str, price: float, description: str):
+ product = self.get_product_by_id(product_id)
+ if not product:
+ raise HTTPException(status_code=404, detail="Product not found")
+ if product:
+ self.db.query(Product).filter(Product.id == product_id).update({"name": name, "price": price, "description": description})
+ self.db.commit()
+
+ return product
+
+
+ def delete_my_product(self, product_id: int):
+ product = self.get_product_by_id(product_id)
+ if not product:
+ raise HTTPException(status_code=404, detail="Product not found")
+ if product:
+ self.db.query(Product).filter(Product.id == product_id).delete()
+ self.db.commit()
+
+ return product
\ No newline at end of file
diff --git a/app/repositories/user_repository.py b/app/repositories/user_repository.py
new file mode 100644
index 0000000..0f8ec8c
--- /dev/null
+++ b/app/repositories/user_repository.py
@@ -0,0 +1,32 @@
+from sqlalchemy.orm import Session
+from app.models.user import User
+from fastapi import HTTPException,status
+
+class UserRepository:
+ def __init__(self, db: Session):
+ self.db = db
+
+
+ def get_by_me(self, user_id: int):
+ user = self.db.query(User).filter(User.id == user_id).first()
+ if not user:
+ raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,detail="User not found")
+ return user
+
+ def create_user(self, username: str, hashed_pw: str):
+ user = self.db.query(User).filter(User.username == username).first()
+ if not user:
+ user = User(username=username, password=hashed_pw)
+ self.db.add(user)
+ self.db.commit()
+
+ return user
+
+ def delete_user(self, user_id: int):
+ user = self.db.query(User).filter(User.id == user_id).first()
+ if not user:
+ raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,detail="User not found")
+ if user:
+ self.db.delete(user)
+ self.db.commit()
+ return {"message": "User deleted successfully"}
\ No newline at end of file
diff --git a/app/schemas/company.py b/app/schemas/company.py
index 7fa504e..34a7b77 100644
--- a/app/schemas/company.py
+++ b/app/schemas/company.py
@@ -6,13 +6,14 @@
class CompanyCreate(BaseModel):
name: str
location: str
-
+ company_type: Optional[str] = None
class CompanyResponse(BaseModel):
id: int
name: str
location: str
+ company_type: Optional[str] = None
products: List[ProductResponse] = []
-
- class Config:
- from_attributes = True
+ #
+ # class Config:
+ # from_attributes = True
diff --git a/app/schemas/model.py b/app/schemas/model.py
deleted file mode 100644
index 8ce1d9c..0000000
--- a/app/schemas/model.py
+++ /dev/null
@@ -1,28 +0,0 @@
-from pydantic import BaseModel
-from typing import Optional
-
-class Product(BaseModel):
- id: int
- name: str
- description: str
- price: float
- quantity: int
-
- class Config:
- from_attributes = True
-
-
-
-
-
-
-
-class Post(BaseModel):
- post_id: Optional [int]
- title: str
- description: str
-
-
-class Token(BaseModel):
- access_token: str
- token_type: str
diff --git a/app/schemas/product.py b/app/schemas/product.py
index 77ed9f7..e74b1b1 100644
--- a/app/schemas/product.py
+++ b/app/schemas/product.py
@@ -1,11 +1,11 @@
from typing import Optional
-from pydantic import BaseModel
+from pydantic import BaseModel,Field
class ProductCreate(BaseModel):
- name: str
- price: float
- description: Optional[str] = None
+ name: str = Field(..., min_length=3, max_length=50, description="Product name")
+ price: float = Field(..., gt=0, description="Price must be greater than 0")
+ description: Optional[str] = Field(None, max_length=200)
class ProductResponse(BaseModel):
@@ -13,6 +13,6 @@ class ProductResponse(BaseModel):
name: str
price: float
description: Optional[str] = None
-
- class Config:
- from_attributes = True
+ #
+ # class Config:
+ # from_attributes = True
diff --git a/app/schemas/user.py b/app/schemas/user.py
index 0e5a05c..f72d10b 100644
--- a/app/schemas/user.py
+++ b/app/schemas/user.py
@@ -1,15 +1,19 @@
-from pydantic import BaseModel
+from pydantic import BaseModel,Field
class UserCreate(BaseModel):
- username: str
+ username: str = Field(..., min_length=3, max_length=15, description="User's unique name")
password: str
class UserResponse(BaseModel):
id: int
username: str
- password: str
+
class Config:
from_attributes = True
+
+
+class TokenResponse(BaseModel):
+ access_token: str
\ No newline at end of file
diff --git a/app/services/company_service.py b/app/services/company_service.py
index e0b6155..37e2476 100644
--- a/app/services/company_service.py
+++ b/app/services/company_service.py
@@ -1,60 +1,28 @@
from fastapi import HTTPException, status
from sqlalchemy.orm import Session
-from app.models.company import Company
-from app.schemas.company import CompanyCreate
+from app.repositories.company_repository import CompanyRepository
+
class CompanyService:
def __init__(self, db: Session):
- self.db = db
-
- def create_company(self, user_id: int, company_data: CompanyCreate):
- existing = self.db.query(Company).filter(
- Company.user_id == user_id).first()
- if existing:
- raise HTTPException(
- status_code=status.HTTP_400_BAD_REQUEST, detail="user already has a company")
-
- new_company = Company(
- name=company_data.name,
- location=company_data.location,
- user_id=user_id
- )
- self.db.add(new_company)
- self.db.commit()
- self.db.refresh(new_company)
- return new_company
-
- def get_my_company(self, user_id: int):
- company = self.db.query(Company).filter(
- Company.user_id == user_id).first()
- if not company:
- raise HTTPException(
- status_code=status.HTTP_404_NOT_FOUND, detail="Company not found")
- return company
+ self.repo = CompanyRepository(db)
+
+ def create_company(self, user_id: int,name: str, company_type: str, location: str):
- def edit_company(self, user_id: int, company_data: CompanyCreate):
- company = self.db.query(Company).filter(
- Company.user_id == user_id
- ).first()
- if not company:
- raise HTTPException(
- status_code=status.HTTP_404_NOT_FOUND, detail="company not found"
- )
- company.name = company_data.name
- company.location = company_data.location
- self.db.commit()
- self.db.refresh(company)
+ existed = self.repo.create_my_company(user_id, name, company_type, location)
+ if not existed:
+ raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Company not found")
+ return existed
+
+ def get_company(self, user_id: int):
+ company = self.repo.get_my_company(user_id)
return company
+ def edit_company(self, user_id: int, name: str, company_type: str, location: str):
+ updated =self.repo.edit_my_company(user_id, name, company_type, location)
+ return updated
+
def delete_company(self, user_id: int):
- company = self.db.query(Company).filter(
- Company.user_id == user_id
- ).first()
- if not company:
- raise HTTPException(
- status_code=status.HTTP_404_NOT_FOUND, detail="company not found"
- )
- self.db.delete(company)
- self.db.commit()
- return {"detail": "company deleted"}
+ deleted = self.repo.delete_my_company(user_id)
+ return deleted
diff --git a/app/services/product_service.py b/app/services/product_service.py
index c9db8c9..8ae43c4 100644
--- a/app/services/product_service.py
+++ b/app/services/product_service.py
@@ -1,47 +1,27 @@
-from fastapi import HTTPException
from sqlalchemy.orm import Session
-from app.models.product import Product
-from app.schemas.product import ProductCreate
+from app.repositories.product_repository import ProductRepository
+
class ProductService:
def __init__(self, db: Session):
- self.db = db
-
- def create_product(self, company_id: int, product_data: ProductCreate):
- new_product = Product(
- name=product_data.name,
- price=product_data.price,
- description=product_data.description,
- company_id=company_id
- )
- self.db.add(new_product)
- self.db.commit()
- self.db.refresh(new_product)
- return new_product
+ self.repo = ProductRepository(db)
+
+ def create_product(self, company_id: int,name: str,price: float,description: str):
+ created = self.repo.create_my_product(company_id,name,price,description)
+ return created
def list_products(self):
- products = self.db.query(Product).all()
+ products = self.repo.list_my_product()
return products
def get_product(self, product_id: int):
- product = self.db.query(Product).filter(
- Product.id == product_id).first()
- if not product:
- raise HTTPException(status_code=404, detail="Product not found")
+ product = self.repo.get_product_by_id(product_id)
return product
- def update_product(self, product_id: int, product_data: ProductCreate):
- product = self.get_product(product_id)
- product.name = product_data.name
- product.price = product_data.price
- product.description = product_data.description
- self.db.commit()
- self.db.refresh(product)
+ def update_product(self, product_id: int, name: str,price: float,description: str):
+ product = self.repo.update_my_product(product_id,name,price,description)
return product
def delete_product(self, product_id: int):
- product = self.get_product(product_id)
- self.db.delete(product)
- self.db.commit()
- return {"detail": "Product deleted"}
+ product = self.repo.delete_my_product(product_id)
\ No newline at end of file
diff --git a/app/services/user_service.py b/app/services/user_service.py
index 9f6e614..bc5cdc1 100644
--- a/app/services/user_service.py
+++ b/app/services/user_service.py
@@ -1,33 +1,23 @@
from sqlalchemy.orm import Session
-from app.schemas.user import UserCreate
-from app.models.user import User
-from app.auth import get_password_hash, verify_password, create_access_token
from fastapi import HTTPException, status
+from app.repositories.user_repository import UserRepository
class UserService:
def __init__(self, db: Session):
- self.db = db
+ self.repo = UserRepository(db)
- def create_user(self, user: UserCreate):
- db_user = self.db.query(User).filter(
- User.username == user.username).first()
- if db_user:
- raise ValueError("Username already registered")
- hashed_pw = get_password_hash(user.password)
- new_user = User(username=user.username, password=hashed_pw)
- self.db.add(new_user)
- self.db.commit()
- self.db.refresh(new_user)
- return new_user
+ def create_user(self, username: str, hashed_pw: str):
+ if self.repo.create_user(username, hashed_pw):
+ raise HTTPException(status_code=status.HTTP_201_CREATED, detail="User created successfully")
-# def login_user(self, user: UserCreate):
-# db_user = self.db.query(User).filter(User.username == user.username).first()
-# if not db_user or not verify_password(user.password, db_user.password):
-# raise HTTPException(
-# status_code=status.HTTP_401_UNAUTHORIZED,
-# detail="Invalid credentials"
-# )
+ return self.repo.create_user(username, hashed_pw)
-# token = create_access_token(db_user.id)
-# return {"access_token": token, "token_type": "bearer"}
+ def get_user(self, user_id: int):
+ me = self.repo.get_by_me(user_id)
+ return me
+
+
+ def delete_user(self, user_id: int):
+ me = self.repo.delete_user(user_id)
+ return me