source: uc_browse.py

main
Last change on this file was 95cf703, checked in by teo <teodorbogoeski@…>, 4 months ago

Initial commit: FRRUAS CLI prototype

  • Property mode set to 100644
File size: 6.9 KB
Line 
1import datetime
2
3from db import get_connection, pick_from_list, print_table, input_date, input_time
4
5
6def browse_resources():
7 """UC0001: Browse Available Resources."""
8 type_filter = None
9 building_filter = None
10
11 while True:
12 resources = _fetch_resources(type_filter, building_filter)
13
14 filters_active = []
15 if type_filter:
16 filters_active.append(f"Type: {type_filter}")
17 if building_filter:
18 filters_active.append(f"Building: {building_filter}")
19
20 print(f"\n=== Browse Resources ({len(resources)} found) ===")
21 if filters_active:
22 print(f" Active filters: {', '.join(filters_active)}")
23 print()
24
25 for i, r in enumerate(resources, start=1):
26 loc = f"{r['building']} / {r['room']}" if r["building"] else "Digital"
27 print(f" {i:>3}. {r['name']} [{r['type_name']}] - {loc}")
28
29 print()
30 options = [
31 "Filter by Resource Type",
32 "Filter by Building",
33 "View Resource Details",
34 "Check Availability for a Time Slot",
35 "Clear Filters",
36 ]
37 idx = pick_from_list(" Choose an option: ", options)
38 if idx is None:
39 return
40
41 if idx == 0:
42 type_filter = _select_type_filter()
43 elif idx == 1:
44 building_filter = _select_building_filter()
45 elif idx == 2:
46 _view_details(resources)
47 elif idx == 3:
48 _check_availability(resources)
49 elif idx == 4:
50 type_filter = None
51 building_filter = None
52 print(" Filters cleared.")
53
54
55def _fetch_resources(type_filter=None, building_filter=None):
56 query = """
57 SELECT r.resource_id, r.name, r.description,
58 r.available_from, r.available_to, r.available_weekends,
59 rt.type_name, rt.is_physical,
60 l.building, l.room
61 FROM resources r
62 JOIN resource_types rt ON r.type_id = rt.type_id
63 LEFT JOIN locations l ON r.location_id = l.location_id
64 WHERE TRUE
65 """
66 params = []
67 if type_filter:
68 query += " AND rt.type_name = %s"
69 params.append(type_filter)
70 if building_filter:
71 query += " AND l.building = %s"
72 params.append(building_filter)
73 query += " ORDER BY rt.type_name, r.name"
74
75 with get_connection() as conn:
76 with conn.cursor() as cur:
77 cur.execute(query, params)
78 cols = [desc[0] for desc in cur.description]
79 return [dict(zip(cols, row)) for row in cur.fetchall()]
80
81
82def _select_type_filter():
83 with get_connection() as conn:
84 with conn.cursor() as cur:
85 cur.execute("SELECT type_name FROM resource_types ORDER BY type_name")
86 types = [row[0] for row in cur.fetchall()]
87 print("\n Select resource type:")
88 idx = pick_from_list(" Choose: ", types)
89 return types[idx] if idx is not None else None
90
91
92def _select_building_filter():
93 with get_connection() as conn:
94 with conn.cursor() as cur:
95 cur.execute("SELECT DISTINCT building FROM locations ORDER BY building")
96 buildings = [row[0] for row in cur.fetchall()]
97 print("\n Select building:")
98 idx = pick_from_list(" Choose: ", buildings)
99 return buildings[idx] if idx is not None else None
100
101
102def _view_details(resources):
103 if not resources:
104 print(" No resources to show.")
105 return
106 print("\n Select a resource to view details:")
107 items = [r["name"] for r in resources]
108 idx = pick_from_list(" Choose: ", items)
109 if idx is None:
110 return
111
112 r = resources[idx]
113 print(f"\n === {r['name']} ===")
114 print(f" Type: {r['type_name']}")
115 print(f" Description: {r['description']}")
116 if r["building"]:
117 print(f" Location: {r['building']} / {r['room']}")
118 else:
119 print(f" Location: Digital (no physical location)")
120 print(f" Available: {r['available_from'].strftime('%H:%M')} - {r['available_to'].strftime('%H:%M')}")
121 print(f" Weekends: {'Yes' if r['available_weekends'] else 'No'}")
122
123 with get_connection() as conn:
124 with conn.cursor() as cur:
125 cur.execute(
126 """
127 SELECT res.start_time, res.end_time, res.status, res.purpose
128 FROM reservations res
129 WHERE res.resource_id = %s
130 AND res.status IN ('approved', 'pending')
131 AND res.end_time > CURRENT_TIMESTAMP
132 ORDER BY res.start_time
133 """,
134 (r["resource_id"],),
135 )
136 reservations = cur.fetchall()
137
138 if reservations:
139 print(f"\n Upcoming reservations:")
140 print_table(
141 ["Start", "End", "Status", "Purpose"],
142 [
143 (
144 row[0].strftime("%Y-%m-%d %H:%M"),
145 row[1].strftime("%Y-%m-%d %H:%M"),
146 row[2],
147 row[3][:40],
148 )
149 for row in reservations
150 ],
151 )
152 else:
153 print("\n No upcoming reservations.")
154
155
156def _check_availability(resources):
157 if not resources:
158 print(" No resources to check.")
159 return
160 print("\n Select a resource to check availability:")
161 items = [r["name"] for r in resources]
162 idx = pick_from_list(" Choose: ", items)
163 if idx is None:
164 return
165
166 r = resources[idx]
167 date = input_date(" Date (YYYY-MM-DD): ")
168 start = input_time(" Start time (HH:MM): ")
169 end = input_time(" End time (HH:MM): ")
170
171 if end <= start:
172 print(" End time must be after start time.")
173 return
174
175 # Check availability window
176 day_of_week = date.isoweekday() # 1=Mon, 7=Sun
177 if day_of_week > 5 and not r["available_weekends"]:
178 print(f"\n NOT AVAILABLE: {r['name']} is not available on weekends.")
179 return
180 if start < r["available_from"] or end > r["available_to"]:
181 print(
182 f"\n NOT AVAILABLE: {r['name']} is only available "
183 f"{r['available_from'].strftime('%H:%M')} - {r['available_to'].strftime('%H:%M')}."
184 )
185 return
186
187 # Check conflicts
188 start_dt = datetime.datetime.combine(date, start)
189 end_dt = datetime.datetime.combine(date, end)
190
191 with get_connection() as conn:
192 with conn.cursor() as cur:
193 cur.execute(
194 """
195 SELECT COUNT(*) FROM reservations
196 WHERE resource_id = %s
197 AND status IN ('approved', 'pending')
198 AND start_time < %s
199 AND end_time > %s
200 """,
201 (r["resource_id"], end_dt, start_dt),
202 )
203 conflicts = cur.fetchone()[0]
204
205 if conflicts == 0:
206 print(f"\n AVAILABLE: {r['name']} is free on {date} from {start.strftime('%H:%M')} to {end.strftime('%H:%M')}.")
207 else:
208 print(f"\n NOT AVAILABLE: {conflicts} conflicting reservation(s) found.")
Note: See TracBrowser for help on using the repository browser.