import json import gzip import pytz from datetime import datetime from django.shortcuts import render from django.http import JsonResponse, HttpResponse from django.core.serializers.json import DjangoJSONEncoder from django.views import View from django.core.cache import cache from django.contrib.auth.decorators import permission_required from django.contrib.auth.mixins import PermissionRequiredMixin from django.contrib.gis.geos import Point from django.db.models import Q from .models import * from .workers.points2trips import TripConverter def index(request): return render(request, 'gps_logger/index.html') @permission_required("gps-logger.markers.change") def upload(request): return render(request, 'gps_logger/upload.html') class MarkerCreateView(PermissionRequiredMixin, View): permission_required = ("gps-logger.markers.change") def post(self, request): utctz = pytz.timezone("UTC") insert_count = censor_count = replace_count = 0 data = json.loads(request.body) minDate = datetime.utcnow().replace(tzinfo=utctz) for file in data: if len(data[file]) == 0: continue objects = [Marker( timestamp=datetime.strptime(x['timestamp'].replace("Z","-0000"), r"%Y-%m-%dT%H:%M:%S.%f%z"), location = Point(x['lng'], x['lat'], srid=4326), alt = x['alt'], hdop = x.get('hdop', None), speed = x.get('speed', None) ) for x in data[file]] start_date = objects[0].timestamp end_date = objects[-1].timestamp oldMarkers = Marker.objects.filter(timestamp__range=(start_date, end_date)).all() identical = oldMarkers.count() == len(objects) minDate = min(minDate, start_date) if identical: for i, marker in enumerate(oldMarkers): if marker.timestamp != objects[i].timestamp: identical = False break if identical: for i, marker in enumerate(oldMarkers): objects[i].id = marker.id Marker.objects.bulk_update(objects, ['location', 'alt', 'hdop', 'speed']) replace_count += oldMarkers.count() else: insert_count += len(objects) - oldMarkers.count() oldMarkers.delete() Marker.objects.bulk_create(objects) censor_count = censor() minDate = minDate.replace(hour=0, minute=0, second=0, microsecond=0) print("regenerating trips after", minDate) tc = TripConverter(minDate) tc.run() cache.delete('trips') return JsonResponse({ 'markers_censored': censor_count, 'markers_replaced': replace_count, 'markers_inserted': insert_count - censor_count, 'trips_created': tc.created, 'trips_updated': tc.updated, 'trips_skipped': tc.skipped }, status=201) class CreateTripsView(PermissionRequiredMixin, View): permission_required = ("gps-logger.trips.change") def get(self, request): tc = TripConverter() tc.run() cache.delete('trips') return JsonResponse({ 'created': tc.created, 'updated': tc.updated, 'skipped': tc.skipped }, status=201) def marker_view(request): data = cache.get('markers') if not data: values = list(Marker.objects.values()) for marker in values: location = marker['location'] if location: marker['lng'] = location.x marker['lat'] = location.y del marker['location'] data = json.dumps(values, cls=DjangoJSONEncoder) cache.set('markers', data, 3600*24*30) return HttpResponse(data, content_type='application/json') def trip_view(request): data = cache.get('trips') if not data: values = list(Trip.objects.values()) for trip in values: trip['path'] = json.loads(gzip.decompress(trip['path'])) trip['startTime'] = trip['startTime'].timestamp() trip['endTime'] = trip['endTime'].timestamp() trip['movementTime'] = trip['movementTime'].total_seconds() trip['totalTime'] = trip['totalTime'].total_seconds() trip['center'] = { 'lng': trip['center'].x, 'lat': trip['center'].y } trip['minLng'], trip['minLat'], trip['maxLng'], trip['maxLat'] = trip['line'].extent del trip['line'] data = json.dumps(values) cache.set('trips', data, 3600*24*30) return HttpResponse(data, content_type='application/json') class DeleteCensoredView(PermissionRequiredMixin, View): permission_required = ("gps-logger.markers.change",) def get(self, request): counter = censor() return JsonResponse({'censored': counter}) def censor() -> int: locations = CensoredLocation.objects.all() filter = None for location in locations: f = Q(location__distance_lte=(location.location, distance_to_decimal_degrees(D(m=location.radius), location.location.y))) filter = f if filter is None else filter | f matches = Marker.objects.filter(filter) counter, _ = matches.delete() cache.delete('markers') return counter