Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 18 additions & 18 deletions python_codebase/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,44 +14,43 @@ def get_hashed_password(password):


async def very_token(token: str):
'''verify token from login'''
"""verify token from login"""
try:
payload = jwt.decode(token, get_settings().SECRET,
algorithms=["HS256"])
payload = jwt.decode(token, get_settings().SECRET, algorithms=["HS256"])
user = await User.get(id=payload.get("id"))

except:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid Token",
headers={"WWW-Authenticate": "Bearer"}
headers={"WWW-Authenticate": "Bearer"},
)
return await user


async def very_token_email(token: str):
'''verify token from email'''
"""verify token from email"""
try:
payload = jwt.decode(token, get_settings().SECRET,
algorithms=["HS256"])
payload = jwt.decode(token, get_settings().SECRET, algorithms=["HS256"])
user = await User.get(id=payload.get("id"), email=payload.get("email"))

except:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid Token",
headers={"WWW-Authenticate": "Bearer"}
headers={"WWW-Authenticate": "Bearer"},
)
return await user


# bug: sam_ple@gma.com:Trye ; sam_p_le@gma.com: False!!
regex = '^[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w{2,3}$'
regex = "^[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w{2,3}$"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restrictive email regex rejects valid emails

The email regex is overly restrictive and fails to validate emails with multiple dots or underscores in the local part, as highlighted by the bug comment showing sam_p_le@gma.com incorrectly rejected. This can cause valid user registrations to fail in main.py where is_not_email is used. Update the regex to a more permissive pattern that allows multiple special characters while maintaining basic validation.

Code suggestion
Check the AI-generated fix before applying
 -# bug: sam_ple@gma.com:Trye ; sam_p_le@gma.com: False!!
 -regex = "^[a-z0-9]+[\\._]?[a-z0-9]+[@]\\w+[.]\\w{2,3}$"
 +# Fixed: Updated regex to handle multiple dots and underscores in local part
 +regex = "^[a-z0-9]+([\\._][a-z0-9]+)*[@]\\w+([.]\\w+)+$"

Code Review Run #803e49


Should Bito avoid suggestions like this for future reviews? (Manage Rules)

  • Yes, avoid them



def is_not_email(email):
"""if valid mail: return 'True' \n
** This is a simple way to do this and is not recommended for a real project ** """
if(re.search(regex, email)):
"""if valid mail: return 'True' \n
** This is a simple way to do this and is not recommended for a real project **"""
if re.search(regex, email):
return False
else:
return True
Expand All @@ -68,7 +67,7 @@ async def authenticate_user(username: str, password: str):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Email not verifide",
headers={"WWW-Authenticate": "Bearer"}
headers={"WWW-Authenticate": "Bearer"},
)
return user
return False
Expand All @@ -81,12 +80,13 @@ async def token_generator(username: str, password: str):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid Username or Password",
headers={"WWW-Authenticate": "Bearer"}
headers={"WWW-Authenticate": "Bearer"},
)

token_data = {
"id": user.id,
"username": user.username
}
token_data = {"id": user.id, "username": user.username}
token = jwt.encode(token_data, get_settings().SECRET, algorithm="HS256")
return token


async def get_current_user(token: str = Depends(oauth_scheme)):
return await very_token(token)
13 changes: 13 additions & 0 deletions python_codebase/inventory_management_api/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from flask import Flask
from config import configure_app
from rate_limiter import limiter
from routes.inventory import inventory_bp

app = Flask(__name__)
configure_app(app)
limiter.init_app(app)

app.register_blueprint(inventory_bp, url_prefix="/inventory")

if __name__ == "__main__":
app.run(debug=True)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove debug mode for production security

Running the Flask app with debug=True exposes sensitive application internals, stack traces, and configuration details, which can lead to security vulnerabilities in production. The configure_app function sets database credentials and other configs that could be leaked. Remove debug=True from the app.run() call to ensure secure operation.

Code suggestion
Check the AI-generated fix before applying
Suggested change
app.run(debug=True)
app.run()

Code Review Run #803e49


Should Bito avoid suggestions like this for future reviews? (Manage Rules)

  • Yes, avoid them

10 changes: 10 additions & 0 deletions python_codebase/inventory_management_api/cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import redis
from flask import current_app


def get_cache():
return redis.Redis(
host=current_app.config["REDIS_HOST"],
port=current_app.config["REDIS_PORT"],
db=0,
)
11 changes: 11 additions & 0 deletions python_codebase/inventory_management_api/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import os


def configure_app(app):
app.config["REDIS_HOST"] = "localhost"
app.config["REDIS_PORT"] = 6379
app.config["DB_HOST"] = "localhost"
app.config["DB_USER"] = "user"
app.config["DB_PASSWORD"] = os.getenv("DB_PASSWORD", "default")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Insecure default database password

The database password configuration uses an insecure default value of 'default' if the environment variable is not set. This poses a significant security risk as it could allow unauthorized access with a weak password. The get_cache function in cache.py relies on Redis configuration set here, and database operations in routes like inventory.py depend on secure DB credentials. Remove the default to ensure DB_PASSWORD must be explicitly set via environment variable, preventing potential security breaches.

Code suggestion
Check the AI-generated fix before applying
Suggested change
app.config["DB_PASSWORD"] = os.getenv("DB_PASSWORD", "default")
app.config["DB_PASSWORD"] = os.getenv("DB_PASSWORD")

Code Review Run #803e49


Should Bito avoid suggestions like this for future reviews? (Manage Rules)

  • Yes, avoid them

app.config["DB_NAME_1"] = "inventory_db1"
app.config["DB_NAME_2"] = "inventory_db2"
4 changes: 4 additions & 0 deletions python_codebase/inventory_management_api/rate_limiter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address

limiter = Limiter(key_func=get_remote_address, default_limits=["100 per minute"])
Empty file.
60 changes: 60 additions & 0 deletions python_codebase/inventory_management_api/routes/cart.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from fastapi import APIRouter, Depends, HTTPException
from models import User, Cart, CartItem, Product
from authentication import get_current_user

router = APIRouter()


@router.post("/cart/add")
async def add_to_cart(
product_id: int, quantity: int, user: User = Depends(get_current_user)
):
product = await Product.get(id=product_id)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing quantity validation in add_to_cart

The add_to_cart function lacks validation for the quantity parameter, allowing negative or zero values that corrupt cart state. Add a check to ensure quantity > 0 before processing. This prevents invalid quantities from affecting cart totals in view_cart.

Code suggestion
Check the AI-generated fix before applying
Suggested change
product = await Product.get(id=product_id)
if quantity <= 0:
raise HTTPException(status_code=400, detail="Quantity must be greater than 0")
product = await Product.get(id=product_id)

Code Review Run #803e49


Should Bito avoid suggestions like this for future reviews? (Manage Rules)

  • Yes, avoid them

cart, _ = await Cart.get_or_create(user=user)
cart_item, created = await CartItem.get_or_create(cart=cart, product=product)

if not created:
cart_item.quantity += quantity
else:
cart_item.quantity = quantity

cart_item.price = product.new_price
await cart_item.save()
return {"message": "Item added to cart"}
Comment on lines +1 to +23

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Race condition in cart quantity updates

The add_to_cart function has a race condition where concurrent requests adding the same product can result in lost quantity updates due to non-atomic operations. Replace the manual quantity increment with atomic database updates using Tortoise's F expression to ensure consistency. This affects downstream cart total calculations in view_cart which relies on accurate quantities.

Code suggestion
Check the AI-generated fix before applying
Suggested change
from fastapi import APIRouter, Depends, HTTPException
from models import User, Cart, CartItem, Product
from authentication import get_current_user
router = APIRouter()
@router.post("/cart/add")
async def add_to_cart(
product_id: int, quantity: int, user: User = Depends(get_current_user)
):
product = await Product.get(id=product_id)
cart, _ = await Cart.get_or_create(user=user)
cart_item, created = await CartItem.get_or_create(cart=cart, product=product)
if not created:
cart_item.quantity += quantity
else:
cart_item.quantity = quantity
cart_item.price = product.new_price
await cart_item.save()
return {"message": "Item added to cart"}
from fastapi import APIRouter, Depends, HTTPException
from models import User, Cart, CartItem, Product
from authentication import get_current_user
from tortoise.expressions import F
router = APIRouter()
@router.post("/cart/add")
async def add_to_cart(
product_id: int, quantity: int, user: User = Depends(get_current_user)
):
product = await Product.get(id=product_id)
cart, _ = await Cart.get_or_create(user=user)
updated = await CartItem.filter(cart=cart, product=product).update(quantity=F('quantity') + quantity, price=product.new_price)
if updated == 0:
await CartItem.create(cart=cart, product=product, quantity=quantity, price=product.new_price)
return {"message": "Item added to cart"}

Code Review Run #803e49


Should Bito avoid suggestions like this for future reviews? (Manage Rules)

  • Yes, avoid them



@router.get("/cart")
async def view_cart(user: User = Depends(get_current_user)):
cart, _ = await Cart.get_or_create(user=user)
items = await CartItem.filter(cart=cart).prefetch_related("product")
total = sum(item.quantity * item.price for item in items)
return {
"items": [
{
"product": item.product.name,
"quantity": item.quantity,
"price": item.price,
"total": item.quantity * item.price,
}
for item in items
],
"total": total,
}


@router.put("/cart/update/{item_id}")
async def update_cart_item(
item_id: int, quantity: int, user: User = Depends(get_current_user)
):
cart = await Cart.get(user=user)
item = await CartItem.get(id=item_id, cart=cart)
item.quantity = quantity
await item.save()
Comment on lines +49 to +52

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing quantity validation in update_cart_item

The update_cart_item function lacks validation for the quantity parameter, allowing negative or zero values that corrupt cart state. Add a check to ensure quantity > 0 before updating. This prevents invalid quantities from affecting cart totals in view_cart.

Code suggestion
Check the AI-generated fix before applying
Suggested change
cart = await Cart.get(user=user)
item = await CartItem.get(id=item_id, cart=cart)
item.quantity = quantity
await item.save()
cart = await Cart.get(user=user)
item = await CartItem.get(id=item_id, cart=cart)
if quantity <= 0:
raise HTTPException(status_code=400, detail="Quantity must be greater than 0")
item.quantity = quantity
await item.save()

Code Review Run #803e49


Should Bito avoid suggestions like this for future reviews? (Manage Rules)

  • Yes, avoid them

return {"message": "Cart item updated"}


@router.delete("/cart/remove/{item_id}")
async def remove_from_cart(item_id: int, user: User = Depends(get_current_user)):
cart = await Cart.get(user=user)
await CartItem.filter(id=item_id, cart=cart).delete()
return {"message": "Item removed from cart"}
122 changes: 122 additions & 0 deletions python_codebase/inventory_management_api/routes/inventory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
from flask import Blueprint, request, jsonify
import mysql.connector
from cache import get_cache
from db import get_shards, get_shard, execute_query
from rate_limiter import limiter
Comment on lines +1 to +5

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cache serialization type mismatch

The inventory data is cached as a string representation of the list, but when retrieved from cache, it's returned as a decoded string instead of the original list structure. This causes type inconsistency where cached responses return a string while non-cached responses return a list of tuples, potentially breaking JSON serialization or client expectations. The get_inventory method in InventoryRoutes handles caching, but the serialization approach doesn't preserve data types correctly. To fix this, serialize the inventory data as JSON when caching and deserialize it when retrieving, ensuring consistent list responses regardless of cache hit status.

Code suggestion
Check the AI-generated fix before applying
Suggested change
from flask import Blueprint, request, jsonify
import mysql.connector
from cache import get_cache
from db import get_shards, get_shard, execute_query
from rate_limiter import limiter
from flask import Blueprint, request, jsonify
import json
import mysql.connector
from cache import get_cache
from db import get_shards, get_shard, execute_query
from rate_limiter import limiter

Code Review Run #803e49


Should Bito avoid suggestions like this for future reviews? (Manage Rules)

  • Yes, avoid them



class InventoryRoutes:
def __init__(self):
self.shards = get_shards()
self.cache = get_cache()

def get_inventory(self):
try:
product_id = request.args.get("product_id")
page = int(request.args.get("page", 1))
per_page = int(request.args.get("per_page", 10))

offset = (page - 1) * per_page
cache_key = f"inventory_{product_id}_{page}_{per_page}"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incomplete cache invalidation on updates

Cache invalidation in update_inventory and delete_inventory methods deletes only the base cache key 'inventory_{product_id}', but the get_inventory method uses keys that include page and per_page parameters like 'inventory_{product_id}{page}{per_page}'. This mismatch means updates and deletes don't invalidate all cached entries for different pages, leading to stale data being served. The InventoryRoutes class manages caching across methods, but the key formats are inconsistent. To resolve this, standardize the cache key to exclude pagination parameters so that invalidation works correctly, though this means losing per-page caching granularity.

Code suggestion
Check the AI-generated fix before applying
Suggested change
cache_key = f"inventory_{product_id}_{page}_{per_page}"
cache_key = f"inventory_{product_id}"

Code Review Run #803e49


Should Bito avoid suggestions like this for future reviews? (Manage Rules)

  • Yes, avoid them

cached_inventory = self.cache.get(cache_key)

if cached_inventory:
return jsonify({"inventory": cached_inventory.decode("utf-8")})

shard = get_shard(int(product_id), self.shards)
query = f"""
SELECT
i.product_id, i.quantity, p.name AS product_name, c.name AS category_name
FROM
inventory i
JOIN
products p ON i.product_id = p.id
JOIN
categories c ON p.category_id = c.id
WHERE
i.product_id = %s
Comment on lines +27 to +37

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SQL injection vulnerability and formatting issues

SQL query uses f-string which poses SQL injection risk (S608) and has trailing whitespace issues. The query is already using parameterized queries correctly, so remove f-string formatting.

Code suggestion
Check the AI-generated fix before applying
Suggested change
query = f"""
SELECT
i.product_id, i.quantity, p.name AS product_name, c.name AS category_name
FROM
inventory i
JOIN
products p ON i.product_id = p.id
JOIN
categories c ON p.category_id = c.id
WHERE
i.product_id = %s
query = """
SELECT
i.product_id, i.quantity, p.name AS product_name, c.name AS category_name
FROM
inventory i
JOIN
products p ON i.product_id = p.id
JOIN
categories c ON p.category_id = c.id
WHERE
i.product_id = %s

Code Review Run #803e49


Should Bito avoid suggestions like this for future reviews? (Manage Rules)

  • Yes, avoid them

LIMIT %s OFFSET %s
"""
cursor = execute_query(shard, query, (product_id, per_page, offset))
inventory = cursor.fetchall()

if inventory:
self.cache.setex(cache_key, 300, str(inventory)) # Cache for 5 minutes
return jsonify({"inventory": inventory})

return jsonify({"error": "Product not found"}), 404
except mysql.connector.Error as err:
return jsonify({"error": str(err)}), 500

def add_inventory(self):
try:
data = request.json
product_id = data.get("product_id")
quantity = data.get("quantity")

if not product_id or not quantity:
return jsonify({"error": "Invalid data"}), 400

shard = get_shard(int(product_id), self.shards)
query = "INSERT INTO inventory (product_id, quantity) VALUES (%s, %s)"
cursor = execute_query(shard, query, (product_id, quantity))
shard.commit()

return jsonify({"message": "Inventory added successfully"}), 201
except mysql.connector.Error as err:
return jsonify({"error": str(err)}), 500

def update_inventory(self):
try:
data = request.json
product_id = data.get("product_id")
quantity = data.get("quantity")

if not product_id or not quantity:
return jsonify({"error": "Invalid data"}), 400

shard = get_shard(int(product_id), self.shards)
query = "UPDATE inventory SET quantity = %s WHERE product_id = %s"
cursor = execute_query(shard, query, (quantity, product_id))
shard.commit()

# Invalidate cache after update
self.cache.delete(f"inventory_{product_id}")

return jsonify({"message": "Inventory updated successfully"}), 200
except mysql.connector.Error as err:
return jsonify({"error": str(err)}), 500

def delete_inventory(self):
try:
data = request.json
product_id = data.get("product_id")

if not product_id:
return jsonify({"error": "Invalid data"}), 400

shard = get_shard(int(product_id), self.shards)
query = "DELETE FROM inventory WHERE product_id = %s"
cursor = execute_query(shard, query, (product_id,))
shard.commit()

# Invalidate cache after delete
self.cache.delete(f"inventory_{product_id}")

# Confirm deletion
if cursor.rowcount == 0:
return jsonify({"error": "Product not found"}), 404

return jsonify({"message": "Inventory deleted successfully"}), 200
except mysql.connector.Error as err:
return jsonify({"error": str(err)}), 500


inventory_routes = InventoryRoutes()

inventory_bp = Blueprint("inventory", __name__)

inventory_bp.route("/", methods=["GET"])(inventory_routes.get_inventory)
inventory_bp.route("/add", methods=["POST"])(inventory_routes.add_inventory)
inventory_bp.route("/update", methods=["POST"])(inventory_routes.update_inventory)
inventory_bp.route("/delete", methods=["POST"])(inventory_routes.delete_inventory)
64 changes: 64 additions & 0 deletions python_codebase/inventory_management_api/routes/recommendation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from collections import defaultdict
from db import execute_query, get_shards, get_shard


class RecommendationEngine:
def __init__(self):
self.shards = get_shards()

def get_recommendations(self, user_id, num_recommendations=5):
try:
product_counts = defaultdict(int)

# Fetch past orders of the user
for shard in self.shards:
query = """
SELECT
oi.product_id, COUNT(*) AS count
FROM
orders o
JOIN
order_items oi ON o.id = oi.order_id
WHERE
o.user_id = %s
GROUP BY
oi.product_id
"""
cursor = execute_query(shard, query, (user_id,))
results = cursor.fetchall()

for product_id, count in results:
product_counts[product_id] += count

# Fetch recent search history of the user
for shard in self.shards:
query = """
SELECT
product_id
FROM
search_history
WHERE
user_id = %s
ORDER BY
search_time DESC
LIMIT %s
"""
cursor = execute_query(shard, query, (user_id, num_recommendations))
results = cursor.fetchall()

for (product_id,) in results:
product_counts[
product_id
] += 1 # Increment count for searched products

# Aggregate recommendations from past orders and recent searches
recommendations = sorted(
product_counts.items(), key=lambda x: x[1], reverse=True
)[:num_recommendations]
return [product_id for product_id, _ in recommendations]
except Exception as e:
print(f"Error occurred while fetching recommendations: {str(e)}")
return []
Comment on lines +58 to +61

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Broad exception handling and print statement

Catching broad Exception and using print for error handling. Use specific exceptions and proper logging instead.

Code suggestion
Check the AI-generated fix before applying
Suggested change
return [product_id for product_id, _ in recommendations]
except Exception as e:
print(f"Error occurred while fetching recommendations: {str(e)}")
return []
return [product_id for product_id, _ in recommendations]
except (DatabaseError, ConnectionError) as e:
import logging
logging.error(f"Error occurred while fetching recommendations: {e!s}")
return []

Code Review Run #803e49


Should Bito avoid suggestions like this for future reviews? (Manage Rules)

  • Yes, avoid them



recommendation_engine = RecommendationEngine()
Loading