Konoha

Finished
1import json
2
13class RestAPI:
24 def __init__(self, database: dict | None = None):
3 pass
4
5 """
6 Initialize the REST API with an optional database.
7
8 Args:
9 database: A dictionary containing initial user data.
10 """
11 if database is None:
12 self.database = {"users": []}
13 else:
14 self.database = database
15
516 def get(self, url: str, payload: str | None = None) -> str:
6 pass
7
17 """
18 Handle GET requests to the API.
19
20 Args:
21 url: The endpoint URL.
22 payload: Optional JSON payload.
23
24 Returns:
25 A JSON string response.
26
27 Raises:
28 ValueError: If the URL is not recognized.
29 """
30 if url == "/users":
31 if payload is None:
32 # Return all users
33 return json.dumps({"users": self._get_all_users()})
34 else:
35 # Return specific users
36 data = json.loads(payload)
37 user_names = data.get("users", [])
38 return json.dumps({"users": self._get_users_by_names(user_names)})
39 else:
40 raise ValueError(f"Unknown URL: {url}")
41
842 def post(self, url: str, payload: str | None = None) -> str:
9 pass
43 """
44 Handle POST requests to the API.
45
46 Args:
47 url: The endpoint URL.
48 payload: JSON payload.
49
50 Returns:
51 A JSON string response.
52
53 Raises:
54 ValueError: If the URL is not recognized or if required data is missing.
55 """
56 if url == "/add":
57 if payload is None:
58 raise ValueError("Payload is required for /add endpoint")
59
60 data = json.loads(payload)
61 user_name = data.get("user")
62
63 # Edge Case: Missing user name in payload
64 if user_name is None:
65 raise ValueError("User name is required")
66
67 # Edge Case: User already exists
68 if self._find_user(user_name) is not None:
69 raise ValueError(f"User {user_name} already exists")
70
71 new_user = {
72 "name": user_name,
73 "owes": {},
74 "owed_by": {},
75 "balance": 0.0
76 }
77
78 self.database["users"].append(new_user)
79
80 return json.dumps(new_user)
81
82 elif url == "/iou":
83 if payload is None:
84 raise ValueError("Payload is required for /iou endpoint")
85
86 data = json.loads(payload)
87 lender_name = data.get("lender")
88 borrower_name = data.get("borrower")
89 amount = data.get("amount")
90
91 # Edge Case: Missing required fields
92 if lender_name is None or borrower_name is None or amount is None:
93 raise ValueError("Lender, borrower, and amount are required")
94
95 # Edge Case: Lender and borrower are the same person
96 if lender_name == borrower_name:
97 raise ValueError("Lender and borrower cannot be the same person")
98
99 # Edge Case: Negative amount
100 if amount < 0:
101 raise ValueError("Amount must be non-negative")
102
103 lender = self._find_user(lender_name)
104 borrower = self._find_user(borrower_name)
105
106 # Edge Case: Lender or borrower does not exist
107 if lender is None:
108 raise ValueError(f"User {lender_name} does not exist")
109 if borrower is None:
110 raise ValueError(f"User {borrower_name} does not exist")
111
112 # Update lender's owed_by
113 if borrower_name in lender["owed_by"]:
114 lender["owed_by"][borrower_name] += amount
115 else:
116 lender["owed_by"][borrower_name] = amount
117
118 # Update borrower's owes
119 if lender_name in borrower["owes"]:
120 borrower["owes"][lender_name] += amount
121 else:
122 borrower["owes"][lender_name] = amount
123
124 # Update balances
125 lender["balance"] += amount
126 borrower["balance"] -= amount
127
128 # Simplify debts if they owe each other
129 self._simplify_debts(lender, borrower)
130
131 # Return updated users
132 users = [lender, borrower]
133 users.sort(key=lambda u: u["name"])
134 return json.dumps({"users": users})
135
136 else:
137 raise ValueError(f"Unknown URL: {url}")
138
139 def _find_user(self, name: str):
140 """
141 Find a user by name in the database.
142
143 Args:
144 name: The name of the user to find.
145
146 Returns:
147 The user dictionary if found, None otherwise.
148 """
149 for user in self.database["users"]:
150 if user["name"] == name:
151 return user
152 return None
153
154 def _get_all_users(self):
155 """
156 Get all users from the database, sorted by name.
157
158 Returns:
159 A list of all user dictionaries, sorted by name.
160 """
161 return sorted(self.database["users"], key=lambda u: u["name"])
162
163 def _get_users_by_names(self, names):
164 """
165 Get specific users by their names.
166
167 Args:
168 names: A list of user names.
169
170 Returns:
171 A list of user dictionaries for the specified names, sorted by name.
172 """
173 users = []
174 for name in names:
175 user = self._find_user(name)
176 # Edge Case: Requested user does not exist
177 if user is not None:
178 users.append(user)
179 return sorted(users, key=lambda u: u["name"])
180
181 def _simplify_debts(self, user1, user2):
182 """
183 Simplify debts between two users if they owe each other.
184
185 Args:
186 user1: First user dictionary.
187 user2: Second user dictionary.
188 """
189 name1 = user1["name"]
190 name2 = user2["name"]
191
192 # Check if they owe each other
193 owes1to2 = user1["owes"].get(name2, 0)
194 owes2to1 = user2["owes"].get(name1, 0)
195
196 if owes1to2 > 0 and owes2to1 > 0:
197 # They owe each other, simplify
198 if owes1to2 > owes2to1:
199 # user1 owes more to user2 than user2 owes to user1
200 user1["owes"][name2] = owes1to2 - owes2to1
201 del user2["owes"][name1]
202
203 user2["owed_by"][name1] = owes1to2 - owes2to1
204 del user1["owed_by"][name2]
205 elif owes2to1 > owes1to2:
206 # user2 owes more to user1 than user1 owes to user2
207 user2["owes"][name1] = owes2to1 - owes1to2
208 del user1["owes"][name2]
209
210 user1["owed_by"][name2] = owes2to1 - owes1to2
211 del user2["owed_by"][name1]
212 else:
213 # They owe exactly the same amount
214 del user1["owes"][name2]
215 del user2["owes"][name1]
216 del user1["owed_by"][name2]
217 del user2["owed_by"][name1]
218
219 # Remove zero debts
220 if user1["owes"].get(name2, 0) == 0 and name2 in user1["owes"]:
221 del user1["owes"][name2]
222 if user2["owes"].get(name1, 0) == 0 and name1 in user2["owes"]:
223 del user2["owes"][name1]
224 if user1["owed_by"].get(name2, 0) == 0 and name2 in user1["owed_by"]:
225 del user1["owed_by"][name2]
226 if user2["owed_by"].get(name1, 0) == 0 and name1 in user2["owed_by"]:
227 del user2["owed_by"][name1]
228
229 # Handled Edge Cases: Missing user name in payload, User already exists, Missing required fields,
230 # Lender and borrower are the same person, Negative amount, Lender or borrower does not exist,
231 # Requested user does not exist
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.