import json from unittest import mock from django.test import TestCase from django.core.files.uploadedfile import SimpleUploadedFile from apps.users.models import User from core.authentication import create_jwt_token class UsersAPIIntegrationTests(TestCase): def setUp(self): self.user = User.objects.create_user( username="mobile_user", mobile="09192000001", email="person@example.com", password="Sup3rSecure!123", is_mobile_verified=True, ) def _auth(self): return {"HTTP_AUTHORIZATION": f"Bearer {create_jwt_token(self.user)}"} def test_password_login_accepts_mobile_identity(self): response = self.client.post("/api/auth/login", json.dumps({ "identifier": self.user.mobile, "password": "Sup3rSecure!123", }), content_type="application/json") self.assertEqual(response.status_code, 200) self.assertIn("access_token", response.json()) def test_profile_update_treats_supplied_email_as_identity(self): response = self.client.put("/api/auth/profile", json.dumps({"email": "new@example.com"}), content_type="application/json", **self._auth()) self.assertEqual(response.status_code, 200) self.user.refresh_from_db() self.assertEqual(self.user.email, "new@example.com") self.assertTrue(self.user.is_email_verified) def test_profile_update_clears_email_identity_flag(self): response = self.client.put("/api/auth/profile", json.dumps({"email": ""}), content_type="application/json", **self._auth()) self.assertEqual(response.status_code, 200) self.user.refresh_from_db() self.assertIsNone(self.user.email) self.assertFalse(self.user.is_email_verified) def test_profile_requires_authentication_and_returns_account_identity(self): self.assertEqual(self.client.get("/api/auth/profile").status_code, 401) response = self.client.get("/api/auth/profile", **self._auth()) self.assertEqual(response.status_code, 200) self.assertEqual(response.json()["mobile"], self.user.mobile) def test_profile_rejects_duplicate_email(self): User.objects.create_user(username="second", mobile="09192000002", email="taken@example.com", password="password") response = self.client.put("/api/auth/profile", json.dumps({"email": "taken@example.com"}), content_type="application/json", **self._auth()) self.assertEqual(response.status_code, 400) self.user.refresh_from_db() self.assertEqual(self.user.email, "person@example.com") def test_profile_picture_rejects_non_image_upload(self): image = SimpleUploadedFile("notes.txt", b"not an image", content_type="text/plain") response = self.client.post("/api/auth/profile/picture", {"file": image}, **self._auth()) self.assertEqual(response.status_code, 400) def test_check_username_reports_existing_user(self): response = self.client.get("/api/auth/check-username", {"username": self.user.username}) self.assertEqual(response.status_code, 200) self.assertTrue(response.json()["exists"]) def test_legacy_email_auth_routes_are_gone(self): self.assertEqual(self.client.get("/api/auth/verify-email/token").status_code, 404) self.assertEqual(self.client.post("/api/auth/resend-verification").status_code, 404) self.assertEqual(self.client.post("/api/auth/request-password-reset").status_code, 404) @mock.patch("apps.users.api.views.reset_password_with_otp") def test_mobile_otp_password_reset_route_remains_available(self, reset): response = self.client.post("/api/auth/reset-password", json.dumps({ "mobile": self.user.mobile, "code": "123456", "new_password": "AnotherSecurePass!123", }), content_type="application/json") self.assertEqual(response.status_code, 200) reset.assert_called_once()