diff --git a/source/RewardsService/Dockerfile b/source/RewardsService/Dockerfile index 99c06781..018329c6 100644 --- a/source/RewardsService/Dockerfile +++ b/source/RewardsService/Dockerfile @@ -1,8 +1,9 @@ -FROM python:3.5 +FROM python:3.9 ENV PYTHONUNBUFFERED 1 ENV PYTHONPATH=$PYTHONPATH:/code/ RUN mkdir /code WORKDIR /code ADD requirements.txt /code/ -RUN pip install -r requirements.txt +RUN pip install --upgrade pip +RUN pip install --no-cache-dir -r requirements.txt ADD ./ /code/ diff --git a/source/RewardsService/requirements.txt b/source/RewardsService/requirements.txt index c6db96e9..ff9fba8c 100644 --- a/source/RewardsService/requirements.txt +++ b/source/RewardsService/requirements.txt @@ -1,3 +1,5 @@ fabric==1.10.2 motor==1.1.0 tornado==3.2 +jsonschema==4.21.1 +black==24.1.1 \ No newline at end of file diff --git a/source/RewardsService/rewardsservice/handlers/orders_handlers.py b/source/RewardsService/rewardsservice/handlers/orders_handlers.py new file mode 100644 index 00000000..b60c1ae8 --- /dev/null +++ b/source/RewardsService/rewardsservice/handlers/orders_handlers.py @@ -0,0 +1,126 @@ +import datetime +import operator +import re +import json + +import tornado.web +from jsonschema import validate +from jsonschema.exceptions import ValidationError +from pymongo import MongoClient +from tornado.gen import coroutine + +regex = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,7}\b' +dt_format = "%Y/%m/%d %H:%M:%S" + + +class OrdersHandler(tornado.web.RequestHandler): + + client = MongoClient("mongodb", 27017) + db = client["Rewards"] + schema = { + "type": "object", + "properties": { + "email": {"type": "string"}, + "order_total": {"type": "number"}, + }, + "required": ["email", "order_total"], + } + + @staticmethod + def _serialize_data(data): + for item in data: + item["created"] = item["created"].strftime(dt_format) + item["updated"] = item["updated"].strftime(dt_format) + + @coroutine + def get(self): + orders = list(self.db.orders.find({}, {"_id": 0})) + self._serialize_data(orders) + self.write(json.dumps(orders)) + + @coroutine + def post(self): + try: + data = json.loads(self.request.body.decode("utf-8")) + + # input body validation + try: + validate(data, schema=self.schema) + except ValidationError as ve: + self.set_status(400) + self.write(json.dumps({"error_message": ve.message})) + self.finish() + + # email validation + # tried using external package was getting installation + # error in docker so moved to regex + if re.fullmatch(regex, data.get("email")): + pass + else: + self.set_status(422) + self.write(json.dumps({"error_message": "Invalid Email ID"})) + self.finish() + + record = { + "email": data.get("email"), + "order_total": data.get("order_total", 0.0) + } + rewards_data = list(self.db.rewards.find({}, {"_id": 0})) + # sort by points descending true + rewards_data.sort(key=operator.itemgetter("points"), reverse=True) + + # fetch reward match + order_total = data.get('order_total', 0.0) + try: + matching_reward = next(( + item for item in rewards_data if order_total >= item["points"] + )) + except StopIteration: + matching_reward = None + + # update record + if matching_reward: + record.update({ + "reward_points": matching_reward["points"], + "reward_tier": matching_reward["tier"], + "reward_tier_name": matching_reward["rewardName"] + }) + + # finding the next tier + if matching_reward != rewards_data[0]: + next_tier = rewards_data[rewards_data.index(matching_reward) - 1] + record.update({ + "next_reward_tier": next_tier["tier"], + "next_reward_tier_name": next_tier["rewardName"], + "next_reward_tier_progress": (order_total / next_tier["points"]) * 100 + }) + + # metadata + record["created"] = datetime.datetime.now() + record["updated"] = datetime.datetime.now() + + self.db.orders.insert(record) + + self.set_status(201) + self.write(json.dumps({"status": "Order Created"})) + self.finish() + except Exception as e: + self.set_status(400) + self.write(json.dumps({"error_message": f"{str(e)}"})) + + +class OrderHandler(tornado.web.RequestHandler): + client = MongoClient("mongodb", 27017) + db = client["Rewards"] + + def get(self): + query = {} + email = self.get_query_argument("email", default=None) + if not email: + self.write(json.dumps({"error_message": "Please provide email as query params"})) + self.finish() + query["email"] = email + order = self.db.orders.find_one(query, {"_id": 0}) + order["created"] = order["created"].strftime(dt_format) + order["updated"] = order["updated"].strftime(dt_format) + self.write(json.dumps(order)) diff --git a/source/RewardsService/rewardsservice/handlers/rewards_handler.py b/source/RewardsService/rewardsservice/handlers/rewards_handler.py index 4f2aea6e..6a51165f 100644 --- a/source/RewardsService/rewardsservice/handlers/rewards_handler.py +++ b/source/RewardsService/rewardsservice/handlers/rewards_handler.py @@ -1,15 +1,16 @@ import json -import tornado.web +import tornado.web from pymongo import MongoClient from tornado.gen import coroutine class RewardsHandler(tornado.web.RequestHandler): + client = MongoClient("mongodb", 27017) + db = client["Rewards"] + @coroutine def get(self): - client = MongoClient("mongodb", 27017) - db = client["Rewards"] - rewards = list(db.rewards.find({}, {"_id": 0})) + rewards = list(self.db.rewards.find({}, {"_id": 0})) self.write(json.dumps(rewards)) diff --git a/source/RewardsService/rewardsservice/url_patterns.py b/source/RewardsService/rewardsservice/url_patterns.py index 55e471d6..d5803844 100644 --- a/source/RewardsService/rewardsservice/url_patterns.py +++ b/source/RewardsService/rewardsservice/url_patterns.py @@ -1,5 +1,8 @@ from handlers.rewards_handler import RewardsHandler +from handlers.orders_handlers import OrdersHandler, OrderHandler url_patterns = [ - (r'/rewards', RewardsHandler), + (r"/rewards", RewardsHandler), + (r"/orders", OrdersHandler), + (r"/order", OrderHandler), ]