106 lines
3.5 KiB
Python
106 lines
3.5 KiB
Python
from django.utils import timezone
|
|
from django.conf import settings
|
|
|
|
from .models.locale import City
|
|
from .ipstack import get_ipstack_geocoder
|
|
|
|
import math
|
|
import pytz
|
|
import geocoder
|
|
|
|
KM_PER_DEGREE_LAT = 110.574
|
|
KM_PER_DEGREE_LNG = 111.320 # At the equator
|
|
DEFAULT_NEAR_DISTANCE = 100 # kilometeres
|
|
|
|
class TimezoneChoices():
|
|
|
|
def __iter__(self):
|
|
for tz in pytz.all_timezones:
|
|
yield (tz, tz)
|
|
|
|
def get_client_ip(request):
|
|
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
|
|
if x_forwarded_for:
|
|
ip = x_forwarded_for.split(',')[0]
|
|
else:
|
|
ip = request.META.get('REMOTE_ADDR')
|
|
return ip
|
|
|
|
def get_geoip(request):
|
|
client_ip = get_client_ip(request)
|
|
if client_ip == '127.0.0.1' or client_ip == 'localhost':
|
|
if settings.DEBUG:
|
|
client_ip = getattr(settings, 'DEBUG_IP', '8.8.8.8') # Try Debug ip
|
|
print("Client is localhost, using %s for geoip instead" % client_ip)
|
|
else:
|
|
raise Exception("Client is localhost")
|
|
|
|
g = get_ipstack_geocoder(client_ip)
|
|
return g
|
|
|
|
def get_bounding_box(center, radius):
|
|
minlat = center[0]-(radius/KM_PER_DEGREE_LAT)
|
|
maxlat = center[0]+(radius/KM_PER_DEGREE_LAT)
|
|
minlng = center[1]-(radius/(KM_PER_DEGREE_LNG*math.cos(math.radians(center[0]))))
|
|
maxlng = center[1]+(radius/(KM_PER_DEGREE_LNG*math.cos(math.radians(center[0]))))
|
|
return (minlat, maxlat, minlng, maxlng)
|
|
|
|
def distance(center1, center2):
|
|
avglat = (center2[0] + center1[0])/2
|
|
dlat = (center2[0] - center1[0]) * KM_PER_DEGREE_LAT
|
|
dlng = (center2[1] - center1[1]) * (KM_PER_DEGREE_LNG*math.cos(math.radians(avglat)))
|
|
dkm = math.sqrt((dlat*dlat) + (dlng*dlng))
|
|
return dkm
|
|
|
|
def city_distance_from(ll, city):
|
|
if ll is None:
|
|
return 0
|
|
if city is not None and city.latitude is not None and city.longitude is not None:
|
|
return distance((ll), (city.latitude, city.longitude))
|
|
else:
|
|
return 99999
|
|
|
|
def team_distance_from(ll, team):
|
|
if ll is None:
|
|
return 0
|
|
if team.city is not None:
|
|
return city_distance_from(ll, team.city)
|
|
else:
|
|
return 99999
|
|
|
|
def event_distance_from(ll, event):
|
|
if ll is None:
|
|
return 0
|
|
if event.place is not None and event.place.latitude is not None and event.place.longitude is not None:
|
|
return distance((ll), (event.place.latitude, event.place.longitude))
|
|
if event.team is not None:
|
|
return team_distance_from(ll, event.team)
|
|
else:
|
|
return 99999
|
|
|
|
def searchable_distance_from(ll, searchable):
|
|
if ll is None:
|
|
return 0
|
|
if searchable.latitude is not None and searchable.longitude is not None:
|
|
return distance((ll), (float(searchable.latitude), float(searchable.longitude)))
|
|
else:
|
|
return 99999
|
|
|
|
def get_nearest_city(ll, max_distance=100):
|
|
if ll is None:
|
|
return None
|
|
city = None
|
|
city_distance = 1 #km
|
|
while city is None and city_distance <= max_distance:
|
|
minlat = ll[0]-(city_distance/KM_PER_DEGREE_LAT)
|
|
maxlat = ll[0]+(city_distance/KM_PER_DEGREE_LAT)
|
|
minlng = ll[1]-(city_distance/(KM_PER_DEGREE_LNG*math.cos(math.radians(ll[0]))))
|
|
maxlng = ll[1]+(city_distance/(KM_PER_DEGREE_LNG*math.cos(math.radians(ll[0]))))
|
|
nearby_cities = City.objects.filter(latitude__gte=minlat, latitude__lte=maxlat, longitude__gte=minlng, longitude__lte=maxlng)
|
|
if len(nearby_cities) == 0:
|
|
city_distance += 1
|
|
else:
|
|
return sorted(nearby_cities, key=lambda city: city_distance_from(ll, city))[0]
|
|
return city
|
|
|
|
|