Skip to content

Commit

Permalink
✨(dashboard) add admin actions for updating consent statuses
Browse files Browse the repository at this point in the history
Introduce `make_revoked` and `make_awaiting` actions to simplify updating consent status directly from the admin interface.
Updates include relevant timestamps and user feedback via success messages.
  • Loading branch information
ssorin committed Jan 8, 2025
1 parent 6e5afa4 commit d3a040d
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 1 deletion.
27 changes: 26 additions & 1 deletion src/dashboard/apps/consent/admin.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
"""Dashboard consent admin."""

from django.contrib import admin
from django.contrib import admin, messages
from django.utils import timezone
from django.utils.translation import gettext_lazy as _

from . import AWAITING, REVOKED
from .models import Consent


Expand All @@ -23,3 +26,25 @@ class ConsentAdmin(admin.ModelAdmin):
]
list_filter = ["status"]
date_hierarchy = "start"
actions = ["make_revoked", "make_awaiting"]

@admin.action(description=_("Mark selected consents as revoked"))
def make_revoked(self, request, queryset):
"""Mark selected consents as revoked."""
now = timezone.now()
queryset.update(status=REVOKED, revoked_at=now, updated_at=now)
self.message_user(
request,
_("Selected consents have been marked as revoked."),
messages.SUCCESS,
)

@admin.action(description=_("Mark selected consents as awaiting"))
def make_awaiting(self, request, queryset):
"""Mark selected consents as awaiting."""
queryset.update(status=AWAITING, updated_at=timezone.now(), revoked_at=None)
self.message_user(
request,
_("Selected consents have been marked as awaiting."),
messages.SUCCESS,
)
109 changes: 109 additions & 0 deletions src/dashboard/apps/consent/tests/test_admin.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,52 @@
"""Dashboard consent admin tests."""

import datetime

import pytest
from django.contrib.admin.sites import AdminSite
from django.contrib.messages.middleware import MessageMiddleware
from django.contrib.sessions.middleware import SessionMiddleware
from django.test import RequestFactory
from django.urls import reverse
from django.utils import timezone

from apps.auth.factories import AdminUserFactory
from apps.consent import AWAITING, REVOKED, VALIDATED
from apps.consent.admin import ConsentAdmin
from apps.consent.factories import ConsentFactory
from apps.consent.models import Consent
from apps.core.factories import DeliveryPointFactory


@pytest.fixture
def request_with_message_middleware():
"""Fixture to create a factice request with a message middleware."""
factory = RequestFactory()
request = factory.get("/")

# add session middleware
session_middleware = SessionMiddleware(lambda req: None)
session_middleware.process_request(request)
request.session.save()

# add messages middleware
message_middleware = MessageMiddleware(lambda req: None)
message_middleware.process_request(request)

return request


@pytest.fixture
def patch_timezone_now(monkeypatch):
"""Monkeypatch timezone.now to return a frozen date (`FAKE_TIME`)."""
fixed_date = datetime.datetime(
2025, 1, 1, 12, 0, 0, 0, tzinfo=datetime.timezone.utc
)

def mock_now():
return fixed_date

monkeypatch.setattr(timezone, "now", mock_now)


@pytest.mark.django_db
Expand All @@ -29,3 +70,71 @@ def test_admin_manager_name(rf):
# The manager name must be the default Django manager: `objects`.
manager_name = queryset.model._default_manager.name
assert manager_name == "objects"


@pytest.mark.django_db
def test_make_revoked_action(request_with_message_middleware, patch_timezone_now):
"""Tests the 'make_revoked' action for ConsentAdmin."""
# create a consent
assert Consent.objects.count() == 0
dl = DeliveryPointFactory()
consent = ConsentFactory(delivery_point=dl, status=AWAITING)
assert Consent.objects.count() == 1

# admin instance
admin_user = AdminUserFactory()
admin_site = AdminSite()
admin_instance = ConsentAdmin(Consent, admin_site)

# select consent
queryset = Consent.objects.filter(id=consent.id)
assert queryset.exists()

# mock request
request = request_with_message_middleware
request.user = admin_user

# triggers action
admin_instance.make_revoked(request=request, queryset=queryset)

consent.refresh_from_db()
assert consent.status == REVOKED
assert consent.revoked_at is not None
assert consent.updated_at is not None

expected_end_date = timezone.now()
assert consent.revoked_at == expected_end_date
assert consent.updated_at == expected_end_date


@pytest.mark.django_db
def test_make_awaiting_action(request_with_message_middleware, patch_timezone_now):
"""Tests the 'make_awaiting' action for ConsentAdmin."""
# create a consent
assert Consent.objects.count() == 0
dl = DeliveryPointFactory()
consent = ConsentFactory(delivery_point=dl, status=VALIDATED)
assert Consent.objects.count() == 1

# admin instance
admin_user = AdminUserFactory()
admin_site = AdminSite()
admin_instance = ConsentAdmin(Consent, admin_site)

# select consent
queryset = Consent.objects.filter(id=consent.id)
assert queryset.exists()

# mock request
request = request_with_message_middleware
request.user = admin_user

# triggers action
admin_instance.make_awaiting(request=request, queryset=queryset)

consent.refresh_from_db()
assert consent.status == AWAITING
assert consent.revoked_at is None
assert consent.updated_at is not None
expected_end_date = timezone.now()
assert consent.updated_at == expected_end_date

0 comments on commit d3a040d

Please sign in to comment.