749 lines
No EOL
31 KiB
Python
749 lines
No EOL
31 KiB
Python
from django.contrib.auth import get_user_model
|
|
from django.contrib.auth.models import AnonymousUser
|
|
from django.contrib.contenttypes.models import ContentType
|
|
from django.test import TestCase
|
|
from django.urls import reverse
|
|
|
|
from common.models import Role, UserConfig
|
|
from interventions.models import Intervention
|
|
from projects.models import Project
|
|
|
|
from .models import DocumentAttachment, DocumentFolder, DocumentFolderShare, DocumentShare, ManagedDocument
|
|
from .views import ensure_document_deletable
|
|
from .permissions import (
|
|
filter_documents_for_user,
|
|
filter_folders_for_user,
|
|
get_user_visible_folder_ids,
|
|
user_has_document_permission,
|
|
)
|
|
|
|
|
|
User = get_user_model()
|
|
|
|
|
|
class DocumentPermissionTests(TestCase):
|
|
def setUp(self):
|
|
self.owner = User.objects.create_user(username="owner", password="owner")
|
|
self.shared_user = User.objects.create_user(username="shared", password="shared")
|
|
self.folder_user = User.objects.create_user(username="folder", password="folder")
|
|
self.other_user = User.objects.create_user(username="other", password="other")
|
|
self.superuser = User.objects.create_superuser(username="admin", password="admin")
|
|
|
|
self.document = ManagedDocument.objects.create(title="Doc", created_by=self.owner)
|
|
self.folder = DocumentFolder.objects.create(
|
|
name="Folder", slug="folder", created_by=self.owner
|
|
)
|
|
self.parent_folder = DocumentFolder.objects.create(
|
|
name="Parent", slug="parent-folder", created_by=self.owner
|
|
)
|
|
self.folder.parent_folders.add(self.parent_folder)
|
|
self.document.folders.add(self.folder)
|
|
|
|
DocumentShare.objects.create(
|
|
document=self.document,
|
|
user=self.shared_user,
|
|
permission=ManagedDocument.PERMISSION_COMMENT,
|
|
)
|
|
|
|
DocumentFolderShare.objects.create(
|
|
folder=self.folder,
|
|
user=self.folder_user,
|
|
permission=ManagedDocument.PERMISSION_VIEW,
|
|
)
|
|
|
|
def test_owner_has_full_access(self):
|
|
self.assertTrue(user_has_document_permission(self.owner, self.document))
|
|
self.assertTrue(
|
|
user_has_document_permission(
|
|
self.owner,
|
|
self.document,
|
|
required_permission=ManagedDocument.PERMISSION_APPROVE,
|
|
)
|
|
)
|
|
|
|
def test_share_permission_respected(self):
|
|
self.assertTrue(user_has_document_permission(self.shared_user, self.document))
|
|
self.assertFalse(
|
|
user_has_document_permission(
|
|
self.shared_user,
|
|
self.document,
|
|
required_permission=ManagedDocument.PERMISSION_EDIT,
|
|
)
|
|
)
|
|
|
|
def test_folder_share_grants_access(self):
|
|
self.assertTrue(user_has_document_permission(self.folder_user, self.document))
|
|
|
|
def test_superuser_has_access(self):
|
|
self.assertTrue(user_has_document_permission(self.superuser, self.document))
|
|
|
|
def test_anonymous_user_has_no_access(self):
|
|
self.assertFalse(user_has_document_permission(AnonymousUser(), self.document))
|
|
|
|
def test_filter_documents_for_user(self):
|
|
queryset = ManagedDocument.objects.order_by("pk")
|
|
shared_ids = set(filter_documents_for_user(queryset, self.shared_user).values_list("pk", flat=True))
|
|
folder_ids = set(filter_documents_for_user(queryset, self.folder_user).values_list("pk", flat=True))
|
|
other_ids = set(filter_documents_for_user(queryset, self.other_user).values_list("pk", flat=True))
|
|
|
|
self.assertEqual(shared_ids, {self.document.pk})
|
|
self.assertEqual(folder_ids, {self.document.pk})
|
|
self.assertEqual(other_ids, set())
|
|
|
|
def test_filter_documents_for_superuser_returns_all(self):
|
|
queryset = ManagedDocument.objects.order_by("pk")
|
|
filtered = filter_documents_for_user(queryset, self.superuser)
|
|
self.assertEqual(set(filtered.values_list("pk", flat=True)), set(queryset.values_list("pk", flat=True)))
|
|
|
|
def test_filter_folders_for_user(self):
|
|
queryset = DocumentFolder.objects.order_by("pk")
|
|
owner_ids = set(filter_folders_for_user(queryset, self.owner).values_list("pk", flat=True))
|
|
shared_ids = set(filter_folders_for_user(queryset, self.folder_user).values_list("pk", flat=True))
|
|
other_ids = set(filter_folders_for_user(queryset, self.other_user).values_list("pk", flat=True))
|
|
|
|
self.assertIn(self.folder.pk, owner_ids)
|
|
self.assertIn(self.folder.pk, shared_ids)
|
|
self.assertEqual(other_ids, set())
|
|
|
|
def test_visible_folder_ids_include_ancestors(self):
|
|
visible = get_user_visible_folder_ids(self.folder_user)
|
|
self.assertIn(self.folder.pk, visible)
|
|
self.assertIn(self.parent_folder.pk, visible)
|
|
|
|
|
|
class DocumentListViewTests(TestCase):
|
|
def setUp(self):
|
|
self.user = User.objects.create_user(username="viewer", password="viewer")
|
|
UserConfig.objects.create(user=self.user, is_intern=True)
|
|
self.client.force_login(self.user)
|
|
|
|
self.parent = DocumentFolder.objects.create(
|
|
name="Parent", slug="parent", created_by=self.user
|
|
)
|
|
self.child = DocumentFolder.objects.create(
|
|
name="Child", slug="child", created_by=self.user
|
|
)
|
|
self.grandchild = DocumentFolder.objects.create(
|
|
name="Grandchild", slug="grandchild", created_by=self.user
|
|
)
|
|
|
|
self.child.parent_folders.add(self.parent)
|
|
self.grandchild.parent_folders.add(self.child)
|
|
|
|
self.parent_doc = ManagedDocument.objects.create(
|
|
title="Parent document",
|
|
created_by=self.user,
|
|
)
|
|
self.parent_doc.folders.add(self.parent)
|
|
|
|
self.child_doc = ManagedDocument.objects.create(
|
|
title="Child note",
|
|
created_by=self.user,
|
|
)
|
|
self.child_doc.folders.add(self.child)
|
|
|
|
self.grandchild_doc = ManagedDocument.objects.create(
|
|
title="Grand strategy",
|
|
created_by=self.user,
|
|
)
|
|
self.grandchild_doc.folders.add(self.grandchild)
|
|
|
|
self.outside_folder = DocumentFolder.objects.create(name="External", slug="external")
|
|
self.outside_doc = ManagedDocument.objects.create(
|
|
title="Grand outside",
|
|
created_by=self.user,
|
|
)
|
|
self.outside_doc.folders.add(self.outside_folder)
|
|
|
|
def test_folder_filter_only_includes_direct_documents(self):
|
|
response = self.client.get(reverse("documents:list"), {"folder": self.parent.slug})
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
documents = list(response.context["documents"])
|
|
document_ids = {document.pk for document in documents}
|
|
|
|
self.assertSetEqual(
|
|
document_ids,
|
|
{self.parent_doc.pk},
|
|
)
|
|
self.assertNotIn(self.outside_doc.pk, document_ids)
|
|
|
|
def test_search_returns_descendant_folders(self):
|
|
response = self.client.get(
|
|
reverse("documents:list"),
|
|
{"folder": self.parent.slug, "search": "Grand"},
|
|
)
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
visible_folders = response.context["visible_folders"]
|
|
self.assertIn(self.grandchild, visible_folders)
|
|
self.assertNotIn(self.outside_folder, visible_folders)
|
|
self.assertNotIn(self.child, visible_folders)
|
|
|
|
listing_items = response.context["listing_items"]
|
|
self.assertTrue(
|
|
any(
|
|
item["type"] == "folder" and item["object"].pk == self.grandchild.pk
|
|
for item in listing_items
|
|
)
|
|
)
|
|
|
|
def test_search_limits_documents_to_folder_descendants(self):
|
|
response = self.client.get(
|
|
reverse("documents:list"),
|
|
{"folder": self.parent.slug, "search": "Grand"},
|
|
)
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
documents = list(response.context["documents"])
|
|
document_ids = {document.pk for document in documents}
|
|
|
|
self.assertSetEqual(document_ids, {self.grandchild_doc.pk})
|
|
self.assertNotIn(self.outside_doc.pk, document_ids)
|
|
|
|
|
|
class DocumentFolderManagementTests(TestCase):
|
|
def setUp(self):
|
|
self.owner = User.objects.create_user(username="folder-owner", password="owner")
|
|
UserConfig.objects.create(user=self.owner, is_intern=True)
|
|
self.other = User.objects.create_user(username="folder-other", password="other")
|
|
UserConfig.objects.create(user=self.other, is_intern=True)
|
|
self.admin = User.objects.create_user(username="folder-admin", password="admin")
|
|
admin_role, _ = Role.objects.get_or_create(name="admin")
|
|
admin_config = UserConfig.objects.create(user=self.admin, is_intern=True)
|
|
admin_config.roles.add(admin_role)
|
|
|
|
self.folder = DocumentFolder.objects.create(
|
|
name="Root",
|
|
slug="root",
|
|
created_by=self.owner,
|
|
)
|
|
|
|
def test_owner_can_update_folder(self):
|
|
self.client.force_login(self.owner)
|
|
response = self.client.post(
|
|
reverse("documents:folder_edit", args=[self.folder.pk]),
|
|
{
|
|
"name": "Updated",
|
|
"description": "",
|
|
"application_label": "",
|
|
"parent_folders": [],
|
|
},
|
|
)
|
|
self.assertRedirects(response, f"{reverse('documents:list')}?folder={self.folder.slug}")
|
|
|
|
self.folder.refresh_from_db()
|
|
self.assertEqual(self.folder.name, "Updated")
|
|
self.assertEqual(self.folder.created_by, self.owner)
|
|
|
|
def test_non_owner_cannot_update_folder(self):
|
|
self.client.force_login(self.other)
|
|
response = self.client.post(
|
|
reverse("documents:folder_edit", args=[self.folder.pk]),
|
|
{
|
|
"name": "Blocked",
|
|
"description": "",
|
|
"application_label": "",
|
|
"parent_folders": [],
|
|
},
|
|
)
|
|
self.assertEqual(response.status_code, 403)
|
|
|
|
def test_predefined_folder_cannot_be_modified(self):
|
|
self.folder.is_predefined = True
|
|
self.folder.save()
|
|
|
|
self.client.force_login(self.owner)
|
|
|
|
def test_admin_can_change_owner(self):
|
|
new_owner = User.objects.create_user(username="new-owner", password="new")
|
|
|
|
self.client.force_login(self.admin)
|
|
response = self.client.post(
|
|
reverse("documents:folder_edit", args=[self.folder.pk]),
|
|
{
|
|
"name": "Admin updated",
|
|
"description": "",
|
|
"application_label": "",
|
|
"parent_folders": [],
|
|
"created_by": new_owner.pk,
|
|
},
|
|
)
|
|
self.assertRedirects(response, f"{reverse('documents:list')}?folder={self.folder.slug}")
|
|
|
|
self.folder.refresh_from_db()
|
|
self.assertEqual(self.folder.created_by, new_owner)
|
|
|
|
def test_owner_can_access_share_page(self):
|
|
self.client.force_login(self.owner)
|
|
response = self.client.get(
|
|
reverse("documents:folder_share", args=[self.folder.pk])
|
|
)
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
def test_owner_can_create_share(self):
|
|
target = User.objects.create_user(username="share-target", password="pass")
|
|
self.client.force_login(self.owner)
|
|
response = self.client.post(
|
|
reverse("documents:folder_share_add", args=[self.folder.pk]),
|
|
{"user": target.pk, "permission": ManagedDocument.PERMISSION_VIEW},
|
|
)
|
|
self.assertRedirects(
|
|
response, reverse("documents:folder_share", args=[self.folder.pk])
|
|
)
|
|
self.assertTrue(
|
|
DocumentFolderShare.objects.filter(folder=self.folder, user=target).exists()
|
|
)
|
|
|
|
def test_owner_can_create_access_link(self):
|
|
self.client.force_login(self.owner)
|
|
response = self.client.post(
|
|
reverse("documents:folder_access_link", args=[self.folder.pk]),
|
|
{"permission": ManagedDocument.PERMISSION_VIEW},
|
|
)
|
|
self.assertRedirects(
|
|
response, reverse("documents:folder_share", args=[self.folder.pk])
|
|
)
|
|
self.assertEqual(self.folder.access_links.count(), 1)
|
|
|
|
def test_owner_can_delete_folder(self):
|
|
self.client.force_login(self.owner)
|
|
response = self.client.post(
|
|
reverse("documents:folder_delete", args=[self.folder.pk]),
|
|
{},
|
|
)
|
|
self.assertRedirects(response, reverse("documents:list"))
|
|
self.assertFalse(DocumentFolder.objects.filter(pk=self.folder.pk).exists())
|
|
|
|
def test_non_owner_cannot_delete_folder(self):
|
|
self.client.force_login(self.other)
|
|
response = self.client.post(
|
|
reverse("documents:folder_delete", args=[self.folder.pk]),
|
|
{},
|
|
)
|
|
self.assertEqual(response.status_code, 403)
|
|
|
|
def test_admin_can_delete_folder(self):
|
|
self.client.force_login(self.admin)
|
|
response = self.client.post(
|
|
reverse("documents:folder_delete", args=[self.folder.pk]),
|
|
{},
|
|
)
|
|
self.assertRedirects(response, reverse("documents:list"))
|
|
self.assertFalse(DocumentFolder.objects.filter(pk=self.folder.pk).exists())
|
|
|
|
def test_predefined_folder_cannot_be_deleted(self):
|
|
self.folder.is_predefined = True
|
|
self.folder.save()
|
|
|
|
self.client.force_login(self.owner)
|
|
response = self.client.post(
|
|
reverse("documents:folder_delete", args=[self.folder.pk]),
|
|
{},
|
|
)
|
|
self.assertEqual(response.status_code, 403)
|
|
|
|
def test_cannot_set_folder_as_child_of_descendant(self):
|
|
child = DocumentFolder.objects.create(name="Child", slug="child", created_by=self.owner)
|
|
child.parent_folders.add(self.folder)
|
|
|
|
self.client.force_login(self.owner)
|
|
response = self.client.post(
|
|
reverse("documents:folder_edit", args=[self.folder.pk]),
|
|
{
|
|
"name": self.folder.name,
|
|
"description": "",
|
|
"application_label": "",
|
|
"parent_folders": [child.pk],
|
|
},
|
|
)
|
|
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertIn("parent_folders", response.context["form"].errors)
|
|
|
|
def test_folder_creation_assigns_owner(self):
|
|
self.client.force_login(self.other)
|
|
response = self.client.post(
|
|
reverse("documents:folder_create"),
|
|
{
|
|
"name": "New Folder",
|
|
"description": "",
|
|
"application_label": "",
|
|
"parent_folders": [],
|
|
},
|
|
)
|
|
created_folder = DocumentFolder.objects.get(name="New Folder")
|
|
expected_redirect = f"{reverse('documents:list')}?folder={created_folder.slug}"
|
|
self.assertRedirects(response, expected_redirect)
|
|
self.assertEqual(created_folder.created_by, self.other)
|
|
|
|
|
|
class DocumentDeletionPermissionTests(TestCase):
|
|
def setUp(self):
|
|
self.owner = User.objects.create_user(username="doc-owner", password="owner")
|
|
UserConfig.objects.create(user=self.owner, is_intern=True)
|
|
self.manager = User.objects.create_user(username="doc-manager", password="manager")
|
|
manager_role, _ = Role.objects.get_or_create(name="manager")
|
|
self.manager_config = UserConfig.objects.create(user=self.manager, is_intern=True)
|
|
self.manager_config.roles.add(manager_role)
|
|
|
|
self.project = Project.objects.create(name="Project linked doc", created_by=self.owner)
|
|
self.intervention = Intervention.objects.create(title="Intervention linked doc")
|
|
self.folder = DocumentFolder.objects.create(
|
|
name="Root",
|
|
slug="root",
|
|
created_by=self.owner,
|
|
)
|
|
|
|
|
|
def test_internal_manager_can_delete_thematic_asset_document_owned_by_others(self):
|
|
from common.models import Thematic, UserThematics
|
|
from assets.models import TrafficLightIntersection
|
|
from documents.models import DocumentFolderAttachment
|
|
from django.core.exceptions import PermissionDenied
|
|
|
|
thematic, _ = Thematic.objects.get_or_create(
|
|
code="trafficlights",
|
|
defaults={"name_fr": "Signalisation Lumineuse Tricolore", "name_nl": "Verkeerslichten"}
|
|
)
|
|
UserThematics.objects.create(user_config=self.manager_config, thematic=thematic, can_edit_assets=True)
|
|
|
|
intersection = TrafficLightIntersection.objects.create(code="TL-TEST-1", name_fr="Carrefour Test 1")
|
|
root_folder = DocumentFolder.objects.create(name="Root Intersection Folder", created_by=self.owner)
|
|
sub_folder = DocumentFolder.objects.create(name="Subfolder Schemas", created_by=self.owner)
|
|
sub_folder.parent_folders.add(root_folder)
|
|
|
|
DocumentFolderAttachment.objects.create(
|
|
folder=root_folder,
|
|
content_type=ContentType.objects.get_for_model(TrafficLightIntersection),
|
|
object_id=intersection.pk,
|
|
)
|
|
|
|
other_doc = ManagedDocument.objects.create(title="Other User Doc in Subfolder", created_by=self.owner)
|
|
other_doc.folders.add(sub_folder)
|
|
|
|
# The manager with edit rights on trafficlights should be allowed to delete the document in the subfolder
|
|
ensure_document_deletable(other_doc, self.manager)
|
|
|
|
def test_internal_manager_without_edit_rights_cannot_delete_thematic_asset_document_owned_by_others(self):
|
|
from common.models import Thematic, UserThematics
|
|
from assets.models import TrafficLightIntersection
|
|
from documents.models import DocumentFolderAttachment
|
|
from django.core.exceptions import PermissionDenied
|
|
|
|
thematic, _ = Thematic.objects.get_or_create(
|
|
code="trafficlights",
|
|
defaults={"name_fr": "Signalisation Lumineuse Tricolore", "name_nl": "Verkeerslichten"}
|
|
)
|
|
# Manager has can_edit_assets=False
|
|
UserThematics.objects.create(user_config=self.manager_config, thematic=thematic, can_edit_assets=False)
|
|
|
|
intersection = TrafficLightIntersection.objects.create(code="TL-TEST-2", name_fr="Carrefour Test 2")
|
|
root_folder = DocumentFolder.objects.create(name="Root Intersection Folder 2", created_by=self.owner)
|
|
|
|
DocumentFolderAttachment.objects.create(
|
|
folder=root_folder,
|
|
content_type=ContentType.objects.get_for_model(TrafficLightIntersection),
|
|
object_id=intersection.pk,
|
|
)
|
|
|
|
other_doc = ManagedDocument.objects.create(title="Other User Doc 2", created_by=self.owner)
|
|
other_doc.folders.add(root_folder)
|
|
|
|
# Deletion should raise PermissionDenied because manager lacks edit rights on the thematic
|
|
with self.assertRaises(PermissionDenied):
|
|
ensure_document_deletable(other_doc, self.manager)
|
|
|
|
def test_document_list_view_renders_delete_button_when_user_has_permission(self):
|
|
from common.models import Thematic, UserThematics
|
|
from assets.models import TrafficLightIntersection
|
|
from documents.models import DocumentFolderAttachment
|
|
|
|
thematic, _ = Thematic.objects.get_or_create(
|
|
code="trafficlights",
|
|
defaults={"name_fr": "Signalisation Lumineuse Tricolore", "name_nl": "Verkeerslichten"}
|
|
)
|
|
UserThematics.objects.create(user_config=self.manager_config, thematic=thematic, can_edit_assets=True)
|
|
|
|
intersection = TrafficLightIntersection.objects.create(code="TL-LIST-1", name_fr="Carrefour List 1")
|
|
root_folder = DocumentFolder.objects.create(name="Root Intersection Folder List", created_by=self.owner)
|
|
|
|
DocumentFolderAttachment.objects.create(
|
|
folder=root_folder,
|
|
content_type=ContentType.objects.get_for_model(TrafficLightIntersection),
|
|
object_id=intersection.pk,
|
|
)
|
|
|
|
other_doc = ManagedDocument.objects.create(title="Other User Doc List Test", created_by=self.owner)
|
|
other_doc.folders.add(root_folder)
|
|
|
|
self.client.force_login(self.manager)
|
|
response = self.client.get(reverse("documents:list"))
|
|
self.assertEqual(response.status_code, 200)
|
|
delete_url = reverse("documents:delete", args=[other_doc.pk])
|
|
self.assertContains(response, delete_url)
|
|
|
|
def test_document_list_view_hides_delete_button_when_user_lacks_permission(self):
|
|
from common.models import Thematic, UserThematics
|
|
from assets.models import TrafficLightIntersection
|
|
from documents.models import DocumentFolderAttachment
|
|
|
|
thematic, _ = Thematic.objects.get_or_create(
|
|
code="trafficlights",
|
|
defaults={"name_fr": "Signalisation Lumineuse Tricolore", "name_nl": "Verkeerslichten"}
|
|
)
|
|
UserThematics.objects.create(user_config=self.manager_config, thematic=thematic, can_edit_assets=False)
|
|
|
|
intersection = TrafficLightIntersection.objects.create(code="TL-LIST-2", name_fr="Carrefour List 2")
|
|
root_folder = DocumentFolder.objects.create(name="Root Intersection Folder List 2", created_by=self.owner)
|
|
|
|
DocumentFolderAttachment.objects.create(
|
|
folder=root_folder,
|
|
content_type=ContentType.objects.get_for_model(TrafficLightIntersection),
|
|
object_id=intersection.pk,
|
|
)
|
|
|
|
other_doc = ManagedDocument.objects.create(title="Other User Doc List Test 2", created_by=self.owner)
|
|
other_doc.folders.add(root_folder)
|
|
|
|
self.client.force_login(self.manager)
|
|
response = self.client.get(reverse("documents:list"))
|
|
self.assertEqual(response.status_code, 200)
|
|
delete_url = reverse("documents:delete", args=[other_doc.pk])
|
|
self.assertNotContains(response, delete_url)
|
|
|
|
|
|
|
|
class SearchObjectsViewTests(TestCase):
|
|
def setUp(self):
|
|
self.user = User.objects.create_user(username="testuser", password="testpassword")
|
|
UserConfig.objects.create(user=self.user, is_intern=True)
|
|
self.document = ManagedDocument.objects.create(title="Test Document", created_by=self.user)
|
|
self.project = Project.objects.create(name="Awesome project name", created_by=self.user)
|
|
self.content_type = ContentType.objects.get_for_model(Project)
|
|
|
|
def test_search_objects_anonymous(self):
|
|
url = reverse("documents:search_objects", args=[self.document.pk])
|
|
response = self.client.get(url, {"content_type": self.content_type.pk, "q": "Awesome"})
|
|
self.assertEqual(response.status_code, 302)
|
|
|
|
def test_search_objects_authenticated(self):
|
|
self.client.force_login(self.user)
|
|
url = reverse("documents:search_objects", args=[self.document.pk])
|
|
response = self.client.get(url, {"content_type": self.content_type.pk, "q": "Awesome"})
|
|
self.assertEqual(response.status_code, 200)
|
|
data = response.json()
|
|
self.assertEqual(len(data["results"]), 1)
|
|
self.assertEqual(data["results"][0]["id"], self.project.pk)
|
|
self.assertIn("Awesome project name", data["results"][0]["text"])
|
|
|
|
|
|
class DocumentGeoreferenceTests(TestCase):
|
|
def setUp(self):
|
|
self.user = User.objects.create_user(username="geo_user", password="password")
|
|
UserConfig.objects.create(user=self.user, is_intern=True)
|
|
self.document = ManagedDocument.objects.create(title="Geo Doc", created_by=self.user)
|
|
|
|
def test_georeference_view_denied_for_anonymous(self):
|
|
url = reverse("documents:georeference", args=[self.document.pk])
|
|
response = self.client.get(url)
|
|
self.assertEqual(response.status_code, 302) # Redirect to login
|
|
|
|
def test_georeference_view_allowed_for_owner(self):
|
|
self.client.force_login(self.user)
|
|
url = reverse("documents:georeference", args=[self.document.pk])
|
|
response = self.client.get(url, {"mode": "overlay"})
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertContains(response, "Superposition")
|
|
|
|
def test_georeference_save_success(self):
|
|
self.client.force_login(self.user)
|
|
url = reverse("documents:georeference_save", args=[self.document.pk])
|
|
coords = [[4.1, 50.1], [4.2, 50.1], [4.2, 50.2], [4.1, 50.2]]
|
|
|
|
response = self.client.post(
|
|
url,
|
|
{"coordinates": coords, "page": 1},
|
|
content_type="application/json"
|
|
)
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertEqual(response.json()["status"], "success")
|
|
|
|
# Verify model updated
|
|
self.document.refresh_from_db()
|
|
self.assertEqual(self.document.georeference_coords, coords)
|
|
self.assertEqual(self.document.georeference_page, 1)
|
|
|
|
def test_georeference_save_invalid_format(self):
|
|
self.client.force_login(self.user)
|
|
url = reverse("documents:georeference_save", args=[self.document.pk])
|
|
|
|
# 3 points instead of 4
|
|
coords = [[4.1, 50.1], [4.2, 50.1], [4.2, 50.2]]
|
|
response = self.client.post(
|
|
url,
|
|
{"coordinates": coords},
|
|
content_type="application/json"
|
|
)
|
|
self.assertEqual(response.status_code, 400)
|
|
self.assertEqual(response.json()["status"], "error")
|
|
|
|
def test_map_view_not_georeferenced(self):
|
|
self.client.force_login(self.user)
|
|
url = reverse("documents:map_view", args=[self.document.pk])
|
|
response = self.client.get(url)
|
|
self.assertEqual(response.status_code, 404)
|
|
|
|
def test_map_view_georeferenced(self):
|
|
self.client.force_login(self.user)
|
|
self.document.georeference_coords = [[4.1, 50.1], [4.2, 50.1], [4.2, 50.2], [4.1, 50.2]]
|
|
self.document.save()
|
|
|
|
url = reverse("documents:map_view", args=[self.document.pk])
|
|
response = self.client.get(url)
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
|
|
from unittest.mock import patch
|
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
|
from documents.models import DocumentVersion
|
|
import os
|
|
|
|
class DocumentCadPreviewTests(TestCase):
|
|
def setUp(self):
|
|
self.user = User.objects.create_user(username="cad_user", password="password")
|
|
UserConfig.objects.create(user=self.user, is_intern=True)
|
|
self.document = ManagedDocument.objects.create(title="Cad Doc", created_by=self.user)
|
|
# Create a version with a mock DXF file
|
|
self.version = DocumentVersion.objects.create(
|
|
document=self.document,
|
|
file=SimpleUploadedFile("plan.dxf", b"DUMMY DXF CONTENT"),
|
|
uploaded_by=self.user,
|
|
version_number=1
|
|
)
|
|
|
|
@patch("documents.utils.render_cad_file_to_image")
|
|
def test_dxf_preview_rendering_and_serving(self, mock_render):
|
|
# We simulate the render_cad_file_to_image writing a mock file
|
|
def fake_render(input_path, output_path):
|
|
with open(output_path, "wb") as f:
|
|
f.write(b"MOCK PNG CONTENT")
|
|
mock_render.side_effect = fake_render
|
|
|
|
self.client.force_login(self.user)
|
|
url = reverse("documents:page_image", args=[self.document.pk, 1])
|
|
response = self.client.get(url)
|
|
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertEqual(response["Content-Type"], "image/png")
|
|
self.assertEqual(b"".join(response.streaming_content), b"MOCK PNG CONTENT")
|
|
|
|
# Verify preview file was created on disk
|
|
preview_path = self.version.file.path + ".preview.png"
|
|
self.assertTrue(os.path.exists(preview_path))
|
|
|
|
# Clean up preview file after test
|
|
if os.path.exists(preview_path):
|
|
os.remove(preview_path)
|
|
|
|
@patch("documents.utils.render_cad_file_to_image")
|
|
def test_dwg_preview_rendering_and_serving(self, mock_render):
|
|
# Create a document and version with .dwg file
|
|
doc_dwg = ManagedDocument.objects.create(title="Dwg Doc", created_by=self.user)
|
|
version_dwg = DocumentVersion.objects.create(
|
|
document=doc_dwg,
|
|
file=SimpleUploadedFile("plan.dwg", b"DUMMY DWG CONTENT"),
|
|
uploaded_by=self.user,
|
|
version_number=1
|
|
)
|
|
|
|
def fake_render(input_path, output_path):
|
|
with open(output_path, "wb") as f:
|
|
f.write(b"MOCK DWG PNG CONTENT")
|
|
mock_render.side_effect = fake_render
|
|
|
|
self.client.force_login(self.user)
|
|
url = reverse("documents:page_image", args=[doc_dwg.pk, 1])
|
|
response = self.client.get(url)
|
|
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertEqual(response["Content-Type"], "image/png")
|
|
self.assertEqual(b"".join(response.streaming_content), b"MOCK DWG PNG CONTENT")
|
|
|
|
# Clean up preview file after test
|
|
preview_path = version_dwg.file.path + ".preview.png"
|
|
if os.path.exists(preview_path):
|
|
os.remove(preview_path)
|
|
|
|
|
|
from assets.models import NatureLocation
|
|
from documents.models import DocumentFolderAttachment
|
|
|
|
class DocumentGeoreferenceAutoZoomTests(TestCase):
|
|
def setUp(self):
|
|
self.user = User.objects.create_user(username="geo_user", password="password")
|
|
UserConfig.objects.create(user=self.user, is_intern=True)
|
|
self.document = ManagedDocument.objects.create(
|
|
title="Auto Zoom Doc",
|
|
created_by=self.user
|
|
)
|
|
self.location = NatureLocation.objects.create(
|
|
code="LOC1",
|
|
name_fr="Location 1",
|
|
lon=4.3517,
|
|
lat=50.8503
|
|
)
|
|
|
|
def test_direct_attachment_coords(self):
|
|
# Create direct attachment to the geolocated asset
|
|
DocumentAttachment.objects.create(
|
|
document=self.document,
|
|
content_type=ContentType.objects.get_for_model(self.location),
|
|
object_id=self.location.pk
|
|
)
|
|
|
|
# Test helper function
|
|
from .views import _get_associated_asset_coords
|
|
coords = _get_associated_asset_coords(self.document)
|
|
self.assertEqual(coords, [4.3517, 50.8503])
|
|
|
|
# Test that view injects associated_coords into template context
|
|
self.client.force_login(self.user)
|
|
url = reverse("documents:georeference", args=[self.document.pk])
|
|
response = self.client.get(url)
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertEqual(response.context["associated_coords"], [4.3517, 50.8503])
|
|
|
|
def test_folder_attachment_coords(self):
|
|
# Create folder and associate with document
|
|
folder = DocumentFolder.objects.create(name="Geo Folder", slug="geo-folder")
|
|
self.document.folders.add(folder)
|
|
|
|
# Create folder attachment to the geolocated asset
|
|
DocumentFolderAttachment.objects.create(
|
|
folder=folder,
|
|
content_type=ContentType.objects.get_for_model(self.location),
|
|
object_id=self.location.pk
|
|
)
|
|
|
|
from .views import _get_associated_asset_coords
|
|
coords = _get_associated_asset_coords(self.document)
|
|
self.assertEqual(coords, [4.3517, 50.8503])
|
|
|
|
def test_parent_folder_attachment_coords(self):
|
|
# Create parent folder, child folder, and associate with document
|
|
parent_folder = DocumentFolder.objects.create(name="Parent Geo Folder", slug="parent-geo-folder")
|
|
child_folder = DocumentFolder.objects.create(name="Child Folder", slug="child-folder")
|
|
child_folder.parent_folders.add(parent_folder)
|
|
self.document.folders.add(child_folder)
|
|
|
|
# Create folder attachment to the parent folder
|
|
DocumentFolderAttachment.objects.create(
|
|
folder=parent_folder,
|
|
content_type=ContentType.objects.get_for_model(self.location),
|
|
object_id=self.location.pk
|
|
)
|
|
|
|
from .views import _get_associated_asset_coords
|
|
coords = _get_associated_asset_coords(self.document)
|
|
self.assertEqual(coords, [4.3517, 50.8503]) |