From 7e5ed3428cd8e3cc193ceba7722d1a82c9f1779e Mon Sep 17 00:00:00 2001 From: Russell Ballestrini Date: Thu, 27 Jun 2024 22:48:55 +0000 Subject: [PATCH] validate big ints and floats and flash error to user --- make_post_sell/lib/currency.py | 33 +++++++++++++++++++++++++++ make_post_sell/views/coupon.py | 20 +++++++++++----- make_post_sell/views/product.py | 21 +++++++---------- make_post_sell/views/shop_location.py | 12 ++++++---- 4 files changed, 62 insertions(+), 24 deletions(-) diff --git a/make_post_sell/lib/currency.py b/make_post_sell/lib/currency.py index 2237237..372c59c 100644 --- a/make_post_sell/lib/currency.py +++ b/make_post_sell/lib/currency.py @@ -1,6 +1,39 @@ +# Maximum value for SQLite INTEGER +MAX_INT = 9223372036854775807 + + def dollars_to_cents(dollars): return int(float(dollars) * 100) def cents_to_dollars(cents): return int(cents) / 100.0 + + +def validate_int(value): + try: + value = int(value) + if abs(value) > MAX_INT: + raise ValueError( + f"Value exceeds maximum limit {MAX_INT} for SQLite INTEGER." + ) + return value + except ValueError as e: + raise ValueError(f"Invalid integer value: {e}") from e + except TypeError as e: + raise TypeError(f"Invalid integer type: {e}") from e + + +def validate_float(value): + try: + value = float(value) + value_in_cents = dollars_to_cents(value) + if abs(value_in_cents) > MAX_INT: + raise ValueError( + f"Value exceeds maximum limit {MAX_INT} for SQLite INTEGER." + ) + return value + except ValueError as e: + raise ValueError(f"Invalid float value: {e}") from e + except TypeError as e: + raise TypeError(f"Invalid float type: {e}") from e diff --git a/make_post_sell/views/coupon.py b/make_post_sell/views/coupon.py index 5ef44cf..02280f5 100644 --- a/make_post_sell/views/coupon.py +++ b/make_post_sell/views/coupon.py @@ -17,6 +17,12 @@ from pyramid.httpexceptions import HTTPFound from datetime import datetime, timedelta +from ..lib.currency import ( + validate_int, + validate_float, +) + + # Define the maximum expiration date (10 years from now) MAX_EXPIRATION_DATE = datetime.now() + timedelta(days=365 * 10) @@ -63,14 +69,16 @@ def coupon_new(request): if request.params: # Convert numeric fields to float or integers for validation. try: - action_value = float(action_value) if action_value else None - max_redemptions = int(max_redemptions) if max_redemptions else None + action_value = validate_float(action_value) if action_value else None + max_redemptions = validate_int(max_redemptions) if max_redemptions else None max_redemptions_per_user = ( - int(max_redemptions_per_user) if max_redemptions_per_user else None + validate_int(max_redemptions_per_user) + if max_redemptions_per_user + else None ) - cart_qualifier = float(cart_qualifier) if cart_qualifier else None - except ValueError: - request.session.flash(("Invalid input for numeric fields.", "error")) + cart_qualifier = validate_float(cart_qualifier) if cart_qualifier else None + except Exception as e: + request.session.flash((f"Invalid input for numeric fields. {e}", "error")) return request.params if expiration_date: diff --git a/make_post_sell/views/product.py b/make_post_sell/views/product.py index 23d6cb1..62542c1 100644 --- a/make_post_sell/views/product.py +++ b/make_post_sell/views/product.py @@ -12,7 +12,7 @@ from ..models.product import Product from ..models.shop_location import ShopLocation from ..models.inventory import Inventory -from ..lib.currency import dollars_to_cents +from ..lib.currency import validate_float def checkbox_to_bool(checkbox): @@ -118,10 +118,10 @@ def product_new(request): price_error = False if is_sellable: try: - price = float(price) - except ValueError: + price = validate_float(price) + except Exception as e: price_error = True - msg = ("Please enter a valid number for price.", "error") + msg = (f"Please enter a valid number for price. {e}", "error") request.session.flash(msg) if not price_error: @@ -213,12 +213,10 @@ def product_edit(request): ) try: - price = float(price) - new_price_in_cents = dollars_to_cents(price) - except ValueError: - request.session.flash(("Please only pass numbers for price.", "error")) + price = validate_float(price) + except Exception as e: + request.session.flash((f"Invalid price. {e}", "error")) price = product.price - new_price_in_cents = None s3_webhook_key = request.params.get("key") s3_webhook_bucket = request.params.get("bucket") @@ -239,12 +237,9 @@ def product_edit(request): product.visibility = visibility request.session.flash(("You updated the product's visibility.", "success")) - if new_price_in_cents and new_price_in_cents != product.price_in_cents: + if price != product.price: product_modified = True request.dbsession.add(product.set_price(price)) - - # price is now a float. - price = product.price request.session.flash(("You updated the product's price.", "success")) if s3_webhook_key and s3_webhook_bucket and s3_webhook_etag: diff --git a/make_post_sell/views/shop_location.py b/make_post_sell/views/shop_location.py index 14c5ca3..09ed374 100644 --- a/make_post_sell/views/shop_location.py +++ b/make_post_sell/views/shop_location.py @@ -5,6 +5,8 @@ from . import shop_owner_required from ..models.shop import get_shop_by_id from ..models.shop_location import ShopLocation +from ..lib.currency import validate_float + def checkbox_to_bool(checkbox): return checkbox == "on" @@ -57,11 +59,11 @@ def shop_location_form(request): # Convert numeric fields to appropriate types for validation try: - local_delivery_rate = float(local_delivery_rate) - local_shipping_rate = float(local_shipping_rate) - international_shipping_rate = float(international_shipping_rate) - except ValueError: - request.session.flash(("Invalid input for numeric fields.", "error")) + local_delivery_rate = validate_float(local_delivery_rate) + local_shipping_rate = validate_float(local_shipping_rate) + international_shipping_rate = validate_float(international_shipping_rate) + except Exception as e: + request.session.flash((f"Invalid input for numeric fields. {e}", "error")) return request.params # Check for negative values