Skip to content

Commit

Permalink
Merge branch 'master' into add_menu_settings
Browse files Browse the repository at this point in the history
  • Loading branch information
LePetitTim committed Aug 8, 2019
2 parents 88e5153 + 15ca483 commit da9ac4e
Show file tree
Hide file tree
Showing 11 changed files with 320 additions and 41 deletions.
1 change: 1 addition & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ CHANGELOG
**Minor Changes**

- Add settings allowing to remove menu on the top left
- Serve attachment with 'Topoguide' type as public PDF

**Bug fixes**

Expand Down
8 changes: 7 additions & 1 deletion geotrek/common/serializers.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
from django.conf import settings
from django.core.urlresolvers import reverse
from django.db import models as django_db_models
from django.shortcuts import get_object_or_404
from django.utils.translation import get_language

from rest_framework import serializers as rest_serializers
from rest_framework import serializers as rest_fields

from .models import Theme, RecordSource, TargetPortal
from .models import Theme, RecordSource, TargetPortal, FileType, Attachment


class TranslatedModelSerializer(rest_serializers.ModelSerializer):
Expand Down Expand Up @@ -45,6 +47,10 @@ class PublishableSerializerMixin(BasePublishableSerializerMixin):
filelist_url = rest_serializers.SerializerMethodField()

def get_printable_url(self, obj):
if settings.ONLY_EXTERNAL_PUBLIC_PDF:
file_type = get_object_or_404(FileType, type="Topoguide")
if not Attachment.objects.attachments_for_object_only_type(obj, file_type).exists():
return None
appname = obj._meta.app_label
modelname = obj._meta.model_name
return reverse('%s:%s_printable' % (appname, modelname),
Expand Down
27 changes: 26 additions & 1 deletion geotrek/common/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,20 @@
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required, user_passes_test
from django.db.utils import DatabaseError
from django.http import HttpResponse
from django.http import HttpResponse, HttpResponseNotFound
from django.utils.translation import ugettext as _
from django_celery_results.models import TaskResult
from django.shortcuts import get_object_or_404
from django.utils import timezone
from django.views import static

from mapentity.helpers import api_bbox
from mapentity.registry import registry
from mapentity import views as mapentity_views

from geotrek.celery import app as celery_app
from geotrek.common.utils import sql_extent
from geotrek.common.models import FileType, Attachment
from geotrek import __version__

from rest_framework import permissions as rest_permissions, viewsets
Expand Down Expand Up @@ -87,6 +90,28 @@ class DocumentPublicMixin(object):
def dispatch(self, *args, **kwargs):
return super(mapentity_views.MapEntityDocumentBase, self).dispatch(*args, **kwargs)

def get(self, request, pk, slug, lang=None):
obj = get_object_or_404(self.model, pk=pk)
try:
file_type = FileType.objects.get(type="Topoguide")
except FileType.DoesNotExist:
file_type = None
attachments = Attachment.objects.attachments_for_object_only_type(obj, file_type)
if not attachments and not settings.ONLY_EXTERNAL_PUBLIC_PDF:
return super(DocumentPublicMixin, self).get(request, pk, slug, lang)
if not attachments:
return HttpResponseNotFound("No attached file with 'Topoguide' type.")
path = attachments[0].attachment_file.name

if settings.DEBUG:
response = static.serve(self.request, path, settings.MEDIA_ROOT)
else:
response = HttpResponse()
response[settings.MAPENTITY_CONFIG['SENDFILE_HTTP_HEADER']] = os.path.join(settings.MEDIA_URL_SECURE, path)
response["Content-Type"] = 'application/pdf'
response['Content-Disposition'] = "attachment; filename={0}.pdf".format(slug)
return response

def get_context_data(self, **kwargs):
context = super(DocumentPublicMixin, self).get_context_data(**kwargs)
modelname = self.get_model()._meta.object_name.lower()
Expand Down
26 changes: 17 additions & 9 deletions geotrek/core/sql/70_troncons_merge.sql
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@ DECLARE
merged_geom geometry;
reverse_update boolean;
reverse_merged boolean;
point_snapping geometry;
max_snap_distance float;
snap_distance float;
count_snapping integer;

BEGIN
reverse_update := FALSE;
reverse_merged := FALSE;
max_snap_distance := {{PATH_MERGE_SNAPPING_DISTANCE}};
snap_distance := {{PATH_SNAPPING_DISTANCE}};
rebuild_line := NULL;

IF updated = merged
Expand All @@ -32,56 +36,60 @@ BEGIN
THEN
rebuild_line := ST_MakeLine(ST_Reverse(updated_geom), merged_geom);
reverse_update := TRUE;

point_snapping := ST_StartPoint(updated_geom);
ELSIF ST_Equals(ST_StartPoint(updated_geom), ST_EndPoint(merged_geom))
THEN
rebuild_line := ST_MakeLine(ST_Reverse(updated_geom), ST_Reverse(merged_geom));
reverse_update := TRUE;
reverse_merged := TRUE;
point_snapping := ST_StartPoint(updated_geom);

ELSIF ST_Equals(ST_EndPoint(updated_geom), ST_EndPoint(merged_geom))
THEN
rebuild_line := ST_MakeLine(updated_geom, ST_Reverse(merged_geom));
reverse_merged := TRUE;
point_snapping := ST_EndPoint(updated_geom);

ELSIF ST_Equals(ST_EndPoint(updated_geom), ST_StartPoint(merged_geom))
THEN
rebuild_line := ST_MakeLine(updated_geom, merged_geom);
point_snapping := ST_EndPoint(updated_geom);

ELSIF (ST_Distance(ST_StartPoint(updated_geom), ST_StartPoint(merged_geom))::float <= max_snap_distance)
THEN
rebuild_line := ST_MakeLine(ST_Reverse(updated_geom), merged_geom);
reverse_update := TRUE;
point_snapping := ST_StartPoint(updated_geom);

ELSIF (ST_Distance(ST_StartPoint(updated_geom), ST_EndPoint(merged_geom)) <= max_snap_distance)
THEN
rebuild_line := ST_MakeLine(ST_Reverse(updated_geom), ST_Reverse(merged_geom));
reverse_update := TRUE;
reverse_merged := TRUE;
point_snapping := ST_StartPoint(updated_geom);

ELSIF (ST_Distance(ST_EndPoint(updated_geom), ST_EndPoint(merged_geom)) <= max_snap_distance)
THEN
rebuild_line := ST_MakeLine(updated_geom, ST_Reverse(merged_geom));
reverse_merged := TRUE;
point_snapping := ST_EndPoint(updated_geom);

ELSIF (ST_Distance(ST_EndPoint(updated_geom), ST_StartPoint(merged_geom)) <= max_snap_distance)
THEN
rebuild_line := ST_MakeLine(updated_geom, merged_geom);
point_snapping := ST_EndPoint(updated_geom);

ELSE
-- no snapping -> END !
RETURN 0;

END IF;

FOR element IN
SELECT * FROM l_t_troncon WHERE id != updated AND id != merged
LOOP
IF ST_Equals(ST_StartPoint(updated_geom), ST_StartPoint(element.geom)) OR ST_Equals(ST_EndPoint(updated_geom), ST_StartPoint(element.geom)) OR ST_Equals(ST_StartPoint(updated_geom), ST_EndPoint(element.geom)) OR ST_Equals(ST_EndPoint(updated_geom), ST_EndPoint(element.geom))
THEN
RETURN 2;
END IF;
END LOOP;
SELECT COUNT(*) INTO count_snapping FROM l_t_troncon WHERE (ST_DWITHIN(ST_StartPoint(geom), point_snapping, snap_distance) OR ST_DWITHIN(ST_EndPoint(geom), point_snapping, snap_distance)) AND brouillon = FALSE AND id != updated AND id != merged;

IF count_snapping != 0 THEN
RETURN 2;
END IF;

-- update events on updated path
FOR element IN
Expand Down
169 changes: 164 additions & 5 deletions geotrek/core/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,21 +285,170 @@ def test_merge_fails_donttouch(self):
self.assertIn('error', response.json())
self.logout()

def test_merge_fails_other_path_intersection(self):
def test_merge_fails_other_path_intersection_less_than_snapping(self):
"""
Merge should fail if other path share merge intersection
|
C
|
|--------A--------|-----------B-----------|
"""
self.login()
path_a = PathFactory.create(name="A", geom=LineString((0, 0), (10, 0)))
path_b = PathFactory.create(name="B", geom=LineString((11, 0), (20, 0)))
PathFactory.create(name="C", geom=LineString((10, 1), (10, 10)))
response = self.client.post(reverse('core:merge_path'), {'path[]': [path_a.pk, path_b.pk]})
json_response = response.json()
self.assertIn('error', json_response)
self.assertEqual(json_response['error'], "You can't merge 2 paths with a 3rd path in the intersection")
self.logout()

def test_merge_fails_other_path_intersection(self):
"""
Merge should fail if other path share merge intersection
|
C
|
|--------A--------|-----------B-----------|
"""
self.login()
path_a = PathFactory.create(name="A", geom=LineString((0, 0), (1, 0)))
path_b = PathFactory.create(name="B", geom=LineString((1, 0), (2, 0)))
PathFactory.create(name="C", geom=LineString((1, 0), (10, 10)))
path_a = PathFactory.create(name="A", geom=LineString((0, 0), (10, 0)))
path_b = PathFactory.create(name="B", geom=LineString((10, 0), (20, 0)))
PathFactory.create(name="C", geom=LineString((10, 0), (10, 10)))
response = self.client.post(reverse('core:merge_path'), {'path[]': [path_a.pk, path_b.pk]})
self.assertIn('error', response.json())
json_response = response.json()
self.assertIn('error', json_response)
self.assertEqual(json_response['error'], "You can't merge 2 paths with a 3rd path in the intersection")
self.logout()

def test_merge_fails_other_path_intersection_2(self):
"""
Merge should fail if other path share merge intersection
|
C (reversed)
|
|--------A--------|-----------B-----------|
"""
self.login()
path_a = PathFactory.create(name="A", geom=LineString((0, 0), (10, 0)))
path_b = PathFactory.create(name="B", geom=LineString((10, 0), (20, 0)))
PathFactory.create(name="C", geom=LineString((10, 10), (10, 0)))
response = self.client.post(reverse('core:merge_path'), {'path[]': [path_a.pk, path_b.pk]})
json_response = response.json()
self.assertIn('error', json_response)
self.assertEqual(json_response['error'], "You can't merge 2 paths with a 3rd path in the intersection")
self.logout()

def test_merge_fails_other_path_intersection_3(self):
"""
Merge should fail if other path share merge intersection
|--------C--------|
C C
| |
|--------A--------|-----------B-----------|
"""
self.login()
path_a = PathFactory.create(name="A", geom=LineString((0, 0), (10, 0)))
path_b = PathFactory.create(name="B", geom=LineString((10, 0), (20, 0)))
PathFactory.create(name="C", geom=LineString((0, 0), (0, 10), (10, 10), (10, 0)))
response = self.client.post(reverse('core:merge_path'), {'path[]': [path_a.pk, path_b.pk]})
json_response = response.json()
self.assertIn('error', json_response)
self.assertEqual(json_response['error'], "You can't merge 2 paths with a 3rd path in the intersection")
self.logout()

def test_merge_not_fail_draftpath_intersection(self):
"""
Merge should not fail
.
C (draft)
.
|--------A--------|-----------B-----------|
"""
self.login()
path_a = PathFactory.create(name="A", geom=LineString((0, 0), (10, 0)))
path_b = PathFactory.create(name="B", geom=LineString((10, 0), (20, 0)))
PathFactory.create(name="C", geom=LineString((10, 0), (10, 10)), draft=True)
response = self.client.post(reverse('core:merge_path'), {'path[]': [path_a.pk, path_b.pk]})
self.assertIn('success', response.json())
self.logout()

def test_merge_not_fail_start_point_end_point(self):
"""
Merge should not fail
|
C
|
|--------A--------|-----------B-----------|
"""
self.login()
path_a = PathFactory.create(name="A", geom=LineString((0, 0), (10, 0)))
path_b = PathFactory.create(name="B", geom=LineString((10, 0), (20, 0)))
PathFactory.create(name="C", geom=LineString((0, 0), (0, 10)))
response = self.client.post(reverse('core:merge_path'), {'path[]': [path_a.pk, path_b.pk]})
self.assertIn('success', response.json())
self.logout()

def test_merge_not_fail_start_point_end_point_2(self):
"""
Merge should not fail
|
C (reversed)
|
|--------A--------|-----------B-----------|
"""
self.login()
path_a = PathFactory.create(name="A", geom=LineString((0, 0), (10, 0)))
path_b = PathFactory.create(name="B", geom=LineString((10, 0), (20, 0)))
PathFactory.create(name="C", geom=LineString((0, 10), (0, 0)))
response = self.client.post(reverse('core:merge_path'), {'path[]': [path_a.pk, path_b.pk]})
self.assertIn('success', response.json())
self.logout()

def test_merge_not_fail_start_point_end_point_3(self):
"""
Merge should not fail
|
C
|
|--------A--------|-----------B-----------|
"""
self.login()
path_a = PathFactory.create(name="A", geom=LineString((0, 0), (10, 0)))
path_b = PathFactory.create(name="B", geom=LineString((10, 0), (20, 0)))
PathFactory.create(name="C", geom=LineString((20, 0), (20, 10)))
response = self.client.post(reverse('core:merge_path'), {'path[]': [path_a.pk, path_b.pk]})
self.assertIn('success', response.json())
self.logout()

def test_merge_not_fail_start_point_end_point_4(self):
"""
Merge should not fail
|
C (reversed)
|
|--------A--------|-----------B-----------|
"""
self.login()
path_a = PathFactory.create(name="A", geom=LineString((0, 0), (10, 0)))
path_b = PathFactory.create(name="B", geom=LineString((10, 0), (20, 0)))
PathFactory.create(name="C", geom=LineString((20, 10), (20, 0)))
response = self.client.post(reverse('core:merge_path'), {'path[]': [path_a.pk, path_b.pk]})
self.assertIn('success', response.json())
self.logout()

def test_merge_works(self):
Expand All @@ -310,6 +459,16 @@ def test_merge_works(self):
self.assertIn('success', response.json())
self.logout()

def test_merge_works_other_line(self):
self.login()
p1 = PathFactory.create(name="AB", geom=LineString((0, 0), (1, 0)))
p2 = PathFactory.create(name="BC", geom=LineString((1, 0), (2, 0)))

PathFactory.create(name="CD", geom=LineString((2, 1), (3, 1)))
response = self.client.post(reverse('core:merge_path'), {'path[]': [p1.pk, p2.pk]})
self.assertIn('success', response.json())
self.logout()

def test_merge_fails_draft_with_nodraft(self):
"""
Draft Not Draft
Expand Down

0 comments on commit da9ac4e

Please sign in to comment.