You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kompass/jdav_web/mailer/tests/admin.py

338 lines
14 KiB
Python

import json
import unittest
from http import HTTPStatus
from django.test import TestCase, override_settings
from django.contrib.admin.sites import AdminSite
from django.test import RequestFactory, Client
from django.contrib.auth.models import User, Permission
from django.utils import timezone
from django.contrib.sessions.middleware import SessionMiddleware
from django.contrib.messages.middleware import MessageMiddleware
from django.contrib.messages.storage.fallback import FallbackStorage
from django.contrib.messages import get_messages
from django.utils.translation import gettext_lazy as _
from django.urls import reverse, reverse_lazy
from django.http import HttpResponseRedirect, HttpResponse
from unittest.mock import Mock, patch
from django.test.utils import override_settings
from django.urls import path, include
from django.contrib import admin as django_admin
from django.conf import settings
from members.tests.utils import create_custom_user
from members.models import Member, MALE, DIVERSE, Group
from ..models import Message, Attachment, EmailAddress
from ..admin import MessageAdmin, submit_message
from ..mailutils import SENT, NOT_SENT, PARTLY_SENT
class AdminTestCase(TestCase):
def setUp(self, model, admin):
self.factory = RequestFactory()
self.model = model
if model is not None and admin is not None:
self.admin = admin(model, AdminSite())
superuser = User.objects.create_superuser(
username='superuser', password='secret'
)
standard = create_custom_user('standard', ['Standard'], 'Paul', 'Wulter')
trainer = create_custom_user('trainer', ['Standard', 'Trainings'], 'Lise', 'Lotte')
def _login(self, name):
c = Client()
res = c.login(username=name, password='secret')
# make sure we logged in
assert res
return c
def _add_middleware(self, request):
"""Add required middleware to request."""
# Session middleware
middleware = SessionMiddleware(lambda x: None)
middleware.process_request(request)
request.session.save()
# Messages middleware
messages_middleware = MessageMiddleware(lambda x: None)
messages_middleware.process_request(request)
request._messages = FallbackStorage(request)
class MessageAdminTestCase(AdminTestCase):
def setUp(self):
super().setUp(Message, MessageAdmin)
# Create test data
self.group = Group.objects.create(name='Test Group')
self.email_address = EmailAddress.objects.create(name='testmail')
# Create test member with internal email
self.internal_member = Member.objects.create(
prename='Internal',
lastname='User',
birth_date=timezone.now().date(),
email=f'internal@{settings.ALLOWED_EMAIL_DOMAINS_FOR_INVITE_AS_USER[0]}',
gender=DIVERSE
)
# Create test member with external email
self.external_member = Member.objects.create(
prename='External',
lastname='User',
birth_date=timezone.now().date(),
email='external@example.com',
gender=DIVERSE
)
# Create users for testing
self.user_with_internal_member = User.objects.create_user(username='testuser', password='secret')
self.user_with_internal_member.member = self.internal_member
self.user_with_internal_member.save()
self.user_with_external_member = User.objects.create_user(username='external_user', password='secret')
self.user_with_external_member.member = self.external_member
self.user_with_external_member.save()
self.user_without_member = User.objects.create_user(username='no_member_user', password='secret')
# Create test message
self.message = Message.objects.create(
subject='Test Message',
content='Test content'
)
self.message.to_groups.add(self.group)
self.message.to_members.add(self.internal_member)
def test_save_model_sets_created_by(self):
"""Test that save_model sets created_by when creating new message."""
request = self.factory.post('/admin/mailer/message/add/')
request.user = self.user_with_internal_member
# Create new message
new_message = Message(subject='New Message', content='New content')
# Test save_model for new object (change=False)
self.admin.save_model(request, new_message, None, change=False)
self.assertEqual(new_message.created_by, self.internal_member)
def test_save_model_does_not_change_created_by_on_update(self):
"""Test that save_model doesn't change created_by when updating."""
request = self.factory.post('/admin/mailer/message/1/change/')
request.user = self.user_with_internal_member
# Message already has created_by set
self.message.created_by = self.external_member
# Test save_model for existing object (change=True)
self.admin.save_model(request, self.message, None, change=True)
self.assertEqual(self.message.created_by, self.external_member)
@patch('mailer.models.Message.submit')
def test_submit_message_success(self, mock_submit):
"""Test submit_message with successful send."""
mock_submit.return_value = SENT
request = self.factory.post('/admin/mailer/message/')
request.user = self.user_with_internal_member
self._add_middleware(request)
# Test submit_message
submit_message(self.message, request)
# Verify submit was called with correct sender
mock_submit.assert_called_once_with(self.internal_member)
# Check success message
messages_list = list(get_messages(request))
self.assertEqual(len(messages_list), 1)
self.assertIn(str(_('Successfully sent message')), str(messages_list[0]))
@patch('mailer.models.Message.submit')
def test_submit_message_not_sent(self, mock_submit):
"""Test submit_message when sending fails."""
mock_submit.return_value = NOT_SENT
request = self.factory.post('/admin/mailer/message/')
request.user = self.user_with_internal_member
self._add_middleware(request)
# Test submit_message
submit_message(self.message, request)
# Check error message
messages_list = list(get_messages(request))
self.assertEqual(len(messages_list), 1)
self.assertIn(str(_('Failed to send message')), str(messages_list[0]))
@patch('mailer.models.Message.submit')
def test_submit_message_partly_sent(self, mock_submit):
"""Test submit_message when partially sent."""
mock_submit.return_value = PARTLY_SENT
request = self.factory.post('/admin/mailer/message/')
request.user = self.user_with_internal_member
self._add_middleware(request)
# Test submit_message
submit_message(self.message, request)
# Check warning message
messages_list = list(get_messages(request))
self.assertEqual(len(messages_list), 1)
self.assertIn(str(_('Failed to send some messages')), str(messages_list[0]))
def test_submit_message_user_has_no_member(self):
"""Test submit_message when user has no associated member."""
request = self.factory.post('/admin/mailer/message/')
request.user = self.user_without_member
self._add_middleware(request)
# Test submit_message
submit_message(self.message, request)
# Check error message
messages_list = list(get_messages(request))
self.assertEqual(len(messages_list), 1)
self.assertIn(str(_('Your account is not connected to a member. Please contact your system administrator.')), str(messages_list[0]))
def test_submit_message_user_has_external_email(self):
"""Test submit_message when user has external email."""
request = self.factory.post('/admin/mailer/message/')
request.user = self.user_with_external_member
self._add_middleware(request)
# Test submit_message
submit_message(self.message, request)
# Check error message
messages_list = list(get_messages(request))
self.assertEqual(len(messages_list), 1)
self.assertIn(str(_('Your email address is not an internal email address. Please use an email address with one of the following domains: %(domains)s.') % {'domains': ", ".join(settings.ALLOWED_EMAIL_DOMAINS_FOR_INVITE_AS_USER)}), str(messages_list[0]))
@patch('mailer.admin.submit_message')
def test_send_message_action_confirmed(self, mock_submit_message):
"""Test send_message action when confirmed."""
request = self.factory.post('/admin/mailer/message/', {'confirmed': 'true'})
request.user = self.user_with_internal_member
self._add_middleware(request)
queryset = Message.objects.filter(pk=self.message.pk)
# Test send_message action
result = self.admin.send_message(request, queryset)
# Verify submit_message was called for each message
mock_submit_message.assert_called_once_with(self.message, request)
# Should return None when confirmed (no template response)
self.assertIsNone(result)
def test_send_message_action_not_confirmed(self):
"""Test send_message action when not confirmed (shows confirmation page)."""
request = self.factory.post('/admin/mailer/message/')
request.user = self.user_with_internal_member
self._add_middleware(request)
queryset = Message.objects.filter(pk=self.message.pk)
# Test send_message action
result = self.admin.send_message(request, queryset)
# Should return HttpResponse with confirmation template
self.assertIsNotNone(result)
self.assertEqual(result.status_code, HTTPStatus.OK)
@patch('mailer.admin.submit_message')
def test_response_change_with_send(self, mock_submit_message):
"""Test response_change when _send is in POST."""
request = self.factory.post('/admin/mailer/message/1/change/', {'_send': 'Send'})
request.user = self.user_with_internal_member
self._add_middleware(request)
# Test response_change
with patch.object(self.admin.__class__.__bases__[2], 'response_change') as mock_super:
mock_super.return_value = HttpResponseRedirect('/admin/')
result = self.admin.response_change(request, self.message)
# Verify submit_message was called
mock_submit_message.assert_called_once_with(self.message, request)
# Verify super method was called
mock_super.assert_called_once()
@patch('mailer.admin.submit_message')
def test_response_change_without_send(self, mock_submit_message):
"""Test response_change when _send is not in POST."""
request = self.factory.post('/admin/mailer/message/1/change/', {'_save': 'Save'})
request.user = self.user_with_internal_member
self._add_middleware(request)
# Test response_change
with patch.object(self.admin.__class__.__bases__[2], 'response_change') as mock_super:
mock_super.return_value = HttpResponseRedirect('/admin/')
result = self.admin.response_change(request, self.message)
# Verify submit_message was NOT called
mock_submit_message.assert_not_called()
# Verify super method was called
mock_super.assert_called_once()
@patch('mailer.admin.submit_message')
def test_response_add_with_send(self, mock_submit_message):
"""Test response_add when _send is in POST."""
request = self.factory.post('/admin/mailer/message/add/', {'_send': 'Send'})
request.user = self.user_with_internal_member
self._add_middleware(request)
# Test response_add
with patch.object(self.admin.__class__.__bases__[2], 'response_add') as mock_super:
mock_super.return_value = HttpResponseRedirect('/admin/')
result = self.admin.response_add(request, self.message)
# Verify submit_message was called
mock_submit_message.assert_called_once_with(self.message, request)
# Verify super method was called
mock_super.assert_called_once()
def test_get_form_with_members_param(self):
"""Test get_form when members parameter is provided."""
# Create request with members parameter
members_ids = [self.internal_member.pk, self.external_member.pk]
request = self.factory.get(f'/admin/mailer/message/add/?members={json.dumps(members_ids)}')
request.user = self.user_with_internal_member
# Test get_form
form_class = self.admin.get_form(request)
form = form_class()
# Verify initial members are set
self.assertEqual(list(form.fields['to_members'].initial), [self.internal_member, self.external_member])
def test_get_form_with_invalid_members_param(self):
"""Test get_form when members parameter is not a list."""
# Create request with invalid members parameter
request = self.factory.get('/admin/mailer/message/add/?members="not_a_list"')
request.user = self.user_with_internal_member
# Test get_form
form_class = self.admin.get_form(request)
# Should return form without modification
self.assertIsNotNone(form_class)
def test_get_form_without_members_param(self):
"""Test get_form when no members parameter is provided."""
# Create request without members parameter
request = self.factory.get('/admin/mailer/message/add/')
request.user = self.user_with_internal_member
# Test get_form
form_class = self.admin.get_form(request)
# Should return form without modification
self.assertIsNotNone(form_class)