11import logging
22from datetime import datetime , timedelta , timezone
3- from typing import List , Optional
3+ from typing import List , Optional , Tuple
44from fastapi import FastAPI , Depends , HTTPException , Query
55from contextlib import asynccontextmanager
66from sqlalchemy .orm import Session
@@ -161,6 +161,29 @@ async def lifespan(app: FastAPI):
161161 lifespan = lifespan ,
162162)
163163
164+ def parse_location (location : str ) -> Tuple [Optional [str ], Optional [str ]]:
165+ """
166+ Parse location string to extract building and floor names.
167+ Returns (building_name, floor_name) tuple.
168+ """
169+ if not location or not isinstance (location , str ):
170+ logger .warning (f"Skipping device with empty or invalid location: { location } " )
171+ return None , None
172+
173+ parts = [p .strip () for p in location .split ('/' ) if p .strip ()]
174+ # Global/Keele Campus/<Building>/<Floor...>
175+ if len (parts ) >= 4 and parts [0 ] == "Global" and parts [1 ] == "Keele Campus" :
176+ building = parts [2 ]
177+ floor = parts [3 ]
178+ return building , floor
179+ # <Building>/<Floor...>
180+ if len (parts ) >= 2 :
181+ building = parts [0 ]
182+ floor = parts [1 ]
183+ return building , floor
184+ logger .warning (f"Skipping device with invalid location format: { location } " )
185+ return None , None
186+
164187def update_ap_data_task (db : Session = None , auth_manager_obj = None , fetch_ap_data_func = None ):
165188 """Background task to update AP data in the database."""
166189 auth_manager_obj = auth_manager_obj or auth_manager
@@ -180,23 +203,16 @@ def update_ap_data_task(db: Session = None, auth_manager_obj=None, fetch_ap_data
180203 # Process AP data
181204 for ap in aps :
182205 ap_name = ap .get ('name' )
183- location = ap .get ('location' , '' )
184- location_parts = location .split ('/' ) if location else []
185206
186- # Handle location parsing based on real data format
187- if not location_parts :
188- logger .warning (f"Skipping device { ap_name } due to invalid location format: { location } " )
189- continue
190-
191- # Extract building and floor from location
192- if len (location_parts ) >= 5 :
193- building_name = location_parts [2 ] # e.g., "Bethune Residence"
194- floor_name = location_parts [3 ] # e.g., "Floor 5"
195- elif len (location_parts ) == 2 :
196- building_name = location_parts [0 ]
197- floor_name = location_parts [1 ]
198- else :
199- logger .warning (f"Skipping device { ap_name } due to invalid location format: { location } " )
207+ # Try different location fields in order of preference
208+ location = ap .get ('location' )
209+ if not location or len (location .split ('/' )) < 2 :
210+ location = ap .get ('snmpLocation' )
211+ if not location or len (location .split ('/' )) < 2 :
212+ location = ap .get ('locationName' )
213+
214+ building_name , floor_name = parse_location (location )
215+ if not building_name or not floor_name :
200216 continue
201217
202218 # Building
@@ -303,39 +319,32 @@ def update_client_count_task(db: Session = None, auth_manager_obj=None, fetch_cl
303319 # Process AP data for apclientcount DB
304320 for ap in ap_data :
305321 ap_name = ap .get ('name' )
306- location = ap .get ('location' , '' )
307- location_parts = location .split ('/' ) if location else []
308322
309- # Handle location parsing based on real data format
310- if not location_parts :
311- logger .warning (f"Skipping device { ap_name } due to invalid location format: { location } " )
312- continue
313-
314- # Extract building and floor from location
315- if len (location_parts ) >= 5 :
316- building_name = location_parts [3 ] # e.g., "Keele Campus"
317- floor_name = location_parts [4 ] # e.g., "Floor 5"
318- elif len (location_parts ) == 2 :
319- building_name = location_parts [0 ]
320- floor_name = location_parts [1 ]
321- else :
322- logger .warning (f"Skipping device { ap_name } due to invalid location format: { location } " )
323+ # Try different location fields in order of preference
324+ location = ap .get ('location' )
325+ if not location or len (location .split ('/' )) < 2 :
326+ location = ap .get ('snmpLocation' )
327+ if not location or len (location .split ('/' )) < 2 :
328+ location = ap .get ('locationName' )
329+
330+ building_name , floor_name = parse_location (location )
331+ if not building_name or not floor_name :
323332 continue
324-
333+
325334 # Building
326- building = db .query (ApBuilding ).filter_by (building_name = building_name ).first ()
335+ building = db .query (ApBuilding ).filter_by (buildingname = building_name ).first ()
327336 if not building :
328- building = ApBuilding (building_name = building_name )
337+ building = ApBuilding (buildingname = building_name )
329338 db .add (building )
330339 db .flush ()
331-
340+
332341 # Floor
333- floor = db .query (Floor ).filter_by (floorname = floor_name , building_id = building .building_id ).first ()
342+ floor = db .query (Floor ).filter_by (floorname = floor_name , buildingid = building .buildingid ).first ()
334343 if not floor :
335- floor = Floor (floorname = floor_name , building_id = building .building_id )
344+ floor = Floor (floorname = floor_name , buildingid = building .buildingid )
336345 db .add (floor )
337346 db .flush ()
338-
347+
339348 # Access Point
340349 mac_address = ap .get ('macAddress' )
341350 ap_record = db .query (AccessPoint ).filter_by (macaddress = mac_address ).first ()
@@ -350,15 +359,15 @@ def update_client_count_task(db: Session = None, auth_manager_obj=None, fetch_cl
350359 modelname = ap .get ('model' ),
351360 isactive = is_active ,
352361 floorid = floor .floorid ,
353- building_id = building .building_id
362+ buildingid = building .buildingid
354363 )
355364 db .add (ap_record )
356365 db .flush ()
357366 else :
358367 logger .debug (f"Updating existing AccessPoint: { ap .get ('name' )} " )
359368 ap_record .isactive = is_active
360369 ap_record .floorid = floor .floorid
361- ap_record .building_id = building .building_id
370+ ap_record .buildingid = building .buildingid
362371
363372 # Create client count records for each radio
364373 client_counts = ap .get ('clientCount' , {})
@@ -412,17 +421,17 @@ def insert_apclientcount_data(device_info_list, timestamp, session=None):
412421
413422 try :
414423 for device_info in device_info_list :
415- # Parse location
416- location = device_info .get ("location" , "" )
417- location_parts = location .split ("/" )
424+ ap_name = device_info .get ('name' )
418425
419- # Determine building name based on location format
420- if len (location_parts ) >= 3 :
421- building_name = location_parts [2 ] # e.g., "Bethune Residence"
422- elif len (location_parts ) == 2 :
423- building_name = location_parts [0 ]
424- else :
425- logger .warning (f"Skipping device { device_info .get ('name' )} due to invalid location format: { location } " )
426+ # Try different location fields in order of preference
427+ location = device_info .get ('location' )
428+ if not location or len (location .split ('/' )) < 2 :
429+ location = device_info .get ('snmpLocation' )
430+ if not location or len (location .split ('/' )) < 2 :
431+ location = device_info .get ('locationName' )
432+
433+ building_name , floor_name = parse_location (location )
434+ if not building_name or not floor_name :
426435 continue
427436
428437 # Get or create building
@@ -433,15 +442,17 @@ def insert_apclientcount_data(device_info_list, timestamp, session=None):
433442 session .commit ()
434443
435444 # Get or create floor
436- floor_name = location_parts [3 ] if len (location_parts ) >= 4 else "Unknown Floor"
437445 floor = session .query (Floor ).filter_by (buildingid = building .buildingid , floorname = floor_name ).first ()
438446 if not floor :
439447 floor = Floor (buildingid = building .buildingid , floorname = floor_name )
440448 session .add (floor )
441449 session .commit ()
442450
443- # Get or create room
444- room_name = location_parts [4 ] if len (location_parts ) >= 5 else "Unknown Room"
451+ # Get or create room (optional)
452+ room_name = "Unknown Room" # Default room name
453+ if location and len (location .split ('/' )) > 4 :
454+ room_name = location .split ('/' )[4 ].strip ()
455+
445456 room = session .query (Room ).filter_by (floorid = floor .floorid , roomname = room_name ).first ()
446457 if not room :
447458 room = Room (floorid = floor .floorid , roomname = room_name )
0 commit comments