Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New settings management with optional django-siteprefs #61

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
6 changes: 6 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ CHANGELOG
0.3.35.dev0 (XXXX-XX-XX)
----------------------------

!! Breaking changes !!

* New settings system.
After install, please reset your settings in Django admin / GEOCRUD / Preference section (superuser only)

* Fix way to generate templates


Expand Down Expand Up @@ -38,6 +43,7 @@ CHANGELOG
* New template tag to handle image from data-url stored image
* Fix bug in admin


0.3.32 (2020-02-06)
----------------------------

Expand Down
129 changes: 76 additions & 53 deletions doc/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,36 @@ In your project :

* settings

::
.. code-block:: python

INSTALLED_APPS = [
...
# basic django apps
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',

# apps required by terralego stack
'django.contrib.gis',
'django.contrib.postgres',
'rest_framework_gis',
'rest_framework_jwt',
'terra_utils',
'terra_accounts',

# apps required by CRUD
'siteprefs', # set some preferences directly in admin
'geostore', # store geographic data
'template_model', # store template in model
'template_engines', # generate odt and docx templates
'rest_framework', # if you want to try api HTML interface
'django_json_widget', # if you want to use django admin
'sorl.thumbnail', # to generate and manage cached image thumbnails
'mapbox_baselayer', # store and configure mapbox base layers
'reversion', # used to store every change on data (run ./manage.py createinitialrevisions first)

# CRUD app
'terra_geocrud',
...
Expand All @@ -32,78 +51,82 @@ In your project :

* urls

::
.. code-block:: python

urlpatterns = [
...
# some urls in geostore are required by geocrud
path('api/geostore/', include('geostore.urls')),
# admin
path('', admin.site.urls), # some base admin views are available in geocrud.

# terralego based urls
path('api/', include('terra_utils.urls')),
path('api/', include('terra_accounts.urls')),

# urls required for geocrud
path('api/mapbox_baselayer/', include('mapbox_baselayer.urls')),
path('api/crud/', include('terra_geocrud.urls')),
...
]

You can customize default url and namespace by including terra_geocrud.views directly

Run migrations

::
.. code-block:: bash

./manage.py migrate



- ADMIN :

you can disable and / or customize admin


- SETTINGS :

Waiting for settings definition directly in models.

Settings should be overrided with TERRA_GEOCRUD settings in your project settings file:

::

...
TERRA_GEOCRUD = {
# default value for map extent. API serialize this for layer extent if there is no features in it (as default)
'EXTENT': [-90.0, -180.0, 90.0, 180.0],
# default storage for file stored in json properties. It is recommended to configure a private web storage in your project (as S3Storage -> see django-storages)
'DATA_FILE_STORAGE_CLASS': 'django.core.files.storage.FileSystemStorage',
# default mapbox style provided by api if no custom style defined in crud view
'STYLES': {
'line': {
'type': 'line',
'paint': {
'line-color': '#000',
'line-width': 3
}
},
'point': {
'type': 'circle',
'paint': {
'circle-color': '#000',
'circle-radius': 8
}
},
'polygon': {
'type': 'fill',
'paint': {
'fill-color': '#000'
}
},
}
}
...
Some settings are available in django admin, Geographic Editor Config -> Preferences, if admin has been enabled in your project.

.. code-block:: python

GEOCRUD_MBGLRENDERER_MAX_ZOOM = 22 # define zoom level max for point map capture (other based on extent)
GEOCRUD_MAPBOX_ACCESS_TOKEN = None # define token to handle mapbox service
GEOCRUD_DEFAULT_MAP_CENTER_LAT = 0.0 # Latitude wgs84 for default empty map center
GEOCRUD_DEFAULT_MAP_CENTER_LNG = 0.0 # Longitude wgs84 for default empty map center
GEOCRUD_DEFAULT_MAP_CENTER_ZOOM = 2 # Zoom level for default empty map
GEOCRUD_DEFAULT_MAP_MAX_ZOOM = 18 # Max zoom level for maps
GEOCRUD_DEFAULT_MAP_MIN_ZOOM = 3 # Min zoom level for maps
GEOCRUD_MAP_EXTENT_SW_LAT = -90.0 # SW latitude wgs84 for empty map extent
GEOCRUD_MAP_EXTENT_SW_LNG = -180.0 # SW lonitude wgs84 for empty map extent
GEOCRUD_MAP_EXTENT_NE_LAT = 90.0 # NE latitude wgs84 for empty map extent
GEOCRUD_MAP_EXTENT_NE_LNG = 180.0 # NE longitude wgs84 for empty map extent
GEOCRUD_DEFAULT_STYLE_LINE = {"type": "line", # Default line style used if not defined in crud view
"paint": {
"line-color": "#000",
"line-width": 3
}}
GEOCRUD_DEFAULT_STYLE_POINT = {"type": "circle", # Default point style used if not defined in crud view
"paint": {
"circle-color": "#000",
"circle-radius": 8
}}
GEOCRUD_DEFAULT_STYLE_POLYGON = {"type": "fill", # Default polygon style used if not defined in crud view
"paint": {
"fill-color": "#000"
}}

These settings should be override in your project settings file only :

.. code-block:: python

GEOCRUD_MBGLRENDERER_URL = 'http://mbglrenderer'

* If you want to generate map on your template with the geometry of your feature, and/or extra features, you should use
mbglrenderer.

Check https://github.com/consbio/mbgl-renderer.

Change the url in the settings to use your instance of mbglrenderer :
Change the url in the settings to use external instance of mbglrenderer :


.. code-block:: python

GEOCRUD_DATA_FILE_STORAGE_CLASS = 'django.core.files.storage.FileSystemStorage'

::
* This settings manage storage class for feature data files. It will be more secure if you choose a custom private storage backend, like s3 with signature
* Configure this with python doted path to your custom storage backend definition.
* -> See django-storages

MBGLRENDERER_URL = 'http://mbglrenderer'
17 changes: 7 additions & 10 deletions doc/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,8 @@ Installation
Requirements
------------

Must be installed, for the package to work:

* terracommon.terra
* template_model
* template_engines
* DATABASE : postgres 10+ / postgis 2.4+ / pgrouting 2.5+
* GeoDjango libs installed https://docs.djangoproject.com/en/3.0/ref/contrib/gis/install/geolibs/

With pip
--------
Expand All @@ -17,19 +14,19 @@ From Pypi:

::

pip install xxxxxxxxxx-xxxxxxxxxxxx
pip install django-terra-geocrud

From Github:

::

pip install -e https://github.com/Terralego/terra.backend.crud.git@master#egg=django-template-engines
pip install -e https://github.com/Terralego/django-terra-geocrud.git@master#egg=django-terra-geocrud

With git
--------

::

git clone https://github.com/Terralego/terra.backend.crud.git
cd terra.backend.crud
python setup.py install
git clone https://github.com/Terralego/django-terra-geocrud.git
django-terra-geocrud
pip install -e .
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
],
install_requires=[
'django>=2.2',
'django-siteprefs',
'django-reversion>=3.0.4',
'django-template-model>=1.0.1',
'django-template-engines>=1.2.24',
Expand Down
1 change: 1 addition & 0 deletions terra_geocrud/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from django.contrib.postgres import fields
from django.utils.translation import gettext_lazy as _
from geostore.models import LayerExtraGeom

from reversion.admin import VersionAdmin
from sorl.thumbnail.admin import AdminInlineImageMixin

Expand Down
5 changes: 3 additions & 2 deletions terra_geocrud/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

class TerraCrudConfig(PermissionRegistrationMixin, AppConfig):
name = 'terra_geocrud'
verbose_name = 'Geographic Editor Config'
verbose_name = 'Geographic Editor (CRUD)'
permissions = (
("can_manage_views", _("GEOCRUD: Can create / edit / delete views / groups and associated layers.")),
("can_view_feature", _("GEOCRUD: Can read feature detail.")),
Expand All @@ -18,11 +18,12 @@ class TerraCrudConfig(PermissionRegistrationMixin, AppConfig):

def ready(self):
super().ready()
# in terra lego context, we assume to render module url
terra_settings = getattr(settings, 'TERRA_APPLIANCE_SETTINGS', {})
modules = terra_settings.get('modules', {})
# auto enable CRUD in terralego modules settings
modules.update({
'CRUD': {
# in terra lego context, we assume to render module url
"settings": reverse_lazy('settings'),
}
})
Expand Down
14 changes: 7 additions & 7 deletions terra_geocrud/map/styles.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,18 @@
class MapStyleModelMixin:
@cached_property
def map_style_with_default(self):
response = get_default_style(self.get_layer())
style = self.map_style
return deepcopy(style) if style else response
return deepcopy(self.map_style) if self.map_style else get_default_style(self.get_layer())


def get_default_style(layer):
style_settings = app_settings.TERRA_GEOCRUD.get('STYLES', {})
response = {}
if layer.is_point:
response = style_settings.get('point')
response = eval(app_settings.DEFAULT_STYLE_POINT) if isinstance(app_settings.DEFAULT_STYLE_POINT, str) \
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use of possibly insecure function - consider using safer ast.literal_eval.

else app_settings.DEFAULT_STYLE_POINT
elif layer.is_linestring:
response = style_settings.get('line')
response = eval(app_settings.DEFAULT_STYLE_LINE) if isinstance(app_settings.DEFAULT_STYLE_LINE, str) \
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use of possibly insecure function - consider using safer ast.literal_eval.

else app_settings.DEFAULT_STYLE_LINE
elif layer.is_polygon:
response = style_settings.get('polygon')
response = eval(app_settings.DEFAULT_STYLE_POLYGON) if isinstance(app_settings.DEFAULT_STYLE_POLYGON, str) \
submarcos marked this conversation as resolved.
Show resolved Hide resolved
else app_settings.DEFAULT_STYLE_POLYGON
return deepcopy(response)
5 changes: 4 additions & 1 deletion terra_geocrud/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@ def extent(self):
extent = features_extent.get('extent')
# get extent in settings if no features

return extent if extent else app_settings.TERRA_GEOCRUD['EXTENT']
return extent if extent else [app_settings.MAP_EXTENT_SW_LNG,
app_settings.MAP_EXTENT_SW_LAT,
app_settings.MAP_EXTENT_NE_LNG,
app_settings.MAP_EXTENT_NE_LAT]

def get_layer(self):
return self.layer
Expand Down
3 changes: 1 addition & 2 deletions terra_geocrud/properties/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ def get_info_content(value):


def get_storage():
""" Get media storage for feature data element, using settings """
StorageClass = get_storage_class(import_path=app_settings.TERRA_GEOCRUD['DATA_FILE_STORAGE_CLASS'])
StorageClass = get_storage_class(import_path=app_settings.DATA_FILE_STORAGE_CLASS)
return StorageClass()


Expand Down
11 changes: 8 additions & 3 deletions terra_geocrud/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ def get_properties(self, obj):
if data_format == 'data-url':
# apply special cases for files
data_type = 'file'

data = {"url": None}
if value:
# generate / get thumbnail for image
Expand All @@ -188,6 +189,7 @@ def get_properties(self, obj):
pass
except IndexError:
pass

elif data_format == "date":
data_type = 'date'
data = value
Expand Down Expand Up @@ -268,9 +270,11 @@ def get_action_url(self, obj):

class Meta:
model = models.FeaturePicture
extra_kwargs = {
}
fields = ('id', 'category', 'legend', 'image', 'thumbnail', 'action_url', 'created_at', 'updated_at')
fields = (
'id', 'category', 'legend', 'image',
'thumbnail', 'action_url',
'created_at', 'updated_at'
)


class FeatureAttachmentSerializer(BaseUpdatableMixin):
Expand Down Expand Up @@ -397,6 +401,7 @@ def get_display_properties(self, obj):

except IndexError:
pass

elif data_format == "date":
data_type = 'date'
data = value
Expand Down
Loading