Fix Python 2/3 compatibility issue in base64 decoding

- Replace deprecated .decode("base64") with base64.b64decode() in short_id_to_bytes function
- Add import base64 to meta.py
- Add comprehensive unit tests for short_id_to_bytes and id_to_uuid functions
- Prevents AttributeError: 'str' object has no attribute 'decode' errors
- Resolves bad gateway authentication issues when accessing URLs with short IDs

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Russell Ballestrini 2025-07-27 15:40:04 -04:00
parent 8672802e78
commit b67521936e
2 changed files with 70 additions and 2 deletions

View file

@ -1,4 +1,5 @@
from time import time
import base64
from sqlalchemy import ForeignKey
@ -74,7 +75,7 @@ def short_id_to_bytes(short_id):
'u\xb1\xdeHAK\x11\xe7\xae\xcf\x9cN6\x9cqX'
"""
return (short_id + "==").replace("_", "/").replace("-", "+").decode("base64")
return base64.b64decode((short_id + "==").replace("_", "/").replace("-", "+"))
def id_to_uuid(the_id):

View file

@ -1,9 +1,10 @@
import unittest
import uuid
import mock
from ..models import User, Coupon, Shop, is_user_name_valid
from ..models.meta import now_timestamp
from ..models.meta import now_timestamp, short_id_to_bytes, id_to_uuid
mock_always_none = mock.Mock(return_value=None)
mock_always_true = mock.Mock(return_value=True)
@ -747,3 +748,69 @@ class TestProductS3Security(unittest.TestCase):
self.assertFalse(self.product.is_public)
self.assertFalse(self.product.is_unlisted)
self.assertTrue(self.product.is_private)
class TestMetaFunctions(unittest.TestCase):
"""Test meta.py utility functions for base64 and UUID handling."""
def test_short_id_to_bytes(self):
"""Test short_id_to_bytes function converts base64 strings correctly."""
# Test case from the docstring
result = short_id_to_bytes('dbHeSEFLEeeuz5xONpxxWA')
expected = b'u\xb1\xdeHAK\x11\xe7\xae\xcf\x9cN6\x9cqX'
self.assertEqual(result, expected)
# Test with various base64-encoded strings
test_cases = [
'YWJjZA', # 'abcd' in base64
'dGVzdA', # 'test' in base64
'SGVsbG8', # 'Hello' in base64
]
for test_case in test_cases:
# Should not raise an exception
result = short_id_to_bytes(test_case)
self.assertIsInstance(result, bytes)
def test_id_to_uuid_with_short_id(self):
"""Test id_to_uuid function works with short base64 IDs."""
# Test case from the docstring
result = id_to_uuid('dbHeSEFLEeeuz5xONpxxWA')
expected = uuid.UUID('75b1de48-414b-11e7-aecf-9c4e369c7158')
self.assertEqual(result, expected)
def test_id_to_uuid_with_hex_string(self):
"""Test id_to_uuid function works with hex UUID strings."""
# Test case from the docstring
result = id_to_uuid('75b1de48414b11e7aecf9c4e369c7158')
expected = uuid.UUID('75b1de48-414b-11e7-aecf-9c4e369c7158')
self.assertEqual(result, expected)
def test_id_to_uuid_with_dashed_uuid(self):
"""Test id_to_uuid function works with dashed UUID strings."""
# Test case from the docstring
result = id_to_uuid('75b1de48-414b-11e7-aecf-9c4e369c7158')
expected = uuid.UUID('75b1de48-414b-11e7-aecf-9c4e369c7158')
self.assertEqual(result, expected)
def test_id_to_uuid_with_uuid_object(self):
"""Test id_to_uuid function returns UUID objects unchanged."""
test_uuid = uuid.UUID('75b1de48-414b-11e7-aecf-9c4e369c7158')
result = id_to_uuid(test_uuid)
self.assertEqual(result, test_uuid)
self.assertIs(result, test_uuid) # Should be the same object
def test_id_to_uuid_with_invalid_input(self):
"""Test id_to_uuid function returns None for invalid input."""
result = id_to_uuid('invalid-input')
self.assertIsNone(result)
result = id_to_uuid('')
self.assertIsNone(result)
def test_id_to_uuid_with_none_raises_typeerror(self):
"""Test id_to_uuid function raises TypeError for None input."""
# None input causes TypeError in uuid.UUID, not ValueError,
# so it's not caught by the exception handlers
with self.assertRaises(TypeError):
id_to_uuid(None)