import pytest from django.contrib.auth import get_user_model from django.urls import reverse from apps.customers.models import CustomerProfile from .models import PhoneContactApiKey pytestmark = pytest.mark.django_db URL = "/api/phone-contacts" FIRST_KEY = "first-phone-contact-api-key-1234567890" SECOND_KEY = "second-phone-contact-api-key-1234567890" def make_contact(*, mobile, first_name, last_name="", active=True): user = get_user_model().objects.create_user( username=f"contact_{mobile}", mobile=mobile, is_active=active, account_type="CUSTOMER", ) return CustomerProfile.objects.create(user=user, first_name=first_name, last_name=last_name) def authorize(client, key=FIRST_KEY): return {"HTTP_AUTHORIZATION": f"Bearer {key}"} def test_contact_feed_authentication_search_and_contract(client): key = PhoneContactApiKey() key.set_key(FIRST_KEY) key.save() make_contact(mobile="09123456789", first_name="علی", last_name="رضایی") make_contact(mobile="09123456780", first_name="علی", last_name="غیرفعال", active=False) make_contact(mobile="09123456781", first_name="مریم") assert client.get(URL, {"search": "علی"}).status_code == 401 assert client.get(URL, {"search": "علی"}, **authorize(client, SECOND_KEY)).status_code == 401 response = client.get(URL, {"search": " علی رضایی ", "limit": "50"}, **authorize(client)) assert response.status_code == 200 assert response.json() == {"contacts": [{ "name": "علی رضایی", "mobile": "09123456789", "phones": [{"type": "همراه", "number": "09123456789"}], }]} assert response["Cache-Control"] == "no-store" assert client.get(URL, {"search": "ع"}, **authorize(client)).json() == {"contacts": []} assert client.get(URL, {"search": "هیچ"}, **authorize(client)).json() == {"contacts": []} assert client.post(URL, **authorize(client)).status_code == 405 @pytest.mark.parametrize("search", [ "09123456789", "+989123456789", "00989123456789", "۰۹۱۲۳۴۵۶۷۸۹", "۰۹۱۲-۳۴۵-۶۷۸۹", ]) def test_contact_feed_finds_same_mobile_in_supported_formats(client, search): key = PhoneContactApiKey() key.set_key(FIRST_KEY) key.save() make_contact(mobile="09123456789", first_name="علی", last_name="رضایی") make_contact(mobile="09123456780", first_name="مریم") response = client.get(URL, {"search": search}, **authorize(client)) assert response.status_code == 200 assert response.json() == {"contacts": [{ "name": "علی رضایی", "mobile": "09123456789", "phones": [{"type": "همراه", "number": "09123456789"}], }]} assert client.get(URL, {"search": "09120000000"}, **authorize(client)).json() == {"contacts": []} @pytest.mark.parametrize("stored,search,display", [ ("+989131234567", "09131234567", "09131234567"), ("+989131234567", "00989131234567", "09131234567"), ("+982112345678", "02112345678", "02112345678"), ("02112345678", "+982112345678", "02112345678"), ("+982112345678", "0098-21-1234-5678", "02112345678"), ]) def test_contact_feed_matches_any_iranian_prefix_without_mobile_area_code_assumption(client, stored, search, display): key = PhoneContactApiKey() key.set_key(FIRST_KEY) key.save() profile = make_contact(mobile="09123456789", first_name="علی", last_name="رضایی") get_user_model().objects.filter(pk=profile.user_id).update(mobile=stored) response = client.get(URL, {"search": search}, **authorize(client)) assert response.status_code == 200 assert response.json() == {"contacts": [{ "name": "علی رضایی", "mobile": display, "phones": [{"type": "همراه" if display.startswith("09") else "تلفن", "number": display}], }]} def test_key_rotation_and_disabling_take_effect_immediately(client): key = PhoneContactApiKey() key.set_key(FIRST_KEY) key.save() assert client.get(URL, {"search": "علی"}, **authorize(client)).status_code == 200 key.set_key(SECOND_KEY) key.save() assert client.get(URL, {"search": "علی"}, **authorize(client)).status_code == 401 assert client.get(URL, {"search": "علی"}, **authorize(client, SECOND_KEY)).status_code == 200 key.is_active = False key.save() assert client.get(URL, {"search": "علی"}, **authorize(client, SECOND_KEY)).status_code == 401 def test_admin_can_create_and_rotate_key_without_exposing_hash(client): admin = get_user_model().objects.create_superuser(username="api_admin", password="secure-admin-password") client.force_login(admin) add_url = reverse("admin:phone_contacts_api_phonecontactapikey_add") response = client.post(add_url, {"new_key": FIRST_KEY, "is_active": "on", "_save": "Save"}) assert response.status_code == 302 key = PhoneContactApiKey.objects.get() assert key.key_hash != FIRST_KEY assert key.accepts(FIRST_KEY) change_url = reverse("admin:phone_contacts_api_phonecontactapikey_change", args=[key.pk]) response = client.post(change_url, {"new_key": SECOND_KEY, "is_active": "on", "_save": "Save"}) assert response.status_code == 302 key.refresh_from_db() assert not key.accepts(FIRST_KEY) assert key.accepts(SECOND_KEY) assert SECOND_KEY not in client.get(change_url).content.decode()