-
Notifications
You must be signed in to change notification settings - Fork 0
/
list.py
334 lines (277 loc) · 13.1 KB
/
list.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
from source import State, main_menu
from helpers import *
from pymysql import DatabaseError
class List:
"""
Represents a List of ingredients and the data associated with it
"""
def __init__(self, l_dict: dict[str,]):
self.id = l_dict.get("list_id")
self.name = l_dict.get("name")
self.date_created = l_dict.get("date_created")
def print_self(self):
print(f"Name: {self.name}")
print(f"Date created: {self.date_created}")
def list_module(state: State):
"""
Top level menu to interact with Lists
"""
clear_screen()
state.print_message_reset()
# Main menu
print_menu("Choose an action", ["View all lists", "Create new list", "Go back"])
choice = get_num_input(1, 3, "Go to")
cur = state.cur
match choice:
case 1:
# View all lists
try:
lists = call_proc(cur, "get_all_lists_for_user", [state.user_id])
except DatabaseError as e:
print(e)
print("Error occurred when trying to fetch all lists")
list_module(state)
return
list_table_data = [row.values() for row in lists]
list_ids = [row.get("list_id") for row in lists]
print_table(["ID", "Name", "Date Created"], list_table_data)
choice = num_input_list_neg_one(
list_ids, "Choose a list ID or -1 to go back"
)
match choice:
case -1:
list_module(state)
return
case _:
l_obj = List(
[row for row in lists if row.get("list_id") == choice][0]
)
list_action(l_obj, state)
case 2:
# Create a new list
name = input("Enter name of new list: ")
try:
list_id = call_proc(cur, "create_list", [name, state.user_id])
except DatabaseError as e:
if e.args[0] == DUPLICATE_CODE:
print("Cannot create a list with a duplicated title")
print("Error creating new list")
list_module(state)
return
finally:
list_id = list_id[0].get("list_id")
print_ingredient_table(cur, state.user_id)
# Loop for adding ingredients to list
while True:
ing_id = safe_num_input(
"Choose an ingredient ID to add to the list or -1 to stop"
)
if ing_id == -1:
break
try:
call_proc(cur, "create_list_item", [ing_id, list_id])
except DatabaseError as e:
if e.args[0] == DUPLICATE_CODE:
print("Duplicate entries are not allowed")
elif e.args[0] == NOT_FOUND_CODE:
print("This ingredient does not exist")
else:
print("Error adding this ingredient to the list")
state.update_message(f"Created new list with ID {list_id}")
list_module(state)
return
case 3:
# Return to the main screen
main_menu(state)
def list_action(list: List, state: State):
"""
Menu to interact with a specific List that is given
"""
clear_screen()
state.print_message_reset()
list.print_self()
try:
items = call_proc(state.cur, "get_ingredients_for_list", [list.id])
except DatabaseError as e:
print(e)
print("Error occurred when trying to fetch ingredients for this list")
item_table_data = [
(row.get("item_id"), row.get("name"), "x" if row.get("completed") == 1 else "")
for row in items
]
# Print a table for the ingredients in the list and their statuses
print_table(["ID", "Item", "Completed"], item_table_data)
print_menu("Select an action", ["Edit", "Delete", "Go back"])
choice = get_num_input(1, 3, "Go to")
match choice:
case 1:
# Edit this list
update_msg = f"Updated list '{list.name}'"
# Loop to execute different actions (edit name, edit items)
while True:
print_menu(
"\nSelect an action",
["Edit list's name", "Edit items in list", "Go back"],
)
choice = get_num_input(1, 3, "Go to")
new_name = list.name
match choice:
case 1:
# Edit the list's name
new_name = input(f"Enter a new name for '{list.name}': ")
try:
call_proc(
state.cur, "update_list_name", [list.id, new_name]
)
except DatabaseError as e:
if e.args[0] == DUPLICATE_CODE:
print("Cannot have duplicate list names")
else:
print(e)
print("Error when trying to update list name")
if " with a different name" not in update_msg:
update_msg += " with a different name"
case 2:
# Edit the items in the list
print_menu(
"\nSelect an action",
["Add items", "Delete items", "Update items", "Go back"],
)
choice = get_num_input(1, 4, "Do")
match choice:
case 1:
# Add items to the list
print_ingredient_table(state.cur, state.user_id)
while True:
ing_id = safe_num_input(
"Choose an ingredient ID to add to the list or -1 to cancel"
)
if ing_id == -1:
break
try:
call_proc(
state.cur,
"create_list_item",
[ing_id, list.id],
)
except DatabaseError as e:
if e.args[0] == DUPLICATE_CODE:
print("Duplicate entries are not allowed")
elif e.args[0] == NOT_FOUND_CODE:
print("This ingredient does not exist")
else:
print(
"Error adding this ingredient to the list"
)
# Ensure the state message is staying up to date
if " with different items" not in update_msg:
update_msg += " with different items"
case 2:
# Delete items from a list
while True:
item_id = safe_num_input(
"Choose an item ID from the list to remove or -1 to cancel"
)
if item_id not in [
row.get("item_id") for row in items
]:
print("Invalid item ID, try again")
continue
if item_id == -1:
break
try:
call_proc(
state.cur,
"remove_item_from_list",
[item_id, list.id],
)
except DatabaseError as e:
if e.args[0] == NOT_FOUND_CODE:
print("Item ID was not found on this list")
else:
print(e)
print("Error removing item from list")
if " with different items" not in update_msg:
update_msg += " with different items"
case 3:
# Update the statuses of items on the list (complete or not)
try:
items = call_proc(
state.cur, "get_ingredients_for_list", [list.id]
)
except DatabaseError as e:
print(e)
print(
"Error occurred when fetching ingredients for this list"
)
item_table_data = [
(
row.get("item_id"),
row.get("name"),
"x" if row.get("completed") == 1 else "",
)
for row in items
]
print_table(
["ID", "Item", "Completed"], item_table_data
)
while True:
item_id = safe_num_input(
"Enter the ID of an item to switch its completeness or -1 to cancel"
)
if item_id == -1:
break
try:
new_status = (
1
if [
row.get("completed") == 0
for row in items
]
else 0
)
call_proc(
state.cur,
"toggle_item_status_in_list",
[item_id, list.id, new_status],
)
except DatabaseError as e:
if e.args[0] == NOT_FOUND_CODE:
print("Item ID not found in this list")
else:
print(e)
print(
"Error occurred when trying to update list item"
)
if " with updated items" not in update_msg:
update_msg += " with updated items"
case 4:
# Return to the top main editing menu
()
case 3:
# Return to main list action menu
break
state.update_message(update_msg)
# Update the properties of the list after editing it
new_list = List(
{
"list_id": list.id,
"name": new_name,
"date_created": list.date_created,
}
)
list_action(new_list, state)
case 2:
# Delete a list
confirm = input(f"Are you sure you want to delete '{list.name}'? Y/N: ")
if confirm == "Y" or confirm == "y":
try:
call_proc(state.cur, "delete_list", [list.id])
except DatabaseError as e:
print(e)
print("Error occurred when trying to delete this list")
state.update_message(f"Deleted list '{list.name}'")
list_module(state)
case 3:
# Return to the top level menu for all lists
list_module(state)