Skip to content

Commit

Permalink
Fix camptocamp#2582 - Backport ability to log user and date to 1.6
Browse files Browse the repository at this point in the history
  • Loading branch information
juliensam committed Nov 16, 2016
1 parent c68cd5f commit 3fe507f
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 3 deletions.
2 changes: 2 additions & 0 deletions c2cgeoportal/scaffolds/update/CONST_vars.yaml_tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ vars:
# The list of available variable names for the `UI metadatas` form.
available_metadata:
- copy_to
- lastUpdateDateColumn
- lastUpdateUserColumn

# The list of functionalities that can be configured
# through the admin interface.
Expand Down
67 changes: 66 additions & 1 deletion c2cgeoportal/tests/functional/test_layers.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def tearDown(self): # noqa

def _create_layer(
self, public=False, none_area=False, attr_list=False,
exclude_properties=False):
exclude_properties=False, ui_metadatas=[]):
""" This function is central for this test class. It creates
a layer with two features, and associates a restriction area
to it. """
Expand Down Expand Up @@ -149,6 +149,8 @@ def _create_layer(
Column("child_id", types.Integer,
ForeignKey("public.%s_child.id" % tablename)),
Column("name", types.Unicode),
Column("last_update_user", types.Unicode),
Column("last_update_date", types.DateTime),
Column("geom", Geometry("POINT", srid=21781, management=management)),
schema="public"
)
Expand Down Expand Up @@ -184,6 +186,10 @@ def _create_layer(
if exclude_properties:
layer.exclude_properties = "name"

for metadata in ui_metadatas:
metadata.item_id = layer.id
DBSession.add(metadata)

DBSession.add(layer)

if not public:
Expand Down Expand Up @@ -402,6 +408,29 @@ def test_create(self):
self.assertTrue(isinstance(collection, FeatureCollection))
self.assertEquals(len(collection.features), 2)

def test_create_log(self):
from datetime import datetime
from geojson.feature import FeatureCollection
from c2cgeoportal.views.layers import Layers
from c2cgeoportal.models import UIMetadata

ui_metadatas = [
UIMetadata("lastUpdateDateColumn", "last_update_date"),
UIMetadata("lastUpdateUserColumn", "last_update_user"),
]
layer_id = self._create_layer(ui_metadatas=ui_metadatas)
request = self._get_request(layer_id, username=u"__test_user")
request.method = "POST"
request.body = '{"type": "FeatureCollection", "features": [{"type": "Feature", "properties": {"name": "foo", "child": "c1é"}, "geometry": {"type": "Point", "coordinates": [5, 45]}}]}' # noqa
layers = Layers(request)
collection = layers.create()
self.assertEquals(request.response.status_int, 201)
self.assertTrue(isinstance(collection, FeatureCollection))
self.assertEquals(len(collection.features), 1)
properties = collection.features[0]
self.assertEquals(properties.last_update_user, request.user.id)
self.assertIsInstance(properties.last_update_date, datetime)

@attr(create_validation_fails=True)
def test_create_validation_fails(self):
from c2cgeoportal.views.layers import Layers
Expand Down Expand Up @@ -470,6 +499,26 @@ def test_update(self):
self.assertEquals(feature.name, "foobar")
self.assertEquals(feature.child, u"c2é")

def test_update_log(self):
from datetime import datetime
from c2cgeoportal.views.layers import Layers
from c2cgeoportal.models import UIMetadata

ui_metadatas = [
UIMetadata("lastUpdateDateColumn", "last_update_date"),
UIMetadata("lastUpdateUserColumn", "last_update_user"),
]
layer_id = self._create_layer(ui_metadatas=ui_metadatas)
request = self._get_request(layer_id, username=u"__test_user")
request.matchdict["feature_id"] = 1
request.method = "PUT"
request.body = '{"type": "Feature", "id": 1, "properties": {"name": "foobar", "child": "c2é"}, "geometry": {"type": "Point", "coordinates": [5, 45]}}' # noqa
layers = Layers(request)
feature = layers.update()
self.assertEquals(feature.id, 1)
self.assertEquals(feature.last_update_user, request.user.id)
self.assertIsInstance(feature.last_update_date, datetime)

@attr(update_validation_fails=True)
def test_update_validation_fails(self):
from c2cgeoportal.views.layers import Layers
Expand Down Expand Up @@ -560,6 +609,22 @@ def test_metadata(self):
self.assertTrue(hasattr(cls, "name"))
self.assertTrue("child" in cls.__dict__)

def test_metadata_log(self):
from c2cgeoportal.views.layers import Layers
from c2cgeoportal.models import UIMetadata

ui_metadatas = [
UIMetadata("lastUpdateDateColumn", "last_update_date"),
UIMetadata("lastUpdateUserColumn", "last_update_user"),
]
layer_id = self._create_layer(ui_metadatas=ui_metadatas)
request = self._get_request(layer_id, username=u"__test_user")

layers = Layers(request)
cls = layers.metadata()
self.assertFalse(hasattr(cls, "last_update_date"))
self.assertFalse(hasattr(cls, "last_update_user"))

@attr(metadata_exclude_properties=True)
def test_metadata_exclude_properties(self):
from c2cgeoportal.views.layers import Layers
Expand Down
41 changes: 39 additions & 2 deletions c2cgeoportal/views/layers.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
# of the authors and should not be interpreted as representing official policies,
# either expressed or implied, of the FreeBSD Project.

from datetime import datetime

from pyramid.httpexceptions import HTTPInternalServerError, \
HTTPNotFound, HTTPBadRequest, HTTPForbidden
from pyramid.view import view_config
Expand All @@ -52,7 +54,7 @@
from c2cgeoportal.lib.caching import get_region, \
set_common_headers, NO_CACHE, PUBLIC_CACHE, PRIVATE_CACHE
from c2cgeoportal.lib.dbreflection import get_class, get_table
from c2cgeoportal.models import DBSessions, DBSession, Layer, RestrictionArea, Role
from c2cgeoportal.models import DBSessions, DBSession, Layer, RestrictionArea, Role, UIMetadata

cache_region = get_region()

Expand Down Expand Up @@ -258,6 +260,8 @@ def check_geometry(r, feature, o):
protocol = self._get_protocol_for_layer(layer, before_create=check_geometry)
try:
features = protocol.create(self.request)
for feature in features.features:
self._log_last_update(layer, feature)
return features
except TopologicalError, e:
self.request.response.status_int = 400
Expand Down Expand Up @@ -308,6 +312,7 @@ def check_geometry(r, feature, o):
protocol = self._get_protocol_for_layer(layer, before_update=check_geometry)
try:
feature = protocol.update(self.request, feature_id)
self._log_last_update(layer, feature)
return feature
except TopologicalError, e:
self.request.response.status_int = 400
Expand All @@ -324,6 +329,26 @@ def _validate_geometry(self, geom):
reason = DBSession.query(func.ST_IsValidReason(geom)).scalar()
raise TopologicalError(reason)

def _log_last_update(self, layer, feature):
last_update_date = self._get_ui_metadata(layer, "lastUpdateDateColumn")
if last_update_date is not None:
setattr(feature, last_update_date, datetime.now())

last_update_user = self._get_ui_metadata(layer, "lastUpdateUserColumn")
if last_update_user is not None:
setattr(feature, last_update_user, self.request.user.role.id)

def _get_ui_metadata(self, layer, key):
query = DBSession.query(UIMetadata).filter(
UIMetadata.item_id == layer.id,
UIMetadata.name == key
)
metadatas = query.all()
if len(metadatas) == 1:
metadata = metadatas[0]
return metadata.value
return None

@view_config(route_name="layers_delete")
def delete(self):
set_common_headers(self.request, "layers", NO_CACHE)
Expand Down Expand Up @@ -362,9 +387,21 @@ def metadata(self):
if not layer.public and self.request.user is None:
raise HTTPForbidden()

# exclude the columns used to record the last features update
if layer.exclude_properties is not None:
exclude = layer.exclude_properties.split(",")
else:
exclude = []
last_update_date = self._get_ui_metadata(layer, "lastUpdateDateColumn")
if last_update_date:
exclude.append(last_update_date)
last_update_user = self._get_ui_metadata(layer, "lastUpdateUserColumn")
if last_update_user:
exclude.append(last_update_user)

return get_class(
str(layer.geo_table),
exclude_properties=layer.exclude_properties
exclude_properties=",".join(exclude)
)

@view_config(route_name="layers_enumerate_attribute_values", renderer="json")
Expand Down

0 comments on commit 3fe507f

Please sign in to comment.