aboutsummaryrefslogtreecommitdiffstats
path: root/ctrack
diff options
context:
space:
mode:
authorMatthew Lemon <lemon@matthewlemon.com>2020-10-19 16:21:03 +0100
committerMatthew Lemon <lemon@matthewlemon.com>2020-10-19 16:25:09 +0100
commit9cc3de6d0245bdc4ed87b810a2208efdd09b6277 (patch)
tree2987cca4ef6eb58fa2e6817c40fb920707f167b4 /ctrack
parentbb39f7f52d5ff6dcf311d9e2a987417796e09424 (diff)
can now filter out private events not belonging to logged in user
Diffstat (limited to 'ctrack')
-rw-r--r--ctrack/organisations/tests/test_views.py137
-rw-r--r--ctrack/organisations/utils.py13
-rw-r--r--ctrack/organisations/views.py14
3 files changed, 160 insertions, 4 deletions
diff --git a/ctrack/organisations/tests/test_views.py b/ctrack/organisations/tests/test_views.py
index dbd717f..a567fab 100644
--- a/ctrack/organisations/tests/test_views.py
+++ b/ctrack/organisations/tests/test_views.py
@@ -9,8 +9,8 @@ from ctrack.organisations.tests.factories import (
OrganisationFactory,
SingleDateTimeEventFactory,
)
-from ctrack.organisations.views import IncidentReportCreateView
-
+from ctrack.organisations.views import IncidentReportCreateView, OrganisationDetailView
+from ..utils import filter_private_events
from ..views import OrganisationListView
pytestmark = pytest.mark.django_db
@@ -42,6 +42,139 @@ def test_meetings_in_organisation_detail_view(user, client, org_with_people):
assert "First Meeting" in html
+def test_private_event_filter(user, org_with_people):
+ """
+ In this test we are creating five events, using two different users.
+ Each event will be set to either private or not private. We are testing
+ a function that will only allow private notes belonging to the logged in,
+ or request.user user to be added to the view context. The context is not
+ referred to here - only the utility function under test. The output from
+ that filter function will go forward into the view context.
+ """
+ person = org_with_people.person_set.first()
+ e1_user = SingleDateTimeEventFactory(
+ type_descriptor="MEETING",
+ short_description="First Event with user",
+ private=True,
+ user=user,
+ )
+ e2_user = SingleDateTimeEventFactory(
+ type_descriptor="MEETING",
+ short_description="Second Event with user",
+ private=False,
+ user=user,
+ )
+ e3_user = SingleDateTimeEventFactory(
+ type_descriptor="MEETING",
+ short_description="Third Event with user",
+ private=True,
+ user=user,
+ )
+ e1_user.participants.add(person)
+ e1_user.save()
+ e2_user.participants.add(person)
+ e2_user.save()
+ e3_user.participants.add(person)
+ e3_user.save()
+ user2 = get_user_model().objects.create(username="sam", email="asd@asdsd.com", password="123")
+ e1_user2 = SingleDateTimeEventFactory(
+ type_descriptor="MEETING",
+ short_description="First Event with user2",
+ private=False,
+ user=user2,
+ )
+ e2_user2 = SingleDateTimeEventFactory(
+ type_descriptor="MEETING",
+ short_description="Second Event with user2",
+ private=True,
+ user=user2,
+ )
+ e1_user2.participants.add(person)
+ e1_user2.save()
+ e2_user2.participants.add(person)
+ e2_user2.save()
+ # This user needs permission to access the list view
+ org_list_permission = Permission.objects.get(name="Can view organisation")
+ assert user.user_permissions.count() == 0
+ user.user_permissions.add(org_list_permission)
+ assert user.has_perm("organisations.view_organisation")
+ user.save()
+ factory = RequestFactory()
+ request = factory.get(reverse("organisations:detail", args=[org_with_people.slug]))
+ request.user = user
+ response = OrganisationDetailView.as_view()(request, slug=org_with_people.slug)
+ assert response.status_code == 200
+ events = person.get_single_datetime_events()
+ assert events.count() == 5
+ assert len(filter_private_events(events, user2)) == 3
+
+
+def test_logged_in_user_can_only_see_their_private_events(
+ user, org_with_people, client
+):
+ org_list_permission = Permission.objects.get(name="Can view organisation")
+ assert user.user_permissions.count() == 0
+ user.user_permissions.add(org_list_permission)
+ assert user.has_perm("organisations.view_organisation")
+ user.save()
+ person = org_with_people.person_set.first()
+
+ # This user creates three events
+ e1 = SingleDateTimeEventFactory(
+ type_descriptor="MEETING",
+ short_description="First Event",
+ private=True,
+ user=user,
+ )
+ e2 = SingleDateTimeEventFactory(
+ type_descriptor="MEETING",
+ short_description="Second Event",
+ private=False,
+ user=user,
+ )
+ e3 = SingleDateTimeEventFactory(
+ type_descriptor="MEETING",
+ short_description="Third Event",
+ private=True,
+ user=user,
+ )
+ e1.participants.add(person)
+ e1.save()
+ e2.participants.add(person)
+ e2.save()
+ e3.participants.add(person)
+ e3.save()
+ response = client.get(
+ reverse("organisations:detail", kwargs={"slug": org_with_people.slug})
+ )
+ assert response.status_code == 200
+ html = response.content.decode("utf-8")
+ assert "First Event" in html
+ assert "Second Event" in html
+ assert "Third Event" in html
+ assert "PRIVATE" in html
+
+ # A second user adds events based on this person/organisation
+ user2 = get_user_model().objects.create(
+ username="bobbins", email="bobbins@gog.com", password="bobbins123345"
+ )
+ user2.user_permissions.add(org_list_permission)
+ assert user2.has_perm("organisations.view_organisation")
+ user2.save()
+ client.logout()
+ client.force_login(user2)
+ response2 = client.get(
+ reverse("organisations:detail", kwargs={"slug": org_with_people.slug})
+ )
+ html2 = response2.content.decode("utf-8")
+ assert response2.status_code == 200
+ # They should not be able to see First Event which was created by another
+ # user and marked private.
+ assert "First Event" not in html2
+ assert "Second Event" in html2
+ assert "Third Event" not in html2
+
+
# https://docs.djangoproject.com/en/3.0/topics/testing/advanced/#example
def test_organisation_list_view():
OrganisationFactory.create()
diff --git a/ctrack/organisations/utils.py b/ctrack/organisations/utils.py
new file mode 100644
index 0000000..121a694
--- /dev/null
+++ b/ctrack/organisations/utils.py
@@ -0,0 +1,13 @@
+from django.contrib.auth.models import User
+from django.db.models import QuerySet, Q
+
+
+def filter_private_events(events: QuerySet, user: User):
+ """
+ Given a QuerySet containing SingleDateTimeEvent objects,
+ ensure that any objects whose user==user and private==True
+ are filtered out. This supports OrganisationDetailView, which
+ lists all events for an organisation but which must hide private
+ events for the logged-in user.
+ """
+ return events.exclude(~Q(user=user) & Q(private=True))
diff --git a/ctrack/organisations/views.py b/ctrack/organisations/views.py
index e8affdb..81af8d4 100644
--- a/ctrack/organisations/views.py
+++ b/ctrack/organisations/views.py
@@ -16,6 +16,9 @@ from .models import IncidentReport, Organisation, Person
# TODO - needs a permission on this view
+from .utils import filter_private_events
+
+
def essential_service_detail(request, pk):
es = EssentialService.objects.get(pk=pk)
org = es.organisation
@@ -87,12 +90,19 @@ class OrganisationDetailView(PermissionRequiredMixin, DetailView):
cafs = org.caf_set.all()
# simple datetime events for org
- _sdes = [person.get_single_datetime_events() for person in peoples]
+ _sdes = [
+ filter_private_events(
+ person.get_single_datetime_events(), self.request.user
+ )
+ for person in peoples
+ ]
flat_sdes = list(itertools.chain.from_iterable(_sdes))
# Some events will not involve a participant, which is what ties an event to an organisation.
# Because we want to list events to an organisation here we must related it via the CAF object too...
- engagement_events = EngagementEvent.objects.filter(Q(participants__in=peoples) | Q(related_caf__in=cafs)).order_by("-date")
+ engagement_events = EngagementEvent.objects.filter(
+ Q(participants__in=peoples) | Q(related_caf__in=cafs)
+ ).order_by("-date")
essential_services = EssentialService.objects.filter(organisation=org)
no_addr = org.addresses.count()