forked from openwisp/openwisp-controller
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request openwisp#22 from openwisp/gis
[geo] Added GIS module (imported django-loci)
- Loading branch information
Showing
28 changed files
with
834 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
{ | ||
"predef": [ | ||
"document", | ||
"navigator", | ||
"console", | ||
"window", | ||
"django", | ||
"gettext", | ||
"windowname_to_id", | ||
"jQuery", | ||
"WebSocket", | ||
"$", | ||
"dismissRelatedLookupPopup", | ||
"dismissAddAnotherPopup", | ||
"FileReader", | ||
"Image", | ||
"L" | ||
], | ||
|
||
"adsafe": false, | ||
"safe": false, | ||
|
||
"bitwise": false, | ||
"cap": false, | ||
"confusion": true, | ||
"continue": true, | ||
"css": true, | ||
"debug": false, | ||
"eqeq": false, | ||
"es5": true, | ||
"evil": false, | ||
"forin": false, | ||
"fragment": true, | ||
"newcap": false, | ||
"nomen": false, | ||
"on": false, | ||
"plusplus": false, | ||
"regexp": true, | ||
"sloppy": false, | ||
"sub": false, | ||
"undef": false, | ||
"unparam": true, | ||
"vars": true, | ||
"white": false, | ||
"validthis": true, | ||
"strict_mode":true, | ||
|
||
"browser": false, | ||
"devel": false, | ||
"node": false, | ||
"rhino": false, | ||
"widget": false, | ||
"windows": false, | ||
"indent": 4, | ||
"maxerr": 50, | ||
"maxlen": 120, | ||
"passfail": false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
default_app_config = 'openwisp_controller.geo.apps.GeoConfig' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
from django.contrib import admin | ||
from django_loci.base.admin import (AbstractFloorPlanAdmin, AbstractFloorPlanForm, AbstractFloorPlanInline, | ||
AbstractLocationAdmin, AbstractLocationForm, AbstractObjectLocationForm, | ||
ObjectLocationMixin) | ||
|
||
from openwisp_utils.admin import MultitenantOrgFilter | ||
|
||
from ..admin import MultitenantAdminMixin | ||
from ..config.admin import DeviceAdmin as BaseDeviceAdmin | ||
from ..config.admin import ConfigInline | ||
from ..config.models import Device | ||
from .models import DeviceLocation, FloorPlan, Location | ||
|
||
|
||
class FloorPlanForm(AbstractFloorPlanForm): | ||
class Meta(AbstractFloorPlanForm.Meta): | ||
model = FloorPlan | ||
exclude = ('organization',) # automatically managed | ||
|
||
|
||
class FloorPlanAdmin(MultitenantAdminMixin, AbstractFloorPlanAdmin): | ||
form = FloorPlanForm | ||
list_filter = [('organization', MultitenantOrgFilter), | ||
'created'] | ||
|
||
|
||
FloorPlanAdmin.list_display.insert(1, 'organization') | ||
|
||
|
||
class LocationForm(AbstractLocationForm): | ||
class Meta(AbstractLocationForm.Meta): | ||
model = Location | ||
|
||
|
||
class FloorPlanInline(AbstractFloorPlanInline): | ||
form = FloorPlanForm | ||
model = FloorPlan | ||
|
||
|
||
class LocationAdmin(MultitenantAdminMixin, AbstractLocationAdmin): | ||
form = LocationForm | ||
inlines = [FloorPlanInline] | ||
list_select_related = ('organization',) | ||
|
||
|
||
LocationAdmin.list_display.insert(1, 'organization') | ||
LocationAdmin.list_filter.insert(0, ('organization', MultitenantOrgFilter)) | ||
|
||
|
||
class ObjectLocationForm(AbstractObjectLocationForm): | ||
class Meta(AbstractObjectLocationForm.Meta): | ||
model = DeviceLocation | ||
|
||
def _get_location_instance(self): | ||
location = super(ObjectLocationForm, self)._get_location_instance() | ||
location.organization_id = self.data.get('organization') | ||
return location | ||
|
||
def _get_floorplan_instance(self): | ||
floorplan = super(ObjectLocationForm, self)._get_floorplan_instance() | ||
floorplan.organization_id = self.data.get('organization') | ||
return floorplan | ||
|
||
|
||
class DeviceLocationInline(ObjectLocationMixin, admin.StackedInline): | ||
model = DeviceLocation | ||
form = ObjectLocationForm | ||
|
||
|
||
admin.site.register(FloorPlan, FloorPlanAdmin) | ||
admin.site.register(Location, LocationAdmin) | ||
|
||
|
||
# Add DeviceLocationInline to config.DeviceAdmin | ||
|
||
class GeoDeviceAdmin(BaseDeviceAdmin): | ||
inlines = [DeviceLocationInline, ConfigInline] | ||
|
||
|
||
admin.site.unregister(Device) | ||
admin.site.register(Device, GeoDeviceAdmin) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
from django.conf.urls import url | ||
|
||
from . import views | ||
|
||
urlpatterns = [ | ||
url(r'^api/device-location/(?P<pk>[^/]+)/$', | ||
views.device_location, | ||
name='api_device_location'), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
from django.core.exceptions import ObjectDoesNotExist | ||
from rest_framework import generics | ||
from rest_framework.permissions import BasePermission | ||
from rest_framework_gis import serializers as gis_serializers | ||
|
||
from ...config.models import Device | ||
from ..models import DeviceLocation, Location | ||
|
||
|
||
class DevicePermission(BasePermission): | ||
def has_object_permission(self, request, view, obj): | ||
return request.query_params.get('key') == obj.key | ||
|
||
|
||
class LocationSerializer(gis_serializers.GeoFeatureModelSerializer): | ||
class Meta: | ||
model = Location | ||
geo_field = 'geometry' | ||
fields = ('name', 'geometry') | ||
read_only_fields = ('name', ) | ||
|
||
|
||
class DeviceLocationView(generics.RetrieveUpdateAPIView): | ||
serializer_class = LocationSerializer | ||
permission_classes = (DevicePermission,) | ||
queryset = Device.objects.select_related('devicelocation', | ||
'devicelocation__location') | ||
|
||
def get_location(self, device): | ||
try: | ||
return device.devicelocation.location | ||
except ObjectDoesNotExist: | ||
return None | ||
|
||
def get_object(self, *args, **kwargs): | ||
device = super(DeviceLocationView, self).get_object() | ||
location = self.get_location(device) | ||
if location: | ||
return location | ||
# if no location present, automatically create it | ||
return self.create_location(device) | ||
|
||
def create_location(self, device): | ||
location = Location(name=device.name, | ||
type='outdoor', | ||
organization=device.organization) | ||
location.full_clean() | ||
location.save() | ||
dl = DeviceLocation(content_object=device, | ||
location=location) | ||
dl.full_clean() | ||
dl.save() | ||
return location | ||
|
||
|
||
device_location = DeviceLocationView.as_view() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
from django.conf import settings | ||
from django.utils.translation import ugettext_lazy as _ | ||
from django_loci.apps import LociConfig | ||
|
||
|
||
class GeoConfig(LociConfig): | ||
name = 'openwisp_controller.geo' | ||
label = 'geo' | ||
verbose_name = _('Geographic Information') | ||
|
||
def __setmodels__(self): | ||
from .models import Location | ||
self.location_model = Location | ||
|
||
def ready(self): | ||
super(GeoConfig, self).ready() | ||
if getattr(settings, 'TESTING', False): | ||
self._add_params_to_test_config() | ||
|
||
def _add_params_to_test_config(self): | ||
""" | ||
this methods adds the management fields of DeviceLocationInline | ||
to the parameters used in config.tests.test_admin.TestAdmin | ||
this hack is needed for the following reasons: | ||
- avoids breaking config.tests.test_admin.TestAdmin | ||
- avoids adding logic of geo app in config, this | ||
way config doesn't know anything about geo, keeping | ||
complexity down to a sane level | ||
""" | ||
from .tests.test_admin_inline import TestAdminInline | ||
from ..config.tests.test_admin import TestAdmin as TestConfigAdmin | ||
params = TestAdminInline._get_params() | ||
delete_keys = [] | ||
# delete unnecessary fields | ||
# leave only management fields | ||
for key in params.keys(): | ||
if '_FORMS' not in key: | ||
delete_keys.append(key) | ||
for key in delete_keys: | ||
del params[key] | ||
TestConfigAdmin._additional_params.update(params) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
from django_loci.channels.base import BaseLocationBroadcast | ||
|
||
from ..models import Location | ||
|
||
|
||
class LocationBroadcast(BaseLocationBroadcast): | ||
model = Location | ||
|
||
def is_authorized(self, user, location): | ||
result = super(LocationBroadcast, self).is_authorized(user, location) | ||
# non superusers must also be members of the org | ||
if result and not user.is_superuser and ( | ||
(location.organization.pk,) not in | ||
user.organizations_pk | ||
): | ||
return False | ||
return result |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from django_loci.channels.base import location_broadcast_path | ||
|
||
from .consumers import LocationBroadcast | ||
|
||
channel_routing = [LocationBroadcast.as_route(path=location_broadcast_path)] |
Oops, something went wrong.