test_api.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. from django.core import mail
  2. from django.test import override_settings
  3. from django.urls import reverse
  4. from model_bakery import baker
  5. from rest_framework.test import APITestCase
  6. from apps.organizations_ext.models import OrganizationUserRole
  7. from apps.projects.models import UserProjectAlert
  8. from glitchtip.test_utils.test_case import GlitchTipTestCase
  9. from ..models import User
  10. class UserRegistrationTestCase(APITestCase):
  11. def test_create_user(self):
  12. url = reverse("rest_register")
  13. data = {
  14. "email": "test@example.com",
  15. "password1": "hunter222",
  16. "password2": "hunter222",
  17. }
  18. res = self.client.post(url, data)
  19. self.assertEqual(res.status_code, 204)
  20. def test_create_user_with_tags(self):
  21. url = reverse("rest_register")
  22. data = {
  23. "email": "test@example.com",
  24. "password1": "hunter222",
  25. "password2": "hunter222",
  26. "tags": "?utm_campaign=test&utm_source=test&utm_medium=test&utm_medium=test",
  27. }
  28. res = self.client.post(url, data)
  29. self.assertEqual(res.status_code, 204)
  30. self.assertTrue(
  31. User.objects.filter(analytics__register__utm_campaign="test").exists()
  32. )
  33. def test_closed_registration(self):
  34. """Only first user may register"""
  35. url = reverse("rest_register")
  36. user1_data = {
  37. "email": "test1@example.com",
  38. "password1": "hunter222",
  39. "password2": "hunter222",
  40. }
  41. user2_data = {
  42. "email": "test2@example.com",
  43. "password1": "hunter222",
  44. "password2": "hunter222",
  45. }
  46. with override_settings(ENABLE_USER_REGISTRATION=False):
  47. res = self.client.post(url, user1_data)
  48. self.assertEqual(res.status_code, 204)
  49. res = self.client.post(url, user2_data)
  50. self.assertEqual(res.status_code, 403)
  51. class UsersTestCase(GlitchTipTestCase):
  52. def setUp(self):
  53. self.create_logged_in_user()
  54. def test_list(self):
  55. url = reverse("api:list_users")
  56. res = self.client.get(url)
  57. self.assertContains(res, self.user.email)
  58. def test_retrieve(self):
  59. url = reverse("api:get_user", args=["me"])
  60. res = self.client.get(url)
  61. self.assertContains(res, self.user.email)
  62. url = reverse("api:get_user", args=[self.user.id])
  63. res = self.client.get(url)
  64. self.assertContains(res, self.user.email)
  65. def test_destroy(self):
  66. other_user = baker.make("users.user")
  67. url = reverse("api:delete_user", args=[other_user.pk])
  68. res = self.client.delete(url)
  69. self.assertEqual(
  70. res.status_code, 404, "User should not be able to delete other users"
  71. )
  72. url = reverse("api:delete_user", args=[self.user.pk])
  73. res = self.client.delete(url)
  74. self.assertEqual(
  75. res.status_code, 400, "Not allowed to destroy owned organization"
  76. )
  77. # Delete organization to allow user deletion
  78. self.organization.delete()
  79. res = self.client.delete(url)
  80. self.assertEqual(res.status_code, 204)
  81. self.assertFalse(User.objects.filter(pk=self.user.pk).exists())
  82. def test_update(self):
  83. url = reverse("api:update_user", args=["me"])
  84. data = {"name": "new", "options": {"foo": "bar"}}
  85. res = self.client.put(url, data, format="json")
  86. self.assertContains(res, data["name"])
  87. self.assertContains(res, data["options"]["foo"])
  88. self.assertTrue(User.objects.filter(name=data["name"]).exists())
  89. def test_organization_members_list(self):
  90. other_user = baker.make("users.user")
  91. other_organization = baker.make("organizations_ext.Organization")
  92. other_organization.add_user(other_user, OrganizationUserRole.ADMIN)
  93. user2 = baker.make("users.User")
  94. self.organization.add_user(user2, OrganizationUserRole.MEMBER)
  95. url = reverse("api:list_organization_members", args=[self.organization.slug])
  96. res = self.client.get(url)
  97. self.assertContains(res, user2.email)
  98. self.assertNotContains(res, other_user.email)
  99. # Can't view members of groups you don't belong to
  100. url = reverse("api:list_organization_members", args=[other_organization.slug])
  101. res = self.client.get(url)
  102. self.assertNotContains(res, other_user.email)
  103. def test_emails_list(self):
  104. email_address = baker.make("account.EmailAddress", user=self.user)
  105. another_user = baker.make("users.user")
  106. another_email_address = baker.make("account.EmailAddress", user=another_user)
  107. url = reverse("api:list_emails", args=["me"])
  108. res = self.client.get(url)
  109. self.assertContains(res, email_address.email)
  110. self.assertNotContains(res, another_email_address.email)
  111. def test_emails_create(self):
  112. url = reverse("api:list_emails", args=["me"])
  113. res = self.client.post(url, {"email": "invalid"}, format="json")
  114. self.assertEqual(res.status_code, 422)
  115. new_email = "new@exmaple.com"
  116. data = {"email": new_email}
  117. res = self.client.post(url, data, format="json")
  118. self.assertContains(res, new_email, status_code=201)
  119. self.assertTrue(
  120. self.user.emailaddress_set.filter(email=new_email, verified=False).exists()
  121. )
  122. self.assertEqual(len(mail.outbox), 1)
  123. # Ensure token is valid and can verify email
  124. body = mail.outbox[0].body
  125. key = body[body.find("confirm-email") :].split("/")[1]
  126. url = reverse("rest_verify_email")
  127. data = {"key": key}
  128. res = self.client.post(url, data)
  129. self.assertTrue(
  130. self.user.emailaddress_set.filter(email=new_email, verified=True).exists()
  131. )
  132. def test_emails_create_dupe_email(self):
  133. url = reverse("api:create_email", args=["me"])
  134. email_address = baker.make(
  135. "account.EmailAddress",
  136. user=self.user,
  137. email="something@example.com",
  138. )
  139. data = {"email": email_address.email}
  140. res = self.client.post(url, data, format="json")
  141. self.assertContains(res, "already exists", status_code=400)
  142. def test_emails_create_dupe_email_other_user(self):
  143. url = reverse("api:create_email", args=["me"])
  144. email_address = baker.make(
  145. "account.EmailAddress", email="a@example.com", verified=True
  146. )
  147. data = {"email": email_address.email}
  148. res = self.client.post(url, data, format="json")
  149. self.assertContains(res, "already exists", status_code=400)
  150. def test_emails_set_primary(self):
  151. url = reverse("api:set_email_as_primary", args=["me"])
  152. email_address = baker.make(
  153. "account.EmailAddress", verified=True, user=self.user
  154. )
  155. data = {"email": email_address.email}
  156. res = self.client.put(url, data, format="json")
  157. self.assertContains(res, email_address.email, status_code=200)
  158. self.assertTrue(
  159. self.user.emailaddress_set.filter(
  160. email=email_address.email, primary=True
  161. ).exists()
  162. )
  163. extra_email = baker.make("account.EmailAddress", verified=True, user=self.user)
  164. data = {"email": extra_email.email}
  165. res = self.client.put(url, data)
  166. self.assertEqual(self.user.emailaddress_set.filter(primary=True).count(), 1)
  167. def test_emails_set_primary_unverified_primary(self):
  168. """
  169. Because confirmation is optional, it's possible to have an existing email that is primary and unverified
  170. """
  171. url = reverse("api:set_email_as_primary", args=["me"])
  172. email = "test@example.com"
  173. baker.make(
  174. "account.EmailAddress",
  175. primary=True,
  176. user=self.user,
  177. )
  178. baker.make(
  179. "account.EmailAddress",
  180. email=email,
  181. verified=True,
  182. user=self.user,
  183. )
  184. data = {"email": email}
  185. res = self.client.put(url, data, format="json")
  186. self.assertEqual(res.status_code, 200)
  187. def test_emails_destroy(self):
  188. url = reverse("api:delete_email", args=["me"])
  189. email_address = baker.make(
  190. "account.EmailAddress", verified=True, primary=False, user=self.user
  191. )
  192. data = {"email": email_address.email}
  193. res = self.client.delete(url, data, format="json")
  194. self.assertEqual(res.status_code, 204)
  195. self.assertFalse(
  196. self.user.emailaddress_set.filter(email=email_address.email).exists()
  197. )
  198. def test_emails_confirm(self):
  199. email_address = baker.make("account.EmailAddress", user=self.user)
  200. url = reverse("api:send_confirm_email", args=["me"])
  201. data = {"email": email_address.email}
  202. res = self.client.post(url, data, format="json")
  203. self.assertEqual(res.status_code, 204)
  204. self.assertEqual(len(mail.outbox), 1)
  205. def test_notifications_retrieve(self):
  206. url = reverse("api:get_notifications", args=["me"])
  207. res = self.client.get(url)
  208. self.assertContains(res, "subscribeByDefault")
  209. def test_notifications_update(self):
  210. url = reverse("api:update_notifications", args=["me"])
  211. data = {"subscribeByDefault": False}
  212. res = self.client.put(url, data, format="json")
  213. self.assertFalse(res.json().get("subscribeByDefault"))
  214. self.user.refresh_from_db()
  215. self.assertFalse(self.user.subscribe_by_default)
  216. def test_alerts_retrieve(self):
  217. url = reverse("user-detail", args=["me"]) + "notifications/alerts/"
  218. alert = baker.make(
  219. "projects.UserProjectAlert", user=self.user, project=self.project
  220. )
  221. res = self.client.get(url)
  222. self.assertContains(res, self.project.id)
  223. self.assertEqual(res.data[self.project.id], alert.status)
  224. def test_alerts_update(self):
  225. url = reverse("user-detail", args=["me"]) + "notifications/alerts/"
  226. # Set to alert to On
  227. data = '{"' + str(self.project.id) + '":1}'
  228. res = self.client.put(url, data, content_type="application/json")
  229. self.assertEqual(res.status_code, 204)
  230. self.assertEqual(UserProjectAlert.objects.all().count(), 1)
  231. self.assertEqual(UserProjectAlert.objects.first().status, 1)
  232. # Set to alert to Off
  233. data = '{"' + str(self.project.id) + '":0}'
  234. res = self.client.put(url, data, content_type="application/json")
  235. self.assertEqual(res.status_code, 204)
  236. self.assertEqual(UserProjectAlert.objects.first().status, 0)
  237. # Set to alert to "default"
  238. data = '{"' + str(self.project.id) + '":-1}'
  239. res = self.client.put(url, data, content_type="application/json")
  240. self.assertEqual(res.status_code, 204)
  241. # Default deletes the row
  242. self.assertEqual(UserProjectAlert.objects.all().count(), 0)
  243. def test_reset_password(self):
  244. """
  245. Social accounts weren't getting reset password emails. This
  246. approximates the issue by testing an account that has an
  247. unusable password.
  248. """
  249. url = reverse("rest_password_reset")
  250. # Normal behavior
  251. self.client.post(url, {"email": self.user.email})
  252. self.assertEqual(len(mail.outbox), 1)
  253. user_without_password = baker.make("users.User")
  254. user_without_password.set_unusable_password()
  255. user_without_password.save()
  256. self.assertFalse(user_without_password.has_usable_password())
  257. self.client.post(url, {"email": user_without_password.email})
  258. self.assertEqual(len(mail.outbox), 2)