1 from django.test import TestCase
2 from madrona.features import *
3 from madrona.features.models import Feature, PointFeature, LineFeature, PolygonFeature, FeatureCollection
4 from madrona.features.forms import FeatureForm
5 from madrona.common.utils import kml_errors, enable_sharing
6 import os
7 import shutil
8 import json
9 from django.test.client import Client
10 from django.contrib.auth.models import *
11 from django.core.urlresolvers import reverse
12 from django.http import HttpResponse, HttpResponseForbidden
13 from django.contrib.gis.geos import GEOSGeometry
14 from django.conf import settings
18 d = os.path.dirname(__file__)
19 dpath = os.path.dirname(os.path.join(d, 'templates', path))
20 os.mkdir(dpath)
21 path = os.path.join(dpath, 'show.html')
22 f = open(path, 'w')
23 f.write('h1 />')
24 f.close()
25
27 d = os.path.dirname(__file__)
28 dpath = os.path.join(d, 'templates')
29 path = os.path.join(dpath, path)
30 path = os.path.dirname(path)
31 if os.path.exists(path):
32 shutil.rmtree(path)
33
38
42
47
51
55 form = 'madrona.features.form.FeatureForm'
56
60 form = 'madrona.features.form.FeatureForm'
61
67
71 form = 'madrona.features.form.FeatureForm'
72
76 form = 'madrona.features.form.FeatureForm'
77 show_template = 'location/show.html'
78
82 form = 'madrona.features.form.FeatureForm'
83
87 form = 'madrona.features.form.FeatureForm'
88 show_template = 'location/show.html'
89
98
100 with self.assertRaisesRegexp(FeatureConfigurationError,'not defined'):
101 @register
102 class TestFeatureFails(Feature):
103 pass
104 TestFeatureFails.get_options()
105
112 TestFeatureNoForm.get_options()
113
120 TestFeature.get_options()
121
124
129
134
144
154
161
168
173
177
183 form = 'madrona.features.form.FeatureForm'
184
186
194
196 """
197 If user not logged in they can't delete anything
198 401 status_code response
199 """
200 url = self.test_instance.get_absolute_url()
201 response = self.client.delete(url)
202 self.assertEqual(response.status_code, 401)
203
205 """
206 Don't allow just any old user to delete objects.
207 Return 403 Forbidden status code
208 """
209 other_user = User.objects.create_user(
210 'other', 'other@madrona.org', password='pword')
211 self.client.login(username=other_user.username, password='pword')
212 url = self.test_instance.get_absolute_url()
213 response = self.client.delete(url)
214 self.assertEqual(response.status_code, 403)
215
217 """
218 Staff users can delete anyone's stuff
219 """
220 staff_user = User.objects.create_user(
221 'staff', 'staff@madrona.org', password='pword')
222 staff_user.is_staff = True
223 staff_user.save()
224 pk = self.test_instance.pk
225 url = self.test_instance.get_absolute_url()
226 self.assertEqual(TestDeleteFeature.objects.filter(pk=pk).count(), 1)
227 self.client.login(username='staff', password='pword')
228 response = self.client.delete(url)
229 self.assertEqual(response.status_code, 200)
230 self.assertEqual(TestDeleteFeature.objects.filter(pk=pk).count(), 0)
231
243
263
275
280
284
307
311 form = 'madrona.features.tests.CreateTestForm'
312
316
318
325
327 response = self.client.post(self.create_url,
328 {'name': "My Test", 'user': 1})
329 self.assertEqual(response.status_code, 401)
330
339
349
351 other_user = User.objects.create_user(
352 'other', 'other@madrona.org', password='pword')
353 old_count = CreateTestFeature.objects.count()
354 self.client.login(username='featuretest', password='pword')
355 response = self.client.post(self.create_url,
356 {'name': "My Test Hack Test", 'user': other_user.pk})
357 self.assertEqual(response.status_code, 201)
358 self.assertTrue(old_count < CreateTestFeature.objects.count())
359 new_instance = CreateTestFeature.objects.get(name='My Test Hack Test')
360 self.assertNotEqual(new_instance.user, other_user)
361
366
370
414
418 form = 'madrona.features.tests.UpdateTestForm'
419
423
425
436
437 - def test_post(self):
438 self.client.login(username='featuretest', password='pword')
439 response = self.client.post(self.instance_url, {
440 'name': 'My New Name',
441 })
442 self.assertEqual(response.status_code, 200)
443
445 self.client.login(username='featuretest', password='pword')
446 response = self.client.post(self.instance_url, {
447 'name': '',
448 })
449 self.assertEqual(response.status_code, 400)
450
452 response = self.client.post(self.instance_url, {
453 'name': 'My New Name',
454 })
455 self.assertEqual(response.status_code, 401)
456
458 other_user = User.objects.create_user('other', 'other@madrona.org', password='pword')
459 self.client.login(username='other', password='pword')
460 response = self.client.post(self.instance_url, {
461 'name': 'My New Name',
462 })
463 self.assertEqual(response.status_code, 403)
464
466 other_user = User.objects.create_user('other', 'other@madrona.org', password='pword')
467 other_user.is_staff = True
468 other_user.save()
469 self.client.login(username='other', password='pword')
470 response = self.client.post(self.instance_url, {
471 'name': 'My New Name',
472 })
473 self.assertEqual(response.status_code, 200)
474
476 self.client.login(username='featuretest', password='pword')
477 response = self.client.post(self.options.get_resource(10000000), {
478 'name': 'My New Name',
479 })
480 self.assertEqual(response.status_code, 404)
481
483 other_user = User.objects.create_user('other', 'other@madrona.org', password='pword')
484 self.client.login(username='featuretest', password='pword')
485 response = self.client.post(self.instance_url, {
486 'name': 'My New Name',
487 'user': other_user.pk,
488 })
489 self.assertEqual(response.status_code, 200)
490 edited_instance = UpdateTestFeature.objects.get(pk=self.test_instance.pk)
491 self.assertNotEqual(edited_instance.user, other_user)
492
494 return HttpResponse(instance.name)
495
498
501
503 return HttpResponse(', '.join([i.name for i in instances]))
504
506
508
509 with self.assertRaises(FeatureConfigurationError):
510 link = alternate(
511 'test title',
512 'madrona.features.tests.invalid_single_select_view')
513
514
515 link = alternate('test title',
516 'madrona.features.tests.valid_single_select_view')
517 self.assertIsInstance(link, Link)
518
520
521 with self.assertRaises(FeatureConfigurationError):
522 link = alternate('test title',
523 'madrona.features.tests.invalid_multiple_select_view',
524 select='multiple')
525
526
527 link = alternate('test title',
528 'madrona.features.tests.valid_multiple_select_view',
529 select='multiple')
530 self.assertIsInstance(link, Link)
531
534
540 form = 'madrona.features.tests.LinkTestFeatureForm'
541 links = (
542 alternate('Single Select View',
543 'madrona.features.tests.valid_single_select_view',
544 type="application/shapefile"),
545
546 alternate('Spreadsheet of all Features',
547 'madrona.features.tests.valid_multiple_select_view',
548 type="application/xls",
549 select='multiple single'),
550
551 edit('Edit single feature',
552 'madrona.features.tests.valid_single_select_view'
553 ),
554
555 edit_form('Edit multiple features',
556 'madrona.features.tests.valid_multiple_select_view',
557 select='multiple single'
558 ),
559 )
560
564
566
581
587
588
589
591 options = LinkTestFeature.get_options()
592 link = options.get_link('Single Select View')
593 link2 = options.get_link('Spreadsheet of all Features')
594
595 self.client.login(username='featuretest', password='pword')
596 response = self.client.get(self.options.get_create_form())
597 self.assertEqual(response.status_code, 200)
598
599 path = link.reverse(self.test_instance)
600 response = self.client.get(path)
601 self.assertRegexpMatches(response.content, r'My Name')
602 path = link2.reverse([self.test_instance, self.i2])
603 response = self.client.get(path)
604 self.assertRegexpMatches(response.content, r'My Name, I2')
605
607 """Should not be able to perform editing actions without login.
608 """
609 link = self.options.get_link('Edit single feature')
610 link2 = self.options.get_link('Edit multiple features')
611 response = self.client.post(link.reverse(self.test_instance))
612 self.assertEqual(response.status_code, 401,response.content)
613 response = self.client.get(link2.reverse(self.test_instance))
614 self.assertEqual(response.status_code, 401)
615 self.client.login(username='featuretest', password='pword')
616 response = self.client.get(link2.reverse(self.test_instance))
617 self.assertEqual(response.status_code, 200)
618
620 """For links of rel=edit, a post request should be required.
621 """
622 link = self.options.get_link('Edit single feature')
623 self.client.login(username='featuretest', password='pword')
624 response = self.client.get(link.reverse(self.test_instance))
625 self.assertEqual(response.status_code, 405,response.content)
626 self.assertEqual(response['Allow'], 'POST')
627
629 """Should not be able to edit shapes a user doesn't own.
630 """
631 link = self.options.get_link('Edit multiple features')
632 self.client.login(username='other', password='pword')
633 response = self.client.get(link.reverse(self.test_instance))
634 self.assertEqual(response.status_code, 403)
635
637 """Should not be able to edit shapes a user doesn't own. Test to make
638 sure every feature in a request is checked.
639 """
640 link = self.options.get_link('Edit multiple features')
641 self.client.login(username='other', password='pword')
642 inst = LinkTestFeature(user=self.other_user,
643 name="Other User's feature")
644 inst.save()
645 response = self.client.get(
646 link.reverse([inst, self.test_instance]))
647 self.assertEqual(response.status_code, 403, response.content)
648
650 link = self.options.get_link('Edit multiple features')
651 self.client.login(username='featuretest', password='pword')
652 inst = LinkTestFeature(user=self.user,
653 name="feature")
654 inst.save()
655 path = link.reverse([inst, self.test_instance])
656 inst.delete()
657 response = self.client.get(path)
658 self.assertEqual(response.status_code, 404)
659
661 return HttpResponse(', '.join([i.name for i in instances]))
662
666 form = 'madrona.features.tests.GenericLinksTestForm'
667 links = (
668 alternate('Generic Link',
669 'madrona.features.tests.multi_select_view',
670 type="application/shapefile",
671 select='multiple single'),
672 alternate('Non-Generic Link',
673 'madrona.features.tests.multi_select_view',
674 type="application/shapefile",
675 select='multiple single'),
676 )
677
681
685 form = 'madrona.features.tests.OtherGenericLinksTestForm'
686 links = (
687 alternate('Generic Link',
688 'madrona.features.tests.multi_select_view',
689 type="application/shapefile",
690 select='multiple single'),
691 )
692
696
700 form = 'madrona.features.tests.GenericLinksTestForm'
701 links = (
702 alternate('Different Name',
703 'madrona.features.tests.multi_select_view',
704 type="application/shapefile",
705 select='multiple single'),
706
707 )
708
710
724
733
735 """Test that a generic view can recieve a request related to more than
736 one feature class."""
737 link = GenericLinksTestFeature.get_options().get_link("Generic Link")
738 path = link.reverse([self.generic_instance, self.other_instance])
739 self.client.login(username='featuretest', password='pword')
740 response = self.client.get(path)
741 self.assertEqual(response.status_code, 200)
742 self.assertRegexpMatches(response.content, r'Generic')
743 self.assertRegexpMatches(response.content, r'Other')
744
756
757 -def delete_w_contents(request, instances):
758 return HttpResponse('Deleted')
759
761 return HttpReponse('Report Contents')
762
764 return HttpResponse('image')
765
766 -def kml(request, instances):
767 return HttpResponse('<kml />')
768
769
770
771
772 DESIGNATION_CHOICES = (
773 ('R', 'Reserve'),
774 ('P', 'Park'),
775 ('C', 'Conservation Area')
776 )
777
778 @register
779 -class TestMpa(PolygonFeature):
780 designation = models.CharField(max_length=1, choices=DESIGNATION_CHOICES)
781
783 verbose_name = 'Marine Protected Area'
784 form = 'madrona.features.tests.MpaForm'
785 manipulators = ['madrona.manipulators.tests.TestManipulator']
786 optional_manipulators = ['madrona.manipulators.manipulators.ClipToGraticuleManipulator']
787 links = (
788 related('Habitat Spreadsheet',
789 'madrona.features.tests.habitat_spreadsheet',
790 select='single',
791 type='application/xls',
792 limit_to_groups=['SuperSpecialTestGroup']
793 ),
794 alternate('Export KML for Owner',
795 'madrona.features.tests.kml',
796 select='multiple single',
797 must_own=True
798 ),
799 alternate('Export KML',
800 'madrona.features.tests.kml',
801 select='multiple single'
802 ),
803 alternate('Export Misc for Owner',
804 'madrona.features.tests.kml',
805 select='multiple single',
806 must_own=True
807 )
808 )
809
813
814 @register
815 -class TestArray(FeatureCollection):
817 form = 'madrona.features.tests.TestArrayForm'
818 valid_children = (
819 'madrona.features.tests.TestMpa',
820 'madrona.features.tests.Pipeline',
821 'madrona.features.tests.RenewableEnergySite')
822
826
827 @register
828 -class TestFolder(FeatureCollection):
829
830 - def copy(self, user):
835
837 form = 'madrona.features.tests.TestFolderForm'
838 valid_children = (
839 'madrona.features.tests.TestMpa',
840 'madrona.features.tests.TestArray',
841 'madrona.features.tests.TestFolder',
842 'madrona.features.tests.TestDeleteFeature',
843 'madrona.features.tests.RenewableEnergySite')
844 links = (
845 edit('Delete folder and contents',
846 'madrona.features.tests.delete_w_contents',
847 select='single multiple',
848 confirm="""
849 Are you sure you want to delete this folder and it's contents?
850 This action cannot be undone.
851 """
852 ),
853 alternate('Export KML for Owner',
854 'madrona.features.tests.kml',
855 select='multiple single',
856 must_own=True
857 ),
858 alternate('Export KML',
859 'madrona.features.tests.kml',
860 select='multiple single'
861 )
862 )
863
867
868 TYPE_CHOICES = (
869 ('W', 'Wind'),
870 ('H', 'Hydrokinetic'),
871 )
875 type = models.CharField(max_length=1, choices=TYPE_CHOICES)
876
878 verbose_name = 'Renewable Energy Site'
879 form = 'madrona.features.tests.RenewableEnergySiteForm'
880 links = (
881 related('Viewshed Map',
882 'madrona.features.tests.viewshed_map',
883 select='single',
884 type='image/png'
885 ),
886 alternate('Export KML',
887 'madrona.features.tests.kml',
888 select='multiple single'
889 )
890 )
891
895
896 @register
897 -class Pipeline(LineFeature):
904
908
916
920
922
930
932 fcdict = [x for x in self.dict['feature-classes'] if x['title'] == 'Shipwreck'][0]
933 for lr in ['self','create','edit']:
934 self.assertTrue(fcdict['link-relations'][lr])
935 with self.assertRaises(KeyError):
936 fcdict['link-relations']['alternate']
937 with self.assertRaises(KeyError):
938 fcdict['link-relations']['related']
939
941 linkdict = [x for x in self.dict['generic-links'] if x['title'] == 'Generic Link'][0]
942 for f in ["features_genericlinkstestfeature", "features_othergenericlinkstestfeature"]:
943 self.assertTrue(f in linkdict['models'])
944 self.assertFalse("features_shipwreck" in linkdict['models'])
945
947 fcdict = [x for x in self.dict['feature-classes'] if x['id'] == 'features_testmpa'][0]
948 for lr in ['self','create','edit','alternate']:
949 self.assertTrue(fcdict['link-relations'][lr])
950
951 fcdict = [x for x in self.dict['feature-classes'] if x['title'] == 'LinkTestFeature'][0]
952 for lr in ['self','create','edit', 'alternate']:
953 self.assertTrue(fcdict['link-relations'][lr])
954 with self.assertRaises(KeyError):
955 fcdict['link-relations']['related']
956
958 fcdict = [x for x in self.dict['feature-classes'] if x['title'] == 'TestArray'][0]
959 self.assertTrue(fcdict['collection'])
960 self.assertEquals(len(fcdict['collection']['classes']), 3)
961
963 """ For "builtin" edit links,
964 they shouldn't show up when using workspace-shared """
965 fcdict = [x for x in self.dict['feature-classes']
966 if x['id'] == 'features_testmpa'][0]
967 self.assertEquals(fcdict['link-relations']['edit'][0]['title'], 'Edit')
968 fcdict_shared = [x for x in self.dict_shared['feature-classes']
969 if x['id'] == 'features_testmpa'][0]
970 with self.assertRaises(KeyError):
971 fcdict_shared['link-relations']['edit']
972
974 """ For generic links with must_own=True,
975 they shouldn't show up when using workspace-shared """
976
977 linkdict = [x for x in self.dict['generic-links'] if x['title'] == 'Export KML for Owner'][0]
978 self.assertTrue('features_testmpa' in linkdict['models'])
979 self.assertTrue('features_testfolder' in linkdict['models'])
980
981
982 self.assertEquals(len([x for x in self.dict_shared['generic-links']
983 if x['title'] == 'Export KML for Owner']),0)
984
986 """ For custom links with must_own=True,
987 they shouldn't show up when using workspace-shared """
988 fcdict = [x for x in self.dict['feature-classes']
989 if x['id'] == 'features_testmpa'][0]
990 self.assertEquals(fcdict['link-relations']['alternate'][0]['title'], 'Export Misc for Owner')
991 fcdict_shared = [x for x in self.dict_shared['feature-classes']
992 if x['id'] == 'features_testmpa'][0]
993 with self.assertRaises(KeyError):
994 fcdict_shared['link-relations']['alternate'][0]['title']
995
997 self.assertEquals(len(self.user.groups.filter(name="SuperSpecialTestGroup")),0)
998
999 dict_pre = json.loads(workspace_json(self.user, True))
1000 fcdict = [x for x in dict_pre['feature-classes']
1001 if x['id'] == 'features_testmpa'][0]
1002 with self.assertRaises(KeyError):
1003 fcdict['link-relations']['related'][0]['title']
1004
1005 special_group, created = Group.objects.get_or_create(name="SuperSpecialTestGroup")
1006 self.user.groups.add(special_group)
1007 self.user.save()
1008 self.assertEquals(len(self.user.groups.filter(name="SuperSpecialTestGroup")),1)
1009
1010 dict_post = json.loads(workspace_json(self.user, True))
1011 fcdict = [x for x in dict_post['feature-classes']
1012 if x['id'] == 'features_testmpa'][0]
1013 self.assertEquals(fcdict['link-relations']['related'][0]['title'], 'Habitat Spreadsheet')
1014
1016 client = Client()
1017 client.login(username='featuretest', password='pword')
1018 url = '/features/featuretest/workspace-owner.json'
1019 response = client.get(url)
1020 self.assertEqual(response.status_code, 200)
1021 self.assertEqual(response.content, self.json)
1022
1024 client = Client()
1025 client.login(username='featuretest', password='pword')
1026 url = '/features/featuretest/workspace-shared.json'
1027 response = client.get(url)
1028 self.assertEqual(response.status_code, 200)
1029 self.assertEqual(response.content, self.json_shared)
1030
1032
1034 self.client = Client()
1035
1036 self.user = User.objects.create_user(
1037 'featuretest', 'featuretest@madrona.org', password='pword')
1038 self.other_user = User.objects.create_user(
1039 'othertest', 'othertest@madrona.org', password='pword')
1040 self.group1 = Group.objects.create(name="Test Group 1")
1041 self.group1.save()
1042 self.user.groups.add(self.group1)
1043 self.other_user.groups.add(self.group1)
1044 enable_sharing(self.group1)
1045
1046 self.mpa = TestMpa(user=self.user, name="My Mpa")
1047 self.folder = TestFolder(user=self.user, name="My Folder")
1048 self.folder.save()
1049 self.mpa.save()
1050
1052 self.client.logout()
1053 link = self.mpa.options.get_link("Copy")
1054 self.assertEqual(Link, getattr(link, '__class__', None))
1055 response = self.client.post(link.reverse([self.mpa]))
1056 self.assertEqual(response.status_code, 401, response)
1057
1059 self.client.login(username='featuretest', password='pword')
1060 link = self.mpa.options.get_link("Copy")
1061 self.assertEqual(Link, getattr(link, '__class__', None))
1062 response = self.client.post(link.reverse([self.mpa]))
1063
1064
1065 self.assertRegexpMatches(response['X-Madrona-Select'],
1066 r'features_testmpa_\d+')
1067
1069 self.client.login(username='featuretest', password='pword')
1070 link = self.mpa.options.get_link("Copy")
1071 self.assertEqual(Link, getattr(link, '__class__', None))
1072 path = link.reverse([self.mpa, self.folder])
1073 response = self.client.post(path)
1074
1075
1076
1077 self.assertRegexpMatches(response['X-Madrona-Select'],
1078 r'features_testmpa_\d+ features_testfolder_\d+')
1079
1081 self.mpa.share_with(self.group1)
1082 self.client.login(username='othertest', password='pword')
1083 link = self.mpa.options.get_link("Copy")
1084 self.assertEqual(Link, getattr(link, '__class__', None))
1085 response = self.client.post(link.reverse([self.mpa]))
1086
1087
1088 self.assertRegexpMatches(response['X-Madrona-Select'],
1089 r'features_testmpa_\d')
1090
1092
1094 self.client = Client()
1095 self.user = User.objects.create_user(
1096 'featuretest', 'featuretest@madrona.org', password='pword')
1097 self.client.login(username='featuretest', password='pword')
1098
1099 g3 = GEOSGeometry('SRID=4326;POINT(-120.45 34.32)')
1100 g3.transform(settings.GEOMETRY_DB_SRID)
1101 self.wreck = Shipwreck(user=self.user, name="Nearby Wreck", geometry_final=g3)
1102 self.wreck.save()
1103
1104 g2 = GEOSGeometry('SRID=4326;LINESTRING(-120.42 34.37, -121.42 33.37)')
1105 g2.transform(settings.GEOMETRY_DB_SRID)
1106 self.pipeline = Pipeline(user=self.user, name="My Pipeline", geometry_final=g2)
1107 self.pipeline.save()
1108
1109 g1 = GEOSGeometry('SRID=4326;POLYGON((-120.42 34.37, -119.64 34.32, -119.63 34.12, -120.44 34.15, -120.42 34.37))')
1110 g1.transform(settings.GEOMETRY_DB_SRID)
1111 self.mpa = TestMpa(user=self.user, name="My Mpa", geometry_orig=g1)
1112
1113 self.mpa.save()
1114
1116 self.assertTrue(isinstance(self.wreck, PointFeature))
1117 self.assertEqual(self.wreck.geometry_final.geom_type,'Point')
1118
1119 self.assertTrue(isinstance(self.pipeline, LineFeature))
1120 self.assertEqual(self.pipeline.geometry_final.geom_type,'LineString')
1121
1122 self.assertTrue(isinstance(self.mpa, PolygonFeature))
1123 self.assertEqual(self.mpa.geometry_final.geom_type,'Polygon')
1124
1126 link = self.wreck.options.get_link('KML')
1127 url = link.reverse(self.wreck)
1128 response = self.client.get(url)
1129 errors = kml_errors(response.content)
1130 self.assertFalse(errors,"invalid KML %s" % str(errors))
1131
1133 link = self.pipeline.options.get_link('KML')
1134 url = link.reverse(self.pipeline)
1135 response = self.client.get(url)
1136 errors = kml_errors(response.content)
1137 self.assertFalse(errors,"invalid KML %s" % str(errors))
1138
1140 link = self.mpa.options.get_link('KML')
1141 url = link.reverse(self.mpa)
1142 response = self.client.get(url)
1143 errors = kml_errors(response.content)
1144 self.assertFalse(errors,"invalid KML %s" % str(errors))
1145
1147
1149 self.client = Client()
1150
1151 self.user1 = User.objects.create_user(
1152 'user1', 'featuretest@madrona.org', password='pword')
1153 self.user2 = User.objects.create_user(
1154 'user2', 'othertest@madrona.org', password='pword')
1155
1156 self.mpa1 = TestMpa(user=self.user1, name="My Mpa")
1157 self.mpa1.save()
1158 self.mpa2 = TestMpa(user=self.user1, name="My Mpa 2")
1159 self.mpa2.save()
1160 self.folder1 = TestFolder(user=self.user1, name="My Folder")
1161 self.folder1.save()
1162 self.folder2 = TestFolder(user=self.user1, name="My Folder2")
1163 self.folder2.save()
1164 self.pipeline = Pipeline(user=self.user1, name="My Pipeline")
1165 self.pipeline.save()
1166 self.mpa3 = TestMpa(user=self.user2, name="User2s MPA")
1167 self.mpa3.save()
1168
1179
1181 self.folder1.add(self.mpa1)
1182 self.assertEqual(self.mpa1.collection, self.folder1)
1183 self.assertTrue(self.mpa1 in self.folder1.feature_set())
1184
1185 self.folder1.remove(self.mpa1)
1186 self.assertEqual(self.mpa1.collection, None)
1187 self.assertTrue(self.mpa1 not in self.folder1.feature_set())
1188
1189 self.assertRaises(AssertionError, self.folder1.add, self.mpa3)
1190
1192 """
1193 When checking which mpas belong to folder1 we can:
1194 * look only at immediate children
1195 * look for children of a given feature class
1196 * look recursively through all containers
1197
1198 folder1
1199 |- mpa1
1200 |- folder2
1201 | - mpa2
1202 """
1203 self.folder1.add(self.mpa1)
1204 self.folder2.add(self.mpa2)
1205 self.folder1.add(self.folder2)
1206
1207 direct_children = self.folder1.feature_set(recurse=False)
1208 self.assertEqual(len(direct_children), 2)
1209 self.assertTrue(self.mpa1 in direct_children)
1210 self.assertTrue(self.folder2 in direct_children)
1211 self.assertTrue(self.mpa2 not in direct_children)
1212
1213 direct_mpa_children = self.folder1.feature_set(recurse=False,feature_classes=[TestMpa])
1214 self.assertEqual(len(direct_mpa_children), 1)
1215 self.assertTrue(self.mpa1 in direct_mpa_children)
1216 self.assertTrue(self.folder2 not in direct_mpa_children)
1217 self.assertTrue(self.mpa2 not in direct_mpa_children)
1218
1219 recursive_mpa_children = self.folder1.feature_set(recurse=True,feature_classes=[TestMpa])
1220 self.assertEqual(len(recursive_mpa_children), 2)
1221 self.assertTrue(self.mpa1 in recursive_mpa_children)
1222 self.assertTrue(self.folder2 not in recursive_mpa_children)
1223 self.assertTrue(self.mpa2 in recursive_mpa_children)
1224
1226 """
1227 folder1
1228 |- mpa1
1229 |- folder2
1230 | - mpa2
1231 | - folder3
1232 |- mpa3
1233 |- folder4
1234 |- mpa4
1235 |- mpa5
1236 """
1237 mpa3 = TestMpa(user=self.user1, name="My Mpa")
1238 mpa3.save()
1239 mpa4 = TestMpa(user=self.user1, name="My Mpa 2")
1240 mpa4.save()
1241 mpa5 = TestMpa(user=self.user1, name="My Mpa 2")
1242 mpa5.save()
1243 folder3 = TestFolder(user=self.user1, name="My Folder")
1244 folder3.save()
1245 folder4 = TestFolder(user=self.user1, name="My Folder2")
1246 folder4.save()
1247
1248 self.folder1.add(self.mpa1)
1249 self.folder2.add(self.mpa2)
1250 self.folder1.add(self.folder2)
1251 self.folder2.add(folder3)
1252 folder3.add(folder4)
1253 folder3.add(mpa3)
1254 folder4.add(mpa4)
1255 folder4.add(mpa5)
1256
1257 recursive_mpa_children = self.folder1.feature_set(recurse=True,feature_classes=[TestMpa])
1258 self.assertEqual(len(recursive_mpa_children), 5)
1259 self.assertTrue(self.mpa1 in recursive_mpa_children)
1260 self.assertTrue(mpa5 in recursive_mpa_children)
1261 self.assertTrue(folder4 not in recursive_mpa_children)
1262
1263 recursive_children = self.folder1.feature_set(recurse=True)
1264 self.assertEqual(len(recursive_children), 8)
1265 self.assertTrue(self.mpa1 in recursive_children)
1266 self.assertTrue(mpa5 in recursive_children)
1267 self.assertTrue(folder4 in recursive_children)
1268
1270 """
1271 Folder (of which TestArray is a valid child but Pipeline is NOT)
1272 TestArray (of which Pipeline is a valid child)
1273 Therefore, Folder is also a potential parent of Pipeline
1274
1275 folder1
1276 |-my_array
1277 |-self.pipeline
1278 |-self.mpa1
1279 """
1280 pipeline_parents = Pipeline.get_options().get_potential_parents()
1281 self.assertTrue(TestArray in pipeline_parents)
1282 self.assertTrue(self.folder1.__class__ in pipeline_parents)
1283
1284 my_array = TestArray(user=self.user1, name="My TestArray")
1285 my_array.save()
1286 my_array.add(self.pipeline)
1287 my_array.add(self.mpa1)
1288 self.assertTrue(self.pipeline in my_array.feature_set())
1289
1290 self.folder1.add(my_array)
1291 self.assertTrue(my_array in self.folder1.feature_set())
1292 self.assertTrue(self.pipeline in self.folder1.feature_set(recurse=True))
1293
1299
1301 """
1302 Try to add a Pipeline to Folder; feature.add has a runtime assertion so
1303 this should raise an AssertionError
1304 """
1305 self.assertRaises(AssertionError, self.folder1.add, self.pipeline)
1306
1308 """
1309 folder1 copied to folder1-copy
1310 make sure it contains mpa1-copy, mpa2-copy and folder2-copy
1311 """
1312 self.folder1.add(self.mpa1)
1313 self.folder2.add(self.mpa2)
1314 self.folder1.add(self.folder2)
1315 folder1_copy = self.folder1.copy(self.user1)
1316 folder1_copy.save()
1317 children = folder1_copy.feature_set(recurse=True)
1318 self.assertEqual(len(children),3,
1319 "Folder1_copy should contain copies folder2, mpa1, mpa2 but doesn't")
1320
1322
1324 self.client = Client()
1325
1326
1327 self.password = 'iluvsharing'
1328 self.user1 = User.objects.create_user('user1', 'test@madrona.org', password=self.password)
1329 self.user2 = User.objects.create_user('user2', 'test@madrona.org', password=self.password)
1330 self.user3 = User.objects.create_user('user3', 'test@madrona.org', password=self.password)
1331
1332
1333
1334
1335
1336 self.group1 = Group.objects.create(name="Test Group 1")
1337 self.group1.save()
1338 self.user1.groups.add(self.group1)
1339 self.user2.groups.add(self.group1)
1340
1341 self.group2 = Group.objects.create(name="Test Group 2")
1342 self.group2.save()
1343 self.user2.groups.add(self.group2)
1344 self.user3.groups.add(self.group2)
1345
1346 self.group3 = Group.objects.create(name="Test Group 3")
1347 self.group3.save()
1348 self.user1.groups.add(self.group3)
1349
1350 enable_sharing(self.group1)
1351
1352
1353 g1 = GEOSGeometry('SRID=4326;POLYGON ((-120.42 34.37, -119.64 34.32, -119.63 34.12, -120.44 34.15, -120.42 34.37))')
1354 g1.transform(settings.GEOMETRY_DB_SRID)
1355
1356
1357 self.mpa1 = TestMpa.objects.create(name='Test_MPA_1', designation='R', user=self.user1, geometry_final=g1)
1358 self.mpa1.save()
1359
1360 self.mpa2 = TestMpa.objects.create(name='Test_MPA_2', designation='R', user=self.user2, geometry_final=g1)
1361 self.mpa2.save()
1362
1363 self.mpa3 = TestMpa.objects.create(name='Test_MPA_3', designation='R', user=self.user3, geometry_final=g1)
1364 self.mpa3.save()
1365
1366
1367 self.pipeline1 = Pipeline(user=self.user1, name="My Pipeline")
1368 self.pipeline1.save()
1369
1370
1371
1372
1373
1374
1375 self.array1 = TestArray.objects.create(name='Test_Array_1', user=self.user1)
1376 self.array1.save()
1377 self.array1.add(self.mpa1)
1378 self.array1.add(self.pipeline1)
1379
1380 self.folder1 = TestFolder.objects.create(user=self.user1, name="My Folder")
1381 self.folder1.save()
1382 self.folder1.add(self.array1)
1383
1384 self.folder1_share_url = self.folder1.get_options().get_share_form(self.folder1.pk)
1385 self.folder1_resource_url = self.folder1.get_options().get_resource(self.folder1.pk)
1386
1388
1389 viewable, response = self.pipeline1.is_viewable(self.user2)
1390 self.assertEquals(viewable, False)
1391 viewable, response = self.pipeline1.is_viewable(self.user3)
1392 self.assertEquals(viewable, False)
1393
1394
1395 self.folder1.share_with(self.group1)
1396 viewable, response = self.array1.is_viewable(self.user2)
1397 self.assertEquals(viewable, True, str(response.status_code) + str(response))
1398 viewable, response = self.array1.is_viewable(self.user3)
1399 self.assertEquals(viewable, False)
1400
1401 viewable, response = self.pipeline1.is_viewable(self.user2)
1402 self.assertEquals(viewable, True, str(response.status_code) + str(response))
1403 viewable, response = self.pipeline1.is_viewable(self.user3)
1404 self.assertEquals(viewable, False)
1405
1415
1417 """
1418 Make sure nothing is shared yet
1419 """
1420 shared_mpas = TestMpa.objects.shared_with_user(self.user1)
1421 self.assertEquals(len(shared_mpas),0)
1422
1424 """
1425 Make sure the basic sharing of mpas works
1426 via the object manager (for returning querysets)
1427 """
1428
1429 self.mpa2.share_with(self.group1)
1430
1431 shared_mpas = TestMpa.objects.shared_with_user(self.user1)
1432 self.assertEquals(len(shared_mpas),1)
1433
1434 shared_mpas = TestMpa.objects.shared_with_user(self.user3)
1435 self.assertEquals(len(shared_mpas),0)
1436
1438 """
1439 Make sure the basic sharing of mpas works
1440 via the feature method (check viewability of particular instance)
1441 """
1442
1443 self.mpa2.share_with(self.group1)
1444
1445 viewable, response = self.mpa2.is_viewable(self.user2)
1446 self.assertEquals(viewable, True)
1447
1448 viewable, response = self.mpa2.is_viewable(self.user1)
1449 self.assertEquals(viewable, True)
1450
1451 viewable, response = self.mpa2.is_viewable(self.user3)
1452 self.assertEquals(response.status_code, 403)
1453 self.assertEquals(viewable, False)
1454
1456 """
1457 Make sure we can't share with a group which does not have permissions
1458 """
1459
1460
1461 error_occured = False
1462 try:
1463 self.mpa2.share_with(self.group2)
1464 except:
1465 error_occured = True
1466 self.assertTrue(error_occured)
1467
1469 """
1470 Make sure user not belonging to the group can't share their objects
1471 """
1472
1473 error_occured = False
1474 try:
1475 self.mpa3.share_with(self.group1)
1476 except:
1477 error_occured = True
1478 self.assertTrue(error_occured)
1479
1481 """
1482 Arrays are containers of MPAs so their child objects should also appear to be shared
1483 Uses the class object manager
1484 """
1485
1486 self.array1.share_with(self.group1)
1487
1488 shared_mpas = TestMpa.objects.shared_with_user(self.user2)
1489 self.assertEquals(len(shared_mpas),1)
1490
1491 shared_mpas = TestMpa.objects.shared_with_user(self.user3)
1492 self.assertEquals(len(shared_mpas),0)
1493
1495 """
1496 Arrays are containers of MPAs so their child objects should also appear to be shared
1497 Uses the feature's is_viewable() method
1498 """
1499
1500 self.array1.share_with(self.group1)
1501
1502 viewable, response = self.mpa1.is_viewable(self.user1)
1503 self.assertEquals(viewable, True)
1504
1505 viewable, response = self.mpa1.is_viewable(self.user2)
1506 self.assertEquals(viewable, True)
1507
1508 viewable, response = self.mpa1.is_viewable(self.user3)
1509 self.assertEquals(viewable, False)
1510
1512 """
1513 Test if we can get a list of groups and users who are sharing with a given user
1514 """
1515
1516 self.mpa1.share_with(self.group1)
1517
1518 sw = groups_users_sharing_with(self.user1)
1519 self.assertEquals(sw,None)
1520
1521 sw = groups_users_sharing_with(self.user2)
1522 self.assertNotEquals(sw,None)
1523 usernames = [x.username for x in sw['Test Group 1']['users']]
1524 self.assertEquals(usernames, ['user1'])
1525
1526 sw = groups_users_sharing_with(self.user3)
1527 self.assertEquals(sw, None)
1528
1533
1539
1557
1559
1560 self.client.login(username=self.user2.username, password=self.password)
1561 response = self.client.get(self.folder1_resource_url)
1562 self.assertEqual(response.status_code, 403)
1563
1564
1565 self.client.logout()
1566 self.client.login(username=self.user1.username, password=self.password)
1567 response = self.client.post(self.folder1_share_url, {'sharing_groups': [self.group1.pk]})
1568 self.assertEqual(response.status_code, 200, response.content)
1569
1570
1571 self.client.logout()
1572 self.client.login(username=self.user2.username, password=self.password)
1573 response = self.client.get(self.folder1_resource_url)
1574 self.assertEqual(response.status_code, 200)
1575
1589
1593
1600
1604
1611
1615
1617
1619 self.client = Client()
1620 self.user = User.objects.create_user(
1621 'featuretest', 'featuretest@madrona.org', password='pword')
1622 self.user2 = User.objects.create_user(
1623 'joerando', 'featuretest@madrona.org', password='pword')
1624 self.group1 = Group.objects.create(name="Test Group 1")
1625 self.user.groups.add(self.group1)
1626 self.user2.groups.add(self.group1)
1627 enable_sharing(self.group1)
1628 self.client.login(username='featuretest', password='pword')
1629
1630 g1 = GEOSGeometry('SRID=4326;POLYGON((-120.42 34.37, -119.64 34.32, -119.63 34.12, -120.44 34.15, -120.42 34.37))')
1631 g1.transform(settings.GEOMETRY_DB_SRID)
1632
1633 '''
1634 mpa3
1635 folder1
1636 |- mpa1
1637 |- folder2
1638 | - mpa2
1639 '''
1640 self.mpa1 = TestMpa.objects.create(user=self.user, name="Mpa1", geometry_orig=g1)
1641 self.mpa2 = TestMpa.objects.create(user=self.user, name="Mpa2", geometry_orig=g1)
1642 self.mpa3 = TestMpa.objects.create(user=self.user, name="Mpa3", geometry_orig=g1)
1643 self.mpa4 = TestMpa.objects.create(user=self.user2, name="Mpa4", geometry_orig=g1)
1644 self.mpa5 = TestForGeoJSON.objects.create(user=self.user, name="Mpa5", geometry_orig=g1)
1645 self.mpa6 = TestNoGeomFinal.objects.create(user=self.user, name="Mpa6")
1646 self.mpa7 = TestNoGeoJSON.objects.create(user=self.user, name="Mpa7", geometry_orig=g1)
1647 self.folder1 = TestFolder.objects.create(user=self.user, name="Folder1")
1648 self.folder2 = TestFolder.objects.create(user=self.user, name="Folder2")
1649 self.folder1.add(self.mpa1)
1650 self.folder2.add(self.mpa2)
1651 self.folder1.add(self.folder2)
1652
1653
1655 link = self.mpa3.options.get_link('GeoJSON')
1656 url = link.reverse(self.mpa3)
1657 response = self.client.get(url)
1658 self.assertEqual(response.status_code, 200)
1659 self.assertTrue('application/json' in response['Content-Type'])
1660 fc = json.loads(response.content)
1661 self.assertEquals(fc['features'][0]['properties']['name'], 'Mpa3')
1662 self.assertEquals(len(fc['features']), 1)
1663
1665 """
1666 Mpa5 has a custom geojson @property that should
1667 return a GeoJSON Feature with an extra `absolute_url` property
1668 """
1669 link = self.mpa5.options.get_link('GeoJSON')
1670 url = link.reverse(self.mpa5)
1671 response = self.client.get(url)
1672 self.assertEqual(response.status_code, 200)
1673 self.assertTrue('application/json' in response['Content-Type'])
1674 fc = json.loads(response.content)
1675 self.assertEquals(fc['features'][0]['properties']['absolute_url'], self.mpa5.get_absolute_url())
1676 self.assertEquals(len(fc['features']), 1)
1677
1679 """
1680 Mpa6 has no geometry_final attr
1681 should fail gracefully with null geometry
1682 """
1683 link = self.mpa6.options.get_link('GeoJSON')
1684 url = link.reverse(self.mpa6)
1685 response = self.client.get(url)
1686 self.assertEqual(response.status_code, 200)
1687 fc = json.loads(response.content)
1688 self.assertEquals(fc['features'][0]['geometry'], None)
1689
1691 """
1692 This one has export_geojson = False
1693 so no link should be available
1694 """
1695 with self.assertRaisesRegexp(Exception, 'has no link named GeoJSON'):
1696 link = self.mpa7.options.get_link('GeoJSON')
1697
1699 """
1700 We expect default 'flat' behavior
1701
1702 FeatureCollection:
1703 mpa1
1704 mpa2
1705 """
1706 link = self.folder1.options.get_link('GeoJSON')
1707 url = link.reverse(self.folder1)
1708 response = self.client.get(url)
1709 self.assertEqual(response.status_code, 200)
1710 self.assertTrue('application/json' in response['Content-Type'])
1711 fc = json.loads(response.content)
1712 self.assertTrue(fc['features'][0]['properties']['name'] in ['Mpa1','Mpa2'])
1713 self.assertTrue(fc['features'][1]['properties']['name'] in ['Mpa1','Mpa2'])
1714 self.assertEquals(len(fc['features']), 2, fc)
1715
1717 """
1718 We expect custom 'nest_feature_set' behavior
1719
1720 FeatureCollection:
1721 folder1 (with a `feature_set` property listing uids and null geom)
1722 """
1723 link = self.folder1.options.get_link('GeoJSON')
1724 url = link.reverse(self.folder1) + "?strategy=nest_feature_set"
1725 response = self.client.get(url)
1726 self.assertEqual(response.status_code, 200)
1727 self.assertTrue('application/json' in response['Content-Type'])
1728 fc = json.loads(response.content)
1729 self.assertEquals(fc['features'][0]['properties']['feature_set'], [x.uid for x in [self.mpa1, self.folder2]])
1730 self.assertEquals(len(fc['features']), 1)
1731
1733 """
1734 We expect custom 'nest_feature_set' behavior
1735
1736 FeatureCollection:
1737 mpa1
1738 folder2 (with a `feature_set` property listing uids and null geom)
1739 """
1740 link = self.folder1.options.get_link('GeoJSON')
1741 url = link.reverse([self.mpa1, self.folder2]) + "?strategy=nest_feature_set"
1742 response = self.client.get(url)
1743 self.assertEqual(response.status_code, 200)
1744 self.assertTrue('application/json' in response['Content-Type'])
1745 fc = json.loads(response.content)
1746 self.assertEquals(fc['features'][0]['properties']['name'], 'Mpa1')
1747 self.assertEquals(fc['features'][1]['properties']['feature_set'], [self.mpa2.uid])
1748 self.assertEquals(len(fc['features']), 2)
1749
1751 self.client.logout()
1752 self.client.login(username='joerando', password='pword')
1753 link = self.folder1.options.get_link('GeoJSON')
1754
1755 url = link.reverse([self.mpa4, self.folder2])
1756 response = self.client.get(url)
1757 self.assertEqual(response.status_code, 403)
1758 self.folder2.share_with(self.group1)
1759 response = self.client.get(url)
1760 self.assertEqual(response.status_code, 200)
1761 fc = json.loads(response.content)
1762 self.assertEquals(len(fc['features']), 2)
1763
1786
1788 link = self.mpa3.options.get_link('GeoJSON')
1789
1790 url = link.reverse(self.mpa3)
1791 response = self.client.get(url)
1792 self.assertEqual(response.status_code, 200)
1793 self.assertTrue('Content-Disposition' in response)
1794 self.assertTrue('attachment; filename=mpa3.geojson' in response['Content-Disposition'])
1795
1796 url = link.reverse(self.mpa3) + "?noattach"
1797 response = self.client.get(url)
1798 self.assertEqual(response.status_code, 200)
1799 self.assertFalse('Content-Disposition' in response)
1800
1801 settings.GEOJSON_DOWNLOAD = False
1802 url = link.reverse(self.mpa3)
1803 response = self.client.get(url)
1804 self.assertEqual(response.status_code, 200)
1805 self.assertFalse('Content-Disposition' in response)
1806
1807 url = link.reverse(self.mpa3) + "?attach"
1808 response = self.client.get(url)
1809 self.assertEqual(response.status_code, 200)
1810 self.assertTrue('Content-Disposition' in response)
1811 self.assertTrue('attachment; filename=mpa3.geojson' in response['Content-Disposition'])
1812
1813 settings.GEOJSON_DOWNLOAD = True
1814
1821