You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

199 lines
8.5 KiB

import datetime
from django.urls import reverse
from rest_framework import status
from rest_framework.test import APITestCase
from apps.account.models import User
from apps.profiles.models import Institution, InstitutionMember
from apps.meetings.models import MeetingRequest, MeetingStatus
class Phase7MeetingsAPITests(APITestCase):
def setUp(self):
# Users
self.superadmin = User.objects.create_superuser(
email="[email protected]",
password="Password123!",
fullname="Super Admin"
)
self.admin_a = User.objects.create_user(
email="[email protected]",
password="Password123!",
fullname="Director Alpha",
user_type="institution_admin"
)
self.admin_b = User.objects.create_user(
email="[email protected]",
password="Password123!",
fullname="Director Beta",
user_type="institution_admin"
)
self.unrelated_user = User.objects.create_user(
email="[email protected]",
password="Password123!",
fullname="External User",
user_type="client"
)
# Institutions
self.inst_a = Institution.objects.create(
name="Islamic Center of Hamburg",
slug="islamic-center-hamburg",
type="cultural_center",
country="Germany",
city="Hamburg",
address="Schöne Aussicht 36",
latitude=53.5600,
longitude=10.0100,
verification_status="approved",
is_active=True
)
self.inst_b = Institution.objects.create(
name="Al-Khoei Foundation London",
slug="al-khoei-london",
type="institute",
country="United Kingdom",
city="London",
address="Chevening Road",
latitude=51.5400,
longitude=-0.2100,
verification_status="approved",
is_active=True
)
self.inst_c = Institution.objects.create(
name="Imam Reza Cultural Center Paris",
slug="imam-reza-paris",
type="cultural_center",
country="France",
city="Paris",
address="Rue de Rivoli",
latitude=48.8566,
longitude=2.3522,
verification_status="approved",
is_active=True
)
# Memberships
InstitutionMember.objects.create(institution=self.inst_a, user=self.admin_a, role="admin")
InstitutionMember.objects.create(institution=self.inst_b, user=self.admin_b, role="admin")
# Initial meeting
self.meeting = MeetingRequest.objects.create(
title="Joint Inter-Faith Youth Dialogue 2026",
requester_institution=self.inst_a,
recipient_institution=self.inst_b,
created_by=self.admin_a,
status=MeetingStatus.PENDING,
meeting_date=datetime.date.today() + datetime.timedelta(days=3),
meeting_time=datetime.time(14, 0),
duration_minutes=60,
agenda="Discussing curriculum collaboration and joint webinar dates."
)
def test_list_meetings_scoped_to_user_institutions(self):
url = reverse('meeting-list-create')
# Admin A should see the meeting
self.client.force_authenticate(user=self.admin_a)
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
results = response.data.get('results', response.data)
self.assertEqual(len(results), 1)
self.assertEqual(results[0]['title'], self.meeting.title)
# Admin B (recipient) should also see the meeting
self.client.force_authenticate(user=self.admin_b)
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
results = response.data.get('results', response.data)
self.assertEqual(len(results), 1)
# Unrelated user should see no meetings
self.client.force_authenticate(user=self.unrelated_user)
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
results = response.data.get('results', response.data)
self.assertEqual(len(results), 0)
def test_create_meeting_request_successful(self):
self.client.force_authenticate(user=self.admin_a)
url = reverse('meeting-list-create')
payload = {
"title": "Bilateral Cultural Exchange Planning",
"requester_institution_id": self.inst_a.id,
"recipient_institution_id": self.inst_c.id,
"meeting_date": str(datetime.date.today() + datetime.timedelta(days=5)),
"meeting_time": "15:30:00",
"duration_minutes": 45,
"agenda": "Reviewing translated publications distribution."
}
response = self.client.post(url, payload, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(response.data['title'], "Bilateral Cultural Exchange Planning")
self.assertEqual(response.data['status'], MeetingStatus.PENDING)
# Verify auto-generated meeting url
self.assertTrue("meet.jit.si" in response.data['meeting_url'])
def test_create_meeting_same_institution_rejected(self):
self.client.force_authenticate(user=self.admin_a)
url = reverse('meeting-list-create')
payload = {
"title": "Invalid Self Meeting",
"requester_institution_id": self.inst_a.id,
"recipient_institution_id": self.inst_a.id,
"meeting_date": str(datetime.date.today() + datetime.timedelta(days=2)),
"meeting_time": "11:00:00"
}
response = self.client.post(url, payload, format='json')
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
error_fields = [e.get('field') for e in response.data.get('errors', [])] if 'errors' in response.data else response.data
self.assertTrue('recipient_institution_id' in error_fields)
def test_create_meeting_unauthorized_requester(self):
self.client.force_authenticate(user=self.unrelated_user)
url = reverse('meeting-list-create')
payload = {
"title": "Unauthorized Meeting",
"requester_institution_id": self.inst_a.id,
"recipient_institution_id": self.inst_b.id,
"meeting_date": str(datetime.date.today() + datetime.timedelta(days=2)),
"meeting_time": "11:00:00"
}
response = self.client.post(url, payload, format='json')
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
error_fields = [e.get('field') for e in response.data.get('errors', [])] if 'errors' in response.data else response.data
self.assertTrue('requester_institution_id' in error_fields)
def test_retrieve_meeting_detail(self):
url = reverse('meeting-detail', kwargs={'pk': self.meeting.id})
# Unrelated user forbidden
self.client.force_authenticate(user=self.unrelated_user)
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
# Recipient admin permitted
self.client.force_authenticate(user=self.admin_b)
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['id'], self.meeting.id)
self.assertEqual(response.data['requester_institution']['id'], self.inst_a.id)
def test_update_meeting_status_and_schedule(self):
url = reverse('meeting-detail', kwargs={'pk': self.meeting.id})
# Recipient admin accepts meeting
self.client.force_authenticate(user=self.admin_b)
response = self.client.patch(url, {
"status": MeetingStatus.SCHEDULED,
"admin_notes": "Accepted. Looking forward to meeting."
}, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['status'], MeetingStatus.SCHEDULED)
self.assertEqual(response.data['admin_notes'], "Accepted. Looking forward to meeting.")
def test_cancel_meeting(self):
url = reverse('meeting-detail', kwargs={'pk': self.meeting.id})
self.client.force_authenticate(user=self.admin_a)
response = self.client.delete(url)
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
self.assertFalse(MeetingRequest.objects.filter(id=self.meeting.id).exists())