|
2 | 2 |
|
3 | 3 | import requests
|
4 | 4 | from celery import shared_task
|
| 5 | +from django.contrib.gis.geos import Point |
5 | 6 | from django.utils.translation import gettext as _
|
6 | 7 | from geoip2 import errors
|
7 | 8 | from geoip2 import webservice as geoip2_webservice
|
@@ -158,3 +159,72 @@ def delete_whois_record(ip_address):
|
158 | 159 | queryset = WHOISInfo.objects.filter(ip_address=ip_address)
|
159 | 160 | if queryset.exists():
|
160 | 161 | queryset.delete()
|
| 162 | + |
| 163 | + |
| 164 | +@shared_task |
| 165 | +def manage_fuzzy_locations( |
| 166 | + device_pk, |
| 167 | + ip_address, |
| 168 | + latitude=None, |
| 169 | + longitude=None, |
| 170 | + address=None, |
| 171 | + add_existing=False, |
| 172 | +): |
| 173 | + """ |
| 174 | + Creates/updates fuzzy location for a device based on the latitude and longitude |
| 175 | + or attaches an existing location if `add_existing` is True. |
| 176 | + Existing location here means a location of a device whose last_ip matches |
| 177 | + the given ip_address. |
| 178 | + """ |
| 179 | + Device = load_model("config", "Device") |
| 180 | + Location = load_model("geo", "Location") |
| 181 | + DeviceLocation = load_model("geo", "DeviceLocation") |
| 182 | + |
| 183 | + device_location = ( |
| 184 | + DeviceLocation.objects.filter(content_object_id=device_pk) |
| 185 | + .select_related("location") |
| 186 | + .first() |
| 187 | + ) |
| 188 | + |
| 189 | + if not device_location: |
| 190 | + device_location = DeviceLocation(content_object_id=device_pk) |
| 191 | + |
| 192 | + # if attaching an existing location, the current device should not have |
| 193 | + # a location already set. |
| 194 | + # TODO: Do we do this if device location exists but is marked fuzzy? |
| 195 | + if add_existing and not device_location.location: |
| 196 | + existing_device_with_location = ( |
| 197 | + Device.objects.select_related("device_location") |
| 198 | + .filter(last_ip=ip_address, device_location__location__isnull=False) |
| 199 | + .first() |
| 200 | + ) |
| 201 | + if existing_device_with_location: |
| 202 | + location = existing_device_with_location.device_location.location |
| 203 | + device_location.location = location |
| 204 | + device_location.full_clean() |
| 205 | + device_location.save() |
| 206 | + elif latitude and longitude: |
| 207 | + device = Device.objects.get(pk=device_pk) |
| 208 | + coords = Point(longitude, latitude, srid=4326) |
| 209 | + # Create/update the device location mapping, updating existing location |
| 210 | + # if exists else create a new location |
| 211 | + location_defaults = { |
| 212 | + "name": f"{device.name} Location", |
| 213 | + "type": "outdoor", |
| 214 | + "organization_id": device.organization_id, |
| 215 | + "is_mobile": False, |
| 216 | + "geometry": coords, |
| 217 | + "address": address, |
| 218 | + } |
| 219 | + if device_location.location and device_location.location.fuzzy: |
| 220 | + for attr, value in location_defaults.items(): |
| 221 | + setattr(device_location.location, attr, value) |
| 222 | + device_location.location.full_clean() |
| 223 | + device_location.location.save() |
| 224 | + elif not device_location.location: |
| 225 | + location = Location(**location_defaults, fuzzy=True) |
| 226 | + location.full_clean() |
| 227 | + location.save() |
| 228 | + device_location.location = location |
| 229 | + device_location.full_clean() |
| 230 | + device_location.save() |
0 commit comments