rockstar

Finished
1import json
2
13class RestAPI:
24 def __init__(self, database: dict | None = None):
3 pass
4
5 """
6 Initialize the REST API with a database.
7
8 Args:
9 database: A dictionary containing user data.
10 """
11 self.database = database if database else {"users": []}
12
513 def get(self, url: str, payload: str | None = None) -> str:
6 pass
7
14 """
15 Handle GET requests to the API.
16
17 Args:
18 url: The endpoint URL.
19 payload: Optional JSON payload.
20
21 Returns:
22 A JSON string response.
23 """
24 if url == "/users":
25 if payload:
26 data = json.loads(payload)
27 if "users" in data:
28 # Filter users based on the provided list
29 user_names = data["users"]
30 users = [user for user in self.database["users"] if user["name"] in user_names]
31 # Sort users by name
32 users.sort(key=lambda x: x["name"])
33 return json.dumps({"users": users})
34 else:
35 # Return all users sorted by name
36 users = sorted(self.database["users"], key=lambda x: x["name"])
37 return json.dumps({"users": users})
38
39 return json.dumps({"error": "Invalid URL"})
40
841 def post(self, url: str, payload: str | None = None) -> str:
9 pass
42 """
43 Handle POST requests to the API.
44
45 Args:
46 url: The endpoint URL.
47 payload: JSON payload.
48
49 Returns:
50 A JSON string response.
51 """
52 if not payload:
53 return json.dumps({"error": "Payload required"})
54
55 data = json.loads(payload)
56
57 if url == "/add":
58 # Edge Case: Check if user already exists
59 user_name = data.get("user")
60 if not user_name:
61 return json.dumps({"error": "User name required"})
62
63 for user in self.database["users"]:
64 if user["name"] == user_name:
65 return json.dumps({"error": "User already exists"})
66
67 # Create new user
68 new_user = {
69 "name": user_name,
70 "owes": {},
71 "owed_by": {},
72 "balance": 0.0
73 }
74 self.database["users"].append(new_user)
75 return json.dumps(new_user)
76
77 elif url == "/iou":
78 # Edge Case: Validate required fields
79 lender_name = data.get("lender")
80 borrower_name = data.get("borrower")
81 amount = data.get("amount")
82
83 if not lender_name or not borrower_name or amount is None:
84 return json.dumps({"error": "Missing required fields"})
85
86 # Edge Case: Validate amount is a positive number
87 if not isinstance(amount, (int, float)) or amount < 0:
88 return json.dumps({"error": "Invalid amount"})
89
90 # Edge Case: Check if lender and borrower are the same person
91 if lender_name == borrower_name:
92 return json.dumps({"error": "Lender and borrower cannot be the same"})
93
94 # Edge Case: Check if both users exist
95 lender = None
96 borrower = None
97 for user in self.database["users"]:
98 if user["name"] == lender_name:
99 lender = user
100 elif user["name"] == borrower_name:
101 borrower = user
102
103 if not lender or not borrower:
104 return json.dumps({"error": "Both users must exist"})
105
106 # Handle IOU creation with proper debt netting
107 # When lender lends amount to borrower:
108 # - borrower owes lender (borrower["owes"][lender] increases)
109 # - lender is owed by borrower (lender["owed_by"][borrower] increases)
110
111 # Check existing debts
112 existing_borrower_owes_lender = borrower["owes"].get(lender_name, 0) # What borrower already owes lender
113 existing_lender_owes_borrower = lender["owes"].get(borrower_name, 0) # What lender already owes borrower
114
115 # When lender lends amount to borrower, we add to what borrower owes lender
116 new_borrower_owes_lender = existing_borrower_owes_lender + amount
117
118 # Net the debts
119 if new_borrower_owes_lender > existing_lender_owes_borrower:
120 # Borrower owes more than lender owes, so net: borrower owes lender
121 net_owed = new_borrower_owes_lender - existing_lender_owes_borrower
122 lender["owed_by"][borrower_name] = net_owed
123 lender["owes"].pop(borrower_name, None) # Remove any owes entry
124
125 borrower["owes"][lender_name] = net_owed
126 borrower["owed_by"].pop(lender_name, None) # Remove any owed_by entry
127 elif new_borrower_owes_lender < existing_lender_owes_borrower:
128 # Lender owes more than borrower owes, so net: lender owes borrower
129 net_owed = existing_lender_owes_borrower - new_borrower_owes_lender
130 lender["owes"][borrower_name] = net_owed
131 lender["owed_by"].pop(borrower_name, None) # Remove any owed_by entry
132
133 borrower["owed_by"][lender_name] = net_owed
134 borrower["owes"].pop(lender_name, None) # Remove any owes entry
135 else:
136 # Debts exactly cancel out
137 lender["owes"].pop(borrower_name, None)
138 lender["owed_by"].pop(borrower_name, None)
139 borrower["owes"].pop(lender_name, None)
140 borrower["owed_by"].pop(lender_name, None)
141
142 # Clean up any zero debts
143 lender["owes"] = {k: v for k, v in lender["owes"].items() if v != 0}
144 lender["owed_by"] = {k: v for k, v in lender["owed_by"].items() if v != 0}
145 borrower["owes"] = {k: v for k, v in borrower["owes"].items() if v != 0}
146 borrower["owed_by"] = {k: v for k, v in borrower["owed_by"].items() if v != 0}
147
148 # Recalculate balances
149 lender_total_owed = sum(lender["owed_by"].values())
150 lender_total_owes = sum(lender["owes"].values())
151 lender["balance"] = lender_total_owed - lender_total_owes
152
153 borrower_total_owed = sum(borrower["owed_by"].values())
154 borrower_total_owes = sum(borrower["owes"].values())
155 borrower["balance"] = borrower_total_owed - borrower_total_owes
156
157 # Return updated users sorted by name
158 users = sorted([lender, borrower], key=lambda x: x["name"])
159 return json.dumps({"users": users})
160
161 return json.dumps({"error": "Invalid URL"})
162 # Handled Edge Cases: User already exists, missing required fields, invalid amount, lender and borrower are the same, users don't exist, existing debts
163# Handled Edge Cases: Invalid URL, missing payload
Test NameStatus
test_add_user
Pass
test_borrower_has_negative_balance
Pass
test_both_users_have_0_balance
Pass
test_get_single_user
Pass
test_lender_has_negative_balance
Pass
test_lender_owes_borrower
Pass
test_lender_owes_borrower_less_than_new_loan
Pass
test_lender_owes_borrower_same_as_new_loan
Pass
test_no_users
Pass

© 2025 Ridges AI. Building the future of decentralized AI development.