diff --git a/src/entities/README.md b/src/entities/README.md
index 0f7a616..f42ddee 100644
--- a/src/entities/README.md
+++ b/src/entities/README.md
@@ -1,5 +1,5 @@
# ENTITIES
-Entities encapsulate enterprise-wide Critical Business Rules. An entity can be an
+"Entities encapsulate enterprise-wide Critical Business Rules. An entity can be an
object with methods, or it can be a set of data structures and functions. It doesn’t
matter so long as the entities can be used by many different applications in the
enterprise.
@@ -8,4 +8,23 @@ entities are the business objects of the application. They encapsulate the most
and high-level rules. They are the least likely to change when something external
changes. For example, you would not expect these objects to be affected by a change
to page navigation or security. No operational change to any particular application
-should affect the entity layer.
\ No newline at end of file
+should affect the entity layer." -- Robert C. Martin, Clean Architecture
+
+# Aufgabe
+
+### Anforderungen:
+
+#### Attribute:
+- **name**: Der Name des Benutzers.
+- **email**: Die E-Mail-Adresse des Benutzers.
+- **password**: Das Passwort des Benutzers.
+- **id**: Eine eindeutige ID, die den Benutzer identifiziert.
+
+#### Getter und Setter Methoden:
+- Implementiere für jedes Attribut (`name`, `email`, `password`, `id`) Getter- und Setter-Methoden. Diese Methoden sollten es ermöglichen, die Werte der Attribute abzurufen und zu ändern.
+
+#### Datenvalidierung (optional):
+- Validiere die Eingabedaten, z.B. sicherstellen, dass die E-Mail-Adresse ein gültiges Format hat und dass das Passwort eine Mindestlänge aufweist.
+
+#### Konstruktor:
+- Erstelle einen Konstruktor, der die Attribute `name`, `email`, `password` und `id` beim Erstellen eines Benutzerobjekts initialisiert.
diff --git a/src/entities/cart.py b/src/entities/cart.py
deleted file mode 100644
index e02a694..0000000
--- a/src/entities/cart.py
+++ /dev/null
@@ -1,69 +0,0 @@
-#python imports
-from typing import List
-
-#dependency imports
-from .cart_item import CartItem
-from .product import Product
-
-class Cart:
- """
- Represents a shopping cart containing multiple cart items.
- """
-
- def __init__(self):
- """
- Initializes a new shopping cart.
- """
- self.items: List[CartItem] = []
- self.total_price: float = 0.0
-
- def add_item(self, product: Product, quantity: int):
- """
- Adds a product to the cart or updates the quantity if it already exists.
-
- Args:
- product (Product): The product to add to the cart.
- quantity (int): The quantity of the product to add.
- """
- for item in self.items:
- if item.product_id == product.id:
- item.quantity += quantity
- return
- self.items.append(CartItem(product_id=product.id, name=product.name, quantity=quantity, price=product.price))
-
- def remove_item(self, product_id: str):
- """
- Removes a product from the cart by its ID.
-
- Args:
- product_id (str): The unique identifier of the product to remove.
- """
- self.items = [item for item in self.items if item.product_id != product_id]
-
- def calculate_total_price(self) -> float:
- """
- Calculates the total price of all items in the cart.
-
- Returns:
- float: The total price of all items in the cart.
- """
- self.total_price = sum(item.calculate_total_price() for item in self.items)
- return self.total_price
-
- def list_items(self) -> List[str]:
- """
- Lists all items in the cart with their quantities and total prices.
-
- Returns:
- List[str]: A list of strings representing the items in the cart.
- """
- return [f"{item.quantity} x {item.name} - {item.calculate_total_price()} EUR" for item in self.items]
-
- def __repr__(self):
- """
- Returns a string representation of the cart.
-
- Returns:
- str: A string representation of the cart.
- """
- return f"Cart(items={self.items}, total_price={self.total_price})"
\ No newline at end of file
diff --git a/src/entities/cart_item.py b/src/entities/cart_item.py
deleted file mode 100644
index b81faf1..0000000
--- a/src/entities/cart_item.py
+++ /dev/null
@@ -1,50 +0,0 @@
-#python imports
-from typing import List
-
-class CartItem:
- """
- Represents an item in the cart with a product ID, name, quantity, and price.
- """
- def __init__(self, product_id: int, name: str, quantity: int, price: float):
- """
- Initializes a new cart item.
-
- Args:
- product_id (int): The unique identifier for the product.
- name (str): The name of the product.
- quantity (int): The quantity of the product in the cart.
- price (float): The price of the product.
- """
- self.product_id = product_id
- self.name = name
- self.quantity = quantity
- self.price = price
- self.post_init()
-
- def post_init(self):
- """
- Validates the cart item's quantity.
-
- Raises:
- ValueError: If the quantity is less than or equal to 0.
- """
- if self.quantity <= 0:
- raise ValueError("Quantity has to be at least 1")
-
- def calculate_total_price(self) -> float:
- """
- Calculates the total price of the cart item.
-
- Returns:
- float: The total price of the cart item.
- """
- return self.quantity * self.price
-
- def __repr__(self):
- """
- Returns a string representation of the cart item.
-
- Returns:
- str: A string representation of the cart item.
- """
- return f"CartItem(product_id={self.product_id}, name={self.name}, quantity={self.quantity}, price={self.price})"
\ No newline at end of file
diff --git a/src/framework_driver/ui/index.html b/src/framework_driver/ui/index.html
index f467aa7..5bacbc7 100644
--- a/src/framework_driver/ui/index.html
+++ b/src/framework_driver/ui/index.html
@@ -33,7 +33,6 @@
diff --git a/src/framework_driver/ui/src/controller.js b/src/framework_driver/ui/src/controller.js
index fa38609..9942ba9 100644
--- a/src/framework_driver/ui/src/controller.js
+++ b/src/framework_driver/ui/src/controller.js
@@ -7,23 +7,20 @@ const Controller = {
},
async showProducts() {
- const products = await Model.fetchProducts();
- View.renderProducts(products);
+ const productsResponse = await Model.fetchProducts();
+ if(productsResponse.status=="success"){
+ const products = productsResponse.data;
+ View.renderProducts(products);
+ }
Controller.addProductClickHandlers();
},
- async showCart() {
- const userId = "1"; // Hardcoded for simplicity
- const cartResponse = await Model.fetchCart(userId);
- if(cartResponse.status=="success"){
- const cart = cartResponse.data;
- View.renderCart(cart);
- }
- },
-
async showProduct(productId) {
- const product = await Model.fetchProduct(productId);
- View.renderProduct(product);
+ const productResponse = await Model.fetchProduct(productId);
+ if(productResponse.status=="success"){
+ const product = productResponse.data;
+ View.renderProduct(product);
+ }
document.getElementById('back-button').addEventListener('click', () => {
Controller.showProducts();
});
@@ -45,11 +42,6 @@ const Controller = {
Controller.showProducts();
});
- document.getElementById('cart-tab').addEventListener('click', (event) => {
- event.preventDefault();
- Controller.showCart();
- });
-
document.getElementById('user-tab').addEventListener('click', (event) => {
event.preventDefault();
Controller.showUserRegister();
diff --git a/src/framework_driver/ui/src/model.js b/src/framework_driver/ui/src/model.js
index e5472b0..ed6774a 100644
--- a/src/framework_driver/ui/src/model.js
+++ b/src/framework_driver/ui/src/model.js
@@ -5,17 +5,6 @@ const Model = {
return response.json();
},
- async fetchCart(userId) {
- const response = await fetch('http://127.0.0.1:8000/view_cart', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({ user_id: userId }),
- });
- return response.json();
- },
-
async fetchProduct(productId) {
const response = await fetch(`http://127.0.0.1:8000/view_product/`, {
method: 'POST',
diff --git a/src/framework_driver/ui/src/view.js b/src/framework_driver/ui/src/view.js
index b94da9b..64ac537 100644
--- a/src/framework_driver/ui/src/view.js
+++ b/src/framework_driver/ui/src/view.js
@@ -1,7 +1,6 @@
// View: Handles rendering
const View = {
renderProducts(products) {
- var products = products.products;
const main = document.getElementById('main');
main.innerHTML = `
Products
@@ -21,25 +20,7 @@ const View = {
`;
},
- renderCart(cart) {
- var cartItems = cart.items;
- const main = document.getElementById('main');
- main.innerHTML = `
- Your Cart
-
- ${cartItems
- .map(
- (item) => `
- - ${item.name} - $${item.price} (Quantity: ${item.quantity})
`
- )
- .join('')}
-
- Total: $${cart.total_price}
- `;
- },
-
renderProduct(product) {
- var product = product.product;
const main = document.getElementById('main');
main.innerHTML = `
${product.name}
diff --git a/src/interface_adapters/controllers/base_controller.py b/src/interface_adapters/controllers/base_controller.py
deleted file mode 100644
index e85a764..0000000
--- a/src/interface_adapters/controllers/base_controller.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from use_cases.interfaces import BaseInputPort, BaseOutputPort
-
-class BaseController:
- def __init__(self, input_port: BaseInputPort) -> None:
- self.input_port = input_port
-
- def handle_request(self, request) -> dict:
- """Handles the incoming API request and delegates to the use case."""
- return self.input_port.execute(request)
\ No newline at end of file
diff --git a/src/interface_adapters/controllers/base_endpoint.py b/src/interface_adapters/controllers/base_endpoint.py
deleted file mode 100644
index 12abe3b..0000000
--- a/src/interface_adapters/controllers/base_endpoint.py
+++ /dev/null
@@ -1,28 +0,0 @@
-from typing import Type
-from fastapi import APIRouter, HTTPException
-
-from .base_controller import BaseController
-from use_cases.interfaces import BaseOutputPort, BaseInputPort, BaseRepository
-
-class Endpoint:
- def __init__(self,
- router: APIRouter,
- controller_impl: Type[BaseController],
- presenter_impl: Type[BaseOutputPort],
- repository_impl: Type[BaseRepository],
- use_case_impl: Type[BaseInputPort]
- ):
- self.router = router
- self.presenter = presenter_impl()
- self.repository = repository_impl()
- self.use_case = use_case_impl(repository=self.repository, output_port=self.presenter)
- self.controller = controller_impl(input_port=self.use_case)
-
- def create(self, route: str, request_model: Type, response_model: Type):
- @self.router.post(route, response_model=response_model)
- async def endpoint(request: request_model):
- try:
- response = self.controller.handle_request(request)
- return response
- except Exception as e:
- raise HTTPException(status_code=400, detail=str(e))
diff --git a/src/interface_adapters/controllers/cart_controller.py b/src/interface_adapters/controllers/cart_controller.py
deleted file mode 100644
index 64f007a..0000000
--- a/src/interface_adapters/controllers/cart_controller.py
+++ /dev/null
@@ -1,77 +0,0 @@
-#python imports
-from fastapi import APIRouter, HTTPException
-from fastapi.responses import JSONResponse
-from fastapi import FastAPI, Request
-from fastapi.responses import HTMLResponse
-from pydantic import BaseModel
-#dependency imports
-from use_cases.interactors import ViewCart
-from use_cases.interfaces import BaseInputPort, BaseOutputPort
-from interface_adapters.dtos import ViewCartRequestDTO, ViewCartResponseDTO, CartItemDTO, CartDTO
-from .base_controller import BaseController
-
-
-
-#move to main
-from .base_endpoint import Endpoint
-from interface_adapters.repositories import SQLCartRepository
-
-class ViewCartRequest(BaseModel):
- user_id: str
-
-class ViewCartResponse(BaseModel):
- status: str
- data: CartDTO
-
-class ViewCartController(BaseController):
- def __init__(self, input_port: BaseInputPort) -> None:
- self.input_port = input_port
-
- def handle_request(self, request) -> dict:
- """Handles the incoming API request and delegates to the use case."""
- return self.input_port.execute(request)
-
-class ViewCartPresenter(BaseOutputPort):
- def present(self, output) -> dict:
- """Format the response data for API."""
- cart_items=[CartItemDTO(product_id=item.product_id, name=item.name, quantity=item.quantity, price=item.price) for item in output.items]
- cart_data = CartDTO(items=cart_items,total_price=output.total_price)
- response = ViewCartResponse(status="success",data=cart_data)
- return response
-
-router = APIRouter()
-
-endpoint = Endpoint(router, ViewCartController, ViewCartPresenter, SQLCartRepository, ViewCart)
-endpoint.create("/view_cart", ViewCartRequest, ViewCartResponse)
-
-"""
-# Initialize components
-presenter = ViewCartPresenter()
-repository = SQLCartRepository()
-use_case = ViewCart(repository=repository, output_port=presenter)
-controller = ViewCartController(input_port=use_case)
-
-
-@router.post("/view_cart/")
-async def view_cart(request: ViewCartRequest):
- try:
- result = controller.handle_request(request.user_id)
- return result # Returns a dictionary which FastAPI will convert to JSON
- except Exception as e:
- raise HTTPException(status_code=400, detail=str(e))
-
-@router.post("/view_cart", response_model=ViewCartResponseDTO)
-async def view_cart(request_dto: ViewCartRequestDTO):
-
- cart = view_cart_use_case.execute(request_dto.user_id)
-
- if not cart:
- raise HTTPException(status_code=404, detail="Cart not found")
-
- response_dto = ViewCartResponseDTO(
- items=[CartItemDTO(product_id=item.product_id, name=item.name, quantity=item.quantity, price=item.price) for item in cart.items],
- total_price=sum(item.price * item.quantity for item in cart.items)
- )
-
- return response_dto
-"""
diff --git a/src/interface_adapters/controllers/product_controller.py b/src/interface_adapters/controllers/product_controller.py
index 3d4efd9..102bc9e 100644
--- a/src/interface_adapters/controllers/product_controller.py
+++ b/src/interface_adapters/controllers/product_controller.py
@@ -1,46 +1,76 @@
#python imports
+from typing import List
from fastapi import APIRouter, HTTPException
from fastapi.responses import JSONResponse
from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse
+from pydantic import BaseModel
#dependency imports
+from entities import Product
from use_cases.interactors import ViewProduct, ViewAllProducts
-from interface_adapters.dtos import ViewProductRequestDTO, ViewProductResponseDTO, ViewAllProductsResponseDTO, ProductDTO
+from use_cases.interfaces.ports import ViewProductInputPort, ViewAllProductsInputPort, ViewProductOutputPort, ViewAllProductsOutputPort
+from interface_adapters.dtos import ProductDTO
from interface_adapters.repositories import SQLProductRepository
-# Initialize components
+
+class ViewProductRequest(BaseModel):
+ product_id: int
+
+class ViewProductResponse(BaseModel):
+ status: str
+ data: ProductDTO
+
+class ViewProductPresenter(ViewProductOutputPort):
+ def present(self, product:Product) -> ViewProductResponse:
+ """Format the response data for API."""
+ product_dto=ProductDTO(id=product.id, name=product.name, description=product.description, price=product.price)
+ response = ViewProductResponse(status="success",data=product_dto)
+ return response
+
+class ViewProductController:
+ def __init__(self, input_port: ViewProductInputPort) -> None:
+ self.input_port = input_port
+
+ def handle_request(self, request:ViewProductRequest):
+ """Handles the incoming API request and delegates to the use case."""
+ return self.input_port.execute(request.product_id)
+
product_repository = SQLProductRepository()
-view_product_use_case = ViewProduct(product_repository)
-view_all_products_use_case = ViewAllProducts(product_repository)
+view_product_presenter = ViewProductPresenter()
+view_product_use_case = ViewProduct(product_repository, view_product_presenter)
+view_product_controller = ViewProductController(view_product_use_case)
+
+
+class ViewAllProductsResponse(BaseModel):
+ status: str
+ data: List[ProductDTO]
+
+class ViewAllProductsPresenter(ViewAllProductsOutputPort):
+ def present(self, products:List[Product]) -> ViewAllProductsResponse:
+ """Format the response data for API."""
+ products_dto=[ProductDTO(id=product.id, name=product.name, description=product.description, price=product.price) for product in products]
+ response = ViewAllProductsResponse(status="success",data=products_dto)
+ return response
+
+class ViewAllProductsController:
+ def __init__(self, input_port: ViewAllProductsInputPort) -> None:
+ self.input_port = input_port
+
+ def handle_request(self):
+ """Handles the incoming API request and delegates to the use case."""
+ return self.input_port.execute()
+
+view_all_products_presenter = ViewAllProductsPresenter()
+view_all_products_use_case = ViewAllProducts(product_repository, view_all_products_presenter)
+view_all_products_controller = ViewAllProductsController(view_all_products_use_case)
router = APIRouter()
-@router.post("/view_product", response_model=ViewProductResponseDTO)
-async def view_product(request_dto: ViewProductRequestDTO):
+@router.post("/view_product", response_model=ViewProductResponse)
+async def view_product(request: ViewProductRequest):
+ return view_product_controller.handle_request(request)
- product = view_product_use_case.execute(request_dto.product_id)
-
- if not product:
- raise HTTPException(status_code=404, detail="Product not found")
-
- response_dto = ViewProductResponseDTO(
- product=ProductDTO(id=product.id, name=product.name, description=product.description, price=product.price)
- )
-
- return response_dto
-
-@router.get("/view_products", response_model=ViewAllProductsResponseDTO)
+@router.get("/view_products", response_model=ViewAllProductsResponse)
async def view_products():
-
- products = view_all_products_use_case.execute()
-
- if not products:
- raise HTTPException(status_code=404, detail="Product not found")
- for product in products:
- print(product)
- response_dto = ViewAllProductsResponseDTO(
- products=[ProductDTO(id=product.id, name=product.name, description=product.description, price=product.price) for product in products]
- )
-
- return response_dto
+ return view_all_products_controller.handle_request()
diff --git a/src/interface_adapters/dtos/cart_dto.py b/src/interface_adapters/dtos/cart_dto.py
deleted file mode 100644
index 2abb0c4..0000000
--- a/src/interface_adapters/dtos/cart_dto.py
+++ /dev/null
@@ -1,13 +0,0 @@
-#python imports
-from pydantic import BaseModel
-from typing import List, Optional
-
-class CartItemDTO(BaseModel):
- product_id: int
- name: str
- quantity: int
- price: float
-
-class CartDTO(BaseModel):
- items: List[CartItemDTO]
- total_price: float
\ No newline at end of file
diff --git a/src/interface_adapters/dtos/view_all_products_response.py b/src/interface_adapters/dtos/view_all_products_response.py
deleted file mode 100644
index 88ed4d3..0000000
--- a/src/interface_adapters/dtos/view_all_products_response.py
+++ /dev/null
@@ -1,8 +0,0 @@
-#python imports
-from pydantic import BaseModel
-from typing import List, Optional
-
-from .product_dto import ProductDTO
-
-class ViewAllProductsResponseDTO(BaseModel):
- products: List[ProductDTO] = []
\ No newline at end of file
diff --git a/src/interface_adapters/dtos/view_cart_request.py b/src/interface_adapters/dtos/view_cart_request.py
deleted file mode 100644
index ac951e5..0000000
--- a/src/interface_adapters/dtos/view_cart_request.py
+++ /dev/null
@@ -1,6 +0,0 @@
-#python imports
-from pydantic import BaseModel
-from typing import List, Optional
-
-class ViewCartRequestDTO(BaseModel):
- user_id: int
\ No newline at end of file
diff --git a/src/interface_adapters/dtos/view_cart_response.py b/src/interface_adapters/dtos/view_cart_response.py
deleted file mode 100644
index 4284ef2..0000000
--- a/src/interface_adapters/dtos/view_cart_response.py
+++ /dev/null
@@ -1,10 +0,0 @@
-#python imports
-from pydantic import BaseModel
-from typing import List, Optional
-
-from .cart_dto import CartItemDTO
-
-
-class ViewCartResponseDTO(BaseModel):
- items: List[CartItemDTO] = []
- total_price: float = 0.0
\ No newline at end of file
diff --git a/src/interface_adapters/dtos/view_product_request.py b/src/interface_adapters/dtos/view_product_request.py
deleted file mode 100644
index a7367e2..0000000
--- a/src/interface_adapters/dtos/view_product_request.py
+++ /dev/null
@@ -1,6 +0,0 @@
-#python imports
-from pydantic import BaseModel
-from typing import List, Optional
-
-class ViewProductRequestDTO(BaseModel):
- product_id: int
\ No newline at end of file
diff --git a/src/interface_adapters/dtos/view_product_response.py b/src/interface_adapters/dtos/view_product_response.py
deleted file mode 100644
index bfb6e10..0000000
--- a/src/interface_adapters/dtos/view_product_response.py
+++ /dev/null
@@ -1,8 +0,0 @@
-#python imports
-from pydantic import BaseModel
-from typing import List, Optional
-
-from .product_dto import ProductDTO
-
-class ViewProductResponseDTO(BaseModel):
- product: ProductDTO
\ No newline at end of file
diff --git a/src/interface_adapters/repositories/sql_cart_repository.py b/src/interface_adapters/repositories/sql_cart_repository.py
deleted file mode 100644
index a404efb..0000000
--- a/src/interface_adapters/repositories/sql_cart_repository.py
+++ /dev/null
@@ -1,88 +0,0 @@
-#python imports
-from typing import Optional, List
-import sqlite3
-
-#dependency imports
-from use_cases.interfaces import ICartRepository
-from entities import Cart, CartItem
-
-class SQLCartRepository(ICartRepository):
- def __init__(self, db_file="framework_driver/db/shop.db"):
- """Initialize the CartDatabase with a connection to the SQLite database."""
- self.conn = sqlite3.connect(db_file)
- self.conn.row_factory = sqlite3.Row
-
- def add_to_cart(self, user_id, product_id, name, quantity, price):
- """Add a product to the user's cart."""
- sql = "INSERT INTO cart (user_id, product_id, name, quantity, price) VALUES (?, ?, ?, ?, ?)"
- try:
- c = self.conn.cursor()
- c.execute(sql, (user_id, product_id, name, quantity, price))
- self.conn.commit()
- return c.lastrowid
- except sqlite3.Error as e:
- print(e)
-
- def get_cart_by_user_id(self, user_id: int) -> Optional[Cart]:
- """Fetch cart items from the database for a given user ID."""
- sql = "SELECT product_id, name, quantity, price FROM cart WHERE user_id = ?"
- try:
- c = self.conn.cursor()
- c.execute(sql, (user_id,))
- rows = c.fetchall()
- return Cart([CartItem(**item) for item in rows])
- except sqlite3.Error as e:
- print(e)
- return None
-
- def update_cart_item(self, user_id, product_id, quantity):
- """Update the quantity of a specific cart item based on user_id and product_id."""
- sql = "UPDATE cart SET quantity = ? WHERE user_id = ? AND product_id = ?"
- try:
- c = self.conn.cursor()
- c.execute(sql, (quantity, user_id, product_id))
- self.conn.commit()
- except sqlite3.Error as e:
- print(e)
-
- def remove_from_cart(self, cart_id):
- """Remove a specific item from the cart."""
- sql = "DELETE FROM cart WHERE id = ?"
- try:
- c = self.conn.cursor()
- c.execute(sql, (cart_id,))
- self.conn.commit()
- except sqlite3.Error as e:
- print(e)
-
- def clear_cart(self, user_id):
- """Clear all items from a user's cart."""
- sql = "DELETE FROM cart WHERE user_id = ?"
- try:
- c = self.conn.cursor()
- c.execute(sql, (user_id,))
- self.conn.commit()
- except sqlite3.Error as e:
- print(e)
-
-def main():
- database = "framework_driver/db/shop.db"
-
- cart_db = SQLCartRepository(database)
-
- ex_user_id = 1
-
- # delete all cart items
- cart_db.clear_cart(ex_user_id)
-
- # user id, product id, name, quantity, price
- cart_db.add_to_cart(ex_user_id, 1, "Unsichtbare Tinte", 2, 3.0)
- cart_db.add_to_cart(ex_user_id, 3, "Geräuschloser Wecker", 5, 15.0)
- print(f"Cart items for user {ex_user_id}:", cart_db.get_cart_by_user_id(ex_user_id))
-
- # user id, product id, quantity
- cart_db.update_cart_item(ex_user_id, 2, 3)
- print(f"Cart items for user {ex_user_id}:", cart_db.get_cart_by_user_id(ex_user_id))
-
-if __name__ == "__main__":
- main()
\ No newline at end of file
diff --git a/src/interface_adapters/repositories/sql_product_repository.py b/src/interface_adapters/repositories/sql_product_repository.py
index d19e9eb..7d9e6a9 100644
--- a/src/interface_adapters/repositories/sql_product_repository.py
+++ b/src/interface_adapters/repositories/sql_product_repository.py
@@ -3,7 +3,7 @@ from typing import Optional, List
import sqlite3
#dependency imports
-from use_cases.interfaces import IProductRepository
+from use_cases.interfaces.repositories import IProductRepository
from entities import Product
class SQLProductRepository(IProductRepository):
diff --git a/src/interface_adapters/repositories/sql_user_repository.py b/src/interface_adapters/repositories/sql_user_repository.py
index 60fb5a1..c877686 100644
--- a/src/interface_adapters/repositories/sql_user_repository.py
+++ b/src/interface_adapters/repositories/sql_user_repository.py
@@ -3,7 +3,7 @@ from typing import Optional, List
import sqlite3
#dependency imports
-from use_cases.interfaces import IUserRepository
+from use_cases.interfaces.repositories import IUserRepository
from entities import User
class SQLUserRepository(IUserRepository):
diff --git a/src/main.py b/src/main.py
index 4e5f402..f298613 100644
--- a/src/main.py
+++ b/src/main.py
@@ -1,4 +1,3 @@
-from interface_adapters.controllers.cart_controller import router as cart_router
from interface_adapters.controllers.product_controller import router as product_router
from interface_adapters.controllers.user_controller import router as user_router
from fastapi.middleware.cors import CORSMiddleware
@@ -14,8 +13,8 @@ import os
app = FastAPI()
-app.include_router(cart_router)
app.include_router(product_router)
+app.include_router(user_router)
# Allow CORS for all origins (for simplicity)
app.add_middleware(
diff --git a/src/use_cases/README.md b/src/use_cases/README.md
index 2822cc6..52f1d7f 100644
--- a/src/use_cases/README.md
+++ b/src/use_cases/README.md
@@ -1,5 +1,5 @@
# USE CASES
-The software in the use cases layer contains application-specific business rules. It
+"The software in the use cases layer contains application-specific business rules. It
encapsulates and implements all of the use cases of the system. These use cases
orchestrate the flow of data to and from the entities, and direct those entities to use
their Critical Business Rules to achieve the goals of the use case.
@@ -8,4 +8,6 @@ this layer to be affected by changes to externalities such as the database, the
any of the common frameworks. The use cases layer is isolated from such concerns.
We do, however, expect that changes to the operation of the application will affect
the use cases and, therefore, the software in this layer. If the details of a use case
-change, then some code in this layer will certainly be affected.
\ No newline at end of file
+change, then some code in this layer will certainly be affected." -- Robert C. Martin, Clean Architecture
+
+# Aufgabe
\ No newline at end of file
diff --git a/src/use_cases/interactors/view_all_products.py b/src/use_cases/interactors/view_all_products.py
index 6b3c765..34c7536 100644
--- a/src/use_cases/interactors/view_all_products.py
+++ b/src/use_cases/interactors/view_all_products.py
@@ -3,11 +3,13 @@ from typing import Optional, List
#dependency imports
from entities import Product
-from use_cases.interfaces.product_repository import IProductRepository
+from use_cases.interfaces.repositories import IProductRepository
+from use_cases.interfaces.ports import ViewAllProductsInputPort, ViewAllProductsOutputPort
-class ViewAllProducts:
- def __init__(self, product_repository: IProductRepository):
+class ViewAllProducts(ViewAllProductsInputPort):
+ def __init__(self, product_repository: IProductRepository, output_port: ViewAllProductsOutputPort):
self.product_repository = product_repository
+ self.output_port = output_port
def execute(self) -> Optional[List[Product]]:
"""
@@ -16,4 +18,4 @@ class ViewAllProducts:
product_data = self.product_repository.get_all_products()
if not product_data:
return None
- return product_data
\ No newline at end of file
+ return self.output_port.present(product_data)
\ No newline at end of file
diff --git a/src/use_cases/interactors/view_cart.py b/src/use_cases/interactors/view_cart.py
deleted file mode 100644
index a232b9a..0000000
--- a/src/use_cases/interactors/view_cart.py
+++ /dev/null
@@ -1,34 +0,0 @@
-#python imports
-from typing import Optional
-
-#dependency imports
-from entities import Cart, CartItem
-from use_cases.interfaces.cart_repository import ICartRepository
-from use_cases.interfaces.base_output_port import BaseOutputPort
-from use_cases.interfaces.base_input_port import BaseInputPort
-
-"""
-class ViewCartInputPort():
- def execute(self, name: str, email: str) -> None:
- pass
-
-class ViewCartOutputPort():
- def present(self, user: dict) -> dict:
- pass
-"""
-class ViewCart(BaseInputPort):
- def __init__(self, repository: ICartRepository, output_port: BaseOutputPort):
- self.repository = repository
- self.output_port = output_port
-
- def execute(self, input_data) -> Optional[Cart]:
- """
- Fetches the cart data from the repository.
- """
- if not hasattr(input_data, 'user_id'):
- raise ValueError("Missing 'user_id' in input_data")
- cart = self.repository.get_cart_by_user_id(input_data.user_id)
- if not cart:
- return None
- cart.calculate_total_price()
- return self.output_port.present(cart)
\ No newline at end of file
diff --git a/src/use_cases/interactors/view_product.py b/src/use_cases/interactors/view_product.py
index 13ba9f0..14a882c 100644
--- a/src/use_cases/interactors/view_product.py
+++ b/src/use_cases/interactors/view_product.py
@@ -3,11 +3,13 @@ from typing import Optional
#dependency imports
from entities import Product
-from use_cases.interfaces.product_repository import IProductRepository
+from use_cases.interfaces.repositories import IProductRepository
+from use_cases.interfaces.ports import ViewProductInputPort, ViewProductOutputPort
-class ViewProduct:
- def __init__(self, product_repository: IProductRepository):
+class ViewProduct(ViewProductInputPort):
+ def __init__(self, product_repository: IProductRepository, output_port: ViewProductOutputPort):
self.product_repository = product_repository
+ self.output_port = output_port
def execute(self, product_id: int) -> Optional[Product]:
"""
@@ -17,4 +19,4 @@ class ViewProduct:
if not product_data:
return None
- return product_data
\ No newline at end of file
+ return self.output_port.present(product_data)
\ No newline at end of file
diff --git a/src/use_cases/interactors/view_user.py b/src/use_cases/interactors/view_user.py
deleted file mode 100644
index dab7561..0000000
--- a/src/use_cases/interactors/view_user.py
+++ /dev/null
@@ -1,14 +0,0 @@
-#python imports
-from typing import Optional
-
-#dependency imports
-#TODO: use correct dependencies
-
-class ViewUser:
- def __init__(self):
- pass
- #TODO: initialize required Interfaces
-
- def execute(self):
- pass
- #TODO: implement
\ No newline at end of file
diff --git a/src/use_cases/interfaces/base_output_port.py b/src/use_cases/interfaces/base_output_port.py
deleted file mode 100644
index 5dc5848..0000000
--- a/src/use_cases/interfaces/base_output_port.py
+++ /dev/null
@@ -1,6 +0,0 @@
-class BaseOutputPort:
- def present(self, output_data):
- """
- Abstract method to present use case output.
- """
- raise NotImplementedError("present must be implemented by a subclass")
\ No newline at end of file
diff --git a/src/use_cases/interfaces/base_repository.py b/src/use_cases/interfaces/base_repository.py
deleted file mode 100644
index a49804f..0000000
--- a/src/use_cases/interfaces/base_repository.py
+++ /dev/null
@@ -1,2 +0,0 @@
-class BaseRepository:
- pass
\ No newline at end of file
diff --git a/src/use_cases/interfaces/cart_repository.py b/src/use_cases/interfaces/cart_repository.py
deleted file mode 100644
index 54abece..0000000
--- a/src/use_cases/interfaces/cart_repository.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from typing import Optional, List
-
-#dependency imports
-from entities import Cart
-from .base_repository import BaseRepository
-
-class ICartRepository(BaseRepository):
- def get_cart_by_user_id(self, user_id: int) -> Optional[Cart]:
- """
- Abstract method to fetch cart data by user ID.
- """
- raise NotImplementedError("get_cart_by_user_id must be implemented by a subclass")
diff --git a/src/use_cases/interfaces/__init__.py b/src/use_cases/interfaces/ports/__init__.py
similarity index 100%
rename from src/use_cases/interfaces/__init__.py
rename to src/use_cases/interfaces/ports/__init__.py
diff --git a/src/use_cases/interfaces/base_input_port.py b/src/use_cases/interfaces/ports/view_all_products_input_port.py
similarity index 65%
rename from src/use_cases/interfaces/base_input_port.py
rename to src/use_cases/interfaces/ports/view_all_products_input_port.py
index 585fb54..1b3c606 100644
--- a/src/use_cases/interfaces/base_input_port.py
+++ b/src/use_cases/interfaces/ports/view_all_products_input_port.py
@@ -1,5 +1,5 @@
-class BaseInputPort:
- def execute(self, input_data):
+class ViewAllProductsInputPort:
+ def execute(self):
"""
Abstract method to execute use case.
"""
diff --git a/src/use_cases/interfaces/ports/view_all_products_output_port.py b/src/use_cases/interfaces/ports/view_all_products_output_port.py
new file mode 100644
index 0000000..46fbc59
--- /dev/null
+++ b/src/use_cases/interfaces/ports/view_all_products_output_port.py
@@ -0,0 +1,8 @@
+from entities import Product
+from typing import List
+class ViewAllProductsOutputPort:
+ def present(self, product_list:List[Product]):
+ """
+ Abstract method to execute use case.
+ """
+ raise NotImplementedError("execute must be implemented by a subclass")
\ No newline at end of file
diff --git a/src/use_cases/interfaces/ports/view_product_input_port.py b/src/use_cases/interfaces/ports/view_product_input_port.py
new file mode 100644
index 0000000..7f069e3
--- /dev/null
+++ b/src/use_cases/interfaces/ports/view_product_input_port.py
@@ -0,0 +1,6 @@
+class ViewProductInputPort:
+ def execute(self, product_id:int):
+ """
+ Abstract method to execute use case.
+ """
+ raise NotImplementedError("execute must be implemented by a subclass")
\ No newline at end of file
diff --git a/src/use_cases/interfaces/ports/view_product_output_port.py b/src/use_cases/interfaces/ports/view_product_output_port.py
new file mode 100644
index 0000000..9a4ee78
--- /dev/null
+++ b/src/use_cases/interfaces/ports/view_product_output_port.py
@@ -0,0 +1,7 @@
+from entities import Product
+class ViewProductOutputPort:
+ def present(self, product:Product):
+ """
+ Abstract method to execute use case.
+ """
+ raise NotImplementedError("execute must be implemented by a subclass")
\ No newline at end of file
diff --git a/src/use_cases/interfaces/repositories/__init__.py b/src/use_cases/interfaces/repositories/__init__.py
new file mode 100644
index 0000000..10727b3
--- /dev/null
+++ b/src/use_cases/interfaces/repositories/__init__.py
@@ -0,0 +1,11 @@
+import importlib
+import pkgutil
+import inspect
+
+__all__ = []
+for loader, module_name, is_pkg in pkgutil.walk_packages(__path__):
+ module = importlib.import_module(f".{module_name}", __name__)
+ for name, obj in inspect.getmembers(module, inspect.isclass):
+ if obj.__module__ == module.__name__:
+ globals()[name] = obj
+ __all__.append(name)
\ No newline at end of file
diff --git a/src/use_cases/interfaces/product_repository.py b/src/use_cases/interfaces/repositories/product_repository.py
similarity index 100%
rename from src/use_cases/interfaces/product_repository.py
rename to src/use_cases/interfaces/repositories/product_repository.py
diff --git a/src/use_cases/interfaces/user_repository.py b/src/use_cases/interfaces/repositories/user_repository.py
similarity index 100%
rename from src/use_cases/interfaces/user_repository.py
rename to src/use_cases/interfaces/repositories/user_repository.py