diff --git a/app/ShyBadger/src/__init__.py b/app/ShyBadger/src/__init__.py deleted file mode 100644 index 9388197..0000000 --- a/app/ShyBadger/src/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# left empty so the user has to import all submodules explicitly, -# this ensures clear namespace separation \ No newline at end of file diff --git a/app/ShyBadger/src/endpoints/BasketEndpoint.py b/app/ShyBadger/src/endpoints/BasketEndpoint.py deleted file mode 100644 index e6a78ca..0000000 --- a/app/ShyBadger/src/endpoints/BasketEndpoint.py +++ /dev/null @@ -1,31 +0,0 @@ -from flask_restful import Resource -from flask import session, Response, request -import uuid - -from src.services import BasketService - - -class Basket(Resource): - basket_service = BasketService() - - def get_session_id(): - # first interaction with server sets session_id - # would need to research if this is ideal - return str(uuid.uuid4()) - - def get(self): - if "session_id" not in session: - session["session_id"] = self.get_session_id() - return Response( - {"total": self.basket_service.total()}, mimetype="application/json" - ) - - def post(self): - # expects something similar: {"items": [{"item_id": abc002}]} - - if "session_id" not in session: - session["session_id"] = self.get_session_id() - jsonData = request.get_json(force=True) - for entry in jsonData["items"]: - self.basket_service.scan(entry["item_id"]) - return Response(HTTPStatus=201) diff --git a/app/ShyBadger/src/main.py b/app/ShyBadger/src/main.py deleted file mode 100644 index a84bce3..0000000 --- a/app/ShyBadger/src/main.py +++ /dev/null @@ -1,20 +0,0 @@ -from flask import Flask, request, g, render_template, redirect -from flask_restful import Resource, reqparse -from flask_restful_swagger_3 import Api -from json import dumps -import logging - -import endpoints.BasketEndpoint as BasketEndpoint - -app = Flask(__name__) -app.secret_key = "SUPER_DUPER_BAD_SECRET_KEY" -api = Api(app) -logging.basicConfig(level=logging.DEBUG) -api.add_resource(BasketEndpoint.Basket, "/api/v1/basket/") - - -@app.route("/") -def index(): - """in lieu of a UI redirect to the API doc""" - app.logger.info(f"request from {request.remote_addr}") - return redirect("/api/doc/swagger.json", code=302) diff --git a/app/ShyBadger/src/models/Item.py b/app/ShyBadger/src/models/Item.py deleted file mode 100644 index c1e0213..0000000 --- a/app/ShyBadger/src/models/Item.py +++ /dev/null @@ -1,7 +0,0 @@ -from dataclasses import dataclass - - -@dataclass -class Item: - id: str - price: str diff --git a/app/ShyBadger/src/run.py b/app/ShyBadger/src/run.py deleted file mode 100644 index d54fb3f..0000000 --- a/app/ShyBadger/src/run.py +++ /dev/null @@ -1,5 +0,0 @@ -from main import app - -# disabled threading for easier session handleing in this demo project -# if threaded was True, as session store would be needed -app.run(host="0.0.0.0", port="80", debug=False, threaded=False) diff --git a/app/ShyBadger/src/services/BasketService.py b/app/ShyBadger/src/services/BasketService.py deleted file mode 100644 index 3bb6b71..0000000 --- a/app/ShyBadger/src/services/BasketService.py +++ /dev/null @@ -1,23 +0,0 @@ -from collections import defaultdict -from DealsService import DealsService -from ProductService import ProductService - - -class BasketService: - baskets = None - dealsService = None - productService = None - - def __init__(self) -> None: - self.baskets = defaultdict() - self.dealsService = DealsService() - self.productService = ProductService() - - def total(self, sessionID: str) -> int: - items = self.baskets[sessionID] - prices = self.dealsService.get_items_with_final_prices(items) - return sum(prices) - - def scan(self, session_id: str, itemId) -> None: - item = self.productService.get_item_from_id(itemId) - self.baskets[session_id].append(item) diff --git a/app/ShyBadger/src/services/DealsService.py b/app/ShyBadger/src/services/DealsService.py deleted file mode 100644 index ee8e19e..0000000 --- a/app/ShyBadger/src/services/DealsService.py +++ /dev/null @@ -1,75 +0,0 @@ -from collections import defaultdict -import math - - -class DealsService: - # deals and promotions are global and therefor class vars instead of instance vars - deals = dict() - promotions = defaultdict(list) - - def __init__(self) -> None: - # placeholder data - # promiootion can be read dznamically from db - self.promotions["A0001"].append("two_for_one") - self.promotions["A0002"].append("ten_percent_off") - - # deal behavior needs to be programmed an can only be - # changed with the rollout of a new version, - self.deals["two_for_one"] = DealsService.two_for_one_deal - - def get_items_with_final_prices(self, items) -> list: - groups = defaultdict(list) - - for obj in items: - groups[obj.id].append(obj) - - for group in groups.values(): - # the deals do not stack, the first deal in the list of deals is taken, - # ideally for the customer all deals would be calculated and the maximum value selected - # not implemented for time reasons - - for promotion in self.promotions.get(group[0].id): - # iterate over all promotions for this item - # lookup the higher order function that is associated with this deal name - # apply the function to the item group - # if the deal was applied to the group of items break and move on to the next item group - # this avoids discout stacking - if self.deals[promotion](group): - break - - return [item for group in groups.values() for item in group] - - @staticmethod - def two_for_one_deal(group): - """' applies deal onto item group in place""" - - # ideally would be an object implementing a "Deal"-interface, - # which has 2 functions, deal_is_applicable() and apply_deal() - def _round_up(self, val: float): - return math.ceil(val * 100) / 100 - - # could be compressed - # not done since this would be the 2 different functions in the above mentioned interface - deal_is_applicable = False - if len(group) >= 2: - deal_is_applicable = True - - for i in range(len(group) // 2): - group[i].price = _round_up(group[i].price / 2) - return deal_is_applicable - - @staticmethod - def ten_percent_off(group): - # the percentage discount could be added to function signature - """' applies deal onto item group in place""" - - # ideally would be an object implementing a "Deal"-interface, - # which has 2 functions, deal_is_applicable() and apply_deal() - def _round_up(self, val: float): - return math.ceil(val * 100) / 100 - - deal_is_applicable = True - - for i in range(len(group)): - group[i].price = _round_up(group[i].price * 0.9) - return deal_is_applicable diff --git a/app/ShyBadger/src/services/ProductService.py b/app/ShyBadger/src/services/ProductService.py deleted file mode 100644 index 6cac84b..0000000 --- a/app/ShyBadger/src/services/ProductService.py +++ /dev/null @@ -1,15 +0,0 @@ -from src.models import Item - - -class ProductService: - # prices are global, sheduled function to refresh prices periodically - # could save ressources under high load - prices = dict() - - def __init__(self) -> None: - # placeholder data - self.prices["A0001"] = 12.99 - self.prices["A0002"] = 3.99 - - def get_item_from_id(self, item_id: str) -> Item: - return Item(id=item_id, price=self.prices.get(item_id)) diff --git a/app/ShyBadger/tests/test.py b/app/ShyBadger/tests/test.py deleted file mode 100644 index e69de29..0000000