@@ -25,40 +25,76 @@ def manage_estimated_locations(device_pk, ip_address, add_existing=False):
2525 - A new location is created if no location exists for current device, or
2626 existing one is updated using coords from WHOIS record if it is estimated (fuzzy).
2727 """
28+ Device = load_model ("config" , "Device" )
29+ Location = load_model ("geo" , "Location" )
30+ WHOISInfo = load_model ("config" , "WHOISInfo" )
31+ DeviceLocation = load_model ("geo" , "DeviceLocation" )
32+
33+ def _create_estimated_location (device_location , location_defaults ):
34+ with transaction .atomic ():
35+ location = Location (** location_defaults , is_estimated = True )
36+ location .full_clean ()
37+ location .save ()
38+ device_location .location = location
39+ device_location .full_clean ()
40+ device_location .save ()
41+ logger .info (
42+ f"Estimated location saved successfully for { device_pk } "
43+ f" for IP: { ip_address } "
44+ )
2845
29- def _update_or_create_estimated_location (device_location , whois_obj ):
46+ def _update_or_create_estimated_location (
47+ device_location , whois_obj , attached_devices_exists = False
48+ ):
3049 # Used to update an existing location if it is estimated
3150 # or create a new one if it doesn't exist
32- location_defaults = {
33- ** whois_obj ._get_defaults_for_estimated_location (),
34- "organization_id" : device .organization_id ,
35- }
36- if current_location and current_location .is_estimated :
37- for attr , value in location_defaults .items ():
38- setattr (current_location , attr , value )
39- current_location .full_clean ()
40- current_location .save ()
41- elif not current_location :
42- with transaction .atomic ():
43- location = Location (** location_defaults , is_estimated = True )
44- location .full_clean ()
45- location .save ()
46- device_location .location = location
47- device_location .full_clean ()
48- device_location .save ()
51+ if whois_obj and whois_obj .coordinates :
52+ location_defaults = {
53+ ** whois_obj ._get_defaults_for_estimated_location (),
54+ "organization_id" : device .organization_id ,
55+ }
56+ if current_location and current_location .is_estimated :
57+ if attached_devices_exists :
58+ # If there are other devices attached to the current location,
59+ # we do not update it, but create a new one.
60+ _create_estimated_location (device_location , location_defaults )
61+ return
62+ updated = False
63+ for attr , value in location_defaults .items ():
64+ if getattr (current_location , attr ) != value :
65+ setattr (current_location , attr , value )
66+ updated = True
67+ if updated :
68+ current_location .full_clean ()
69+ current_location .save ()
70+ logger .info (
71+ f"Estimated location saved successfully for { device_pk } "
72+ f" for IP: { ip_address } "
73+ )
74+ elif not current_location :
75+ # If there is no current location, we create a new one.
76+ _create_estimated_location (device_location , location_defaults )
77+ else :
78+ logger .warning (
79+ f"Coordinates not available for { device_pk } for IP: { ip_address } ."
80+ " Estimated location cannot be determined."
81+ )
82+ return
4983
50- def _handle_attach_existing_location (device , device_location , whois_obj ):
84+ def _handle_attach_existing_location (
85+ device , device_location , whois_obj , attached_devices_exists = False
86+ ):
5187 # For handling the case when WHOIS already exists for device's new last_ip
5288 # then we attach the location of the device with same last_ip if it exists.
53- existing_devices_location = (
89+ devices_with_location = (
5490 Device .objects .select_related ("devicelocation" )
5591 .filter (organization_id = device .organization_id )
5692 .filter (last_ip = ip_address , devicelocation__location__isnull = False )
5793 .exclude (pk = device_pk )
5894 )
5995 # If there are multiple devices with same last_ip then we need to inform
6096 # the user to resolve the conflict manually.
61- if existing_devices_location .count () > 1 :
97+ if devices_with_location .count () > 1 :
6298 send_whois_task_notification (
6399 device_pk = device_pk , notify_type = "location_error"
64100 )
@@ -67,44 +103,46 @@ def _handle_attach_existing_location(device, device_location, whois_obj):
67103 f"last_ip { ip_address } . Please resolve the conflict manually."
68104 )
69105 return
106+ first_device = devices_with_location .first ()
70107 # If existing devices with same last_ip do not have any location
71108 # then we create a new location based on WHOIS data.
72- if existing_devices_location .count () == 0 :
73- _update_or_create_estimated_location (device_location , whois_obj )
109+ if not first_device :
110+ _update_or_create_estimated_location (
111+ device_location , whois_obj , attached_devices_exists
112+ )
74113 return
75- existing_location = existing_devices_location . first () .devicelocation .location
114+ existing_location = first_device .devicelocation .location
76115 # We need to remove any existing estimated location of the device
77- if current_location and current_location . pk != existing_location . pk :
116+ if current_location and not attached_devices_exists :
78117 current_location .delete ()
79118 device_location .location = existing_location
80119 device_location .full_clean ()
81120 device_location .save ()
121+ logger .info (
122+ f"Estimated location saved successfully for { device_pk } "
123+ f" for IP: { ip_address } "
124+ )
82125
83- Device = load_model ("config" , "Device" )
84- Location = load_model ("geo" , "Location" )
85- WHOISInfo = load_model ("config" , "WHOISInfo" )
86- DeviceLocation = load_model ("geo" , "DeviceLocation" )
87-
88- device = Device .objects .get (pk = device_pk )
89126 whois_obj = WHOISInfo .objects .filter (ip_address = ip_address ).first ()
127+ device = Device .objects .get (pk = device_pk )
90128 device_location , _ = DeviceLocation .objects .select_related (
91129 "location"
92130 ).get_or_create (content_object_id = device_pk )
93- current_location = device_location .location
94131
95- if add_existing and (not current_location or current_location .is_estimated ):
96- _handle_attach_existing_location (device , device_location , whois_obj )
132+ attached_devices_exists = False
133+ if current_location := device_location .location :
134+ attached_devices_exists = (
135+ Device .objects .filter (devicelocation__location_id = current_location .pk )
136+ .exclude (pk = device_pk )
137+ .exists ()
138+ )
97139
98- elif whois_obj and whois_obj .coordinates :
99- _update_or_create_estimated_location (device_location , whois_obj )
140+ if add_existing and (not current_location or current_location .is_estimated ):
141+ _handle_attach_existing_location (
142+ device , device_location , whois_obj , attached_devices_exists
143+ )
100144
101145 else :
102- logger .warning (
103- f"Coordinates not available for { device_pk } for IP: { ip_address } ."
104- " Estimated location cannot be determined."
146+ _update_or_create_estimated_location (
147+ device_location , whois_obj , attached_devices_exists
105148 )
106- return
107-
108- logger .info (
109- f"Estimated location saved successfully for { device_pk } for IP: { ip_address } "
110- )
0 commit comments