test_organization_users.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. import json
  2. from django.core import mail
  3. from django.db import transaction
  4. from django.test import TestCase, override_settings
  5. from django.urls import reverse
  6. from model_bakery import baker
  7. from ..models import OrganizationUser, OrganizationUserRole
  8. class OrganizationUsersTestCase(TestCase):
  9. @classmethod
  10. def setUpTestData(cls):
  11. cls.user = baker.make("users.user")
  12. cls.organization = baker.make(
  13. "organizations_ext.Organization",
  14. name="<a>No</a><script>HtmlInOrgName</script>",
  15. )
  16. cls.org_user = cls.organization.add_user(
  17. cls.user, role=OrganizationUserRole.MANAGER
  18. )
  19. baker.make("organizations_ext.OrganizationUser", user=cls.user, role=5)
  20. cls.members_url = reverse(
  21. "api:list_organization_members", args=[cls.organization.slug]
  22. )
  23. def setUp(self):
  24. self.client.force_login(self.user)
  25. def get_org_member_detail_url(self, organization_slug, pk):
  26. return reverse("api:get_organization_member", args=[organization_slug, pk])
  27. def test_organization_members_list(self):
  28. res = self.client.get(self.members_url)
  29. self.assertContains(res, self.user.email)
  30. data = res.json()
  31. self.assertNotIn("teams", data[0].keys())
  32. def test_organization_members_email_field(self):
  33. """
  34. Org Member email should refer to the invited email before acceptance
  35. After acceptance, it should refer to the user's primary email address
  36. """
  37. url = self.get_org_member_detail_url(self.organization.slug, self.org_user.pk)
  38. res = self.client.get(url)
  39. self.assertEqual(res.json()["email"], self.user.email)
  40. def test_organization_team_members_list(self):
  41. team = baker.make("teams.Team", organization=self.organization)
  42. url = reverse(
  43. "api:list_team_organization_members",
  44. args=[self.organization.slug, team.slug],
  45. )
  46. res = self.client.get(url)
  47. self.assertNotContains(res, self.user.email)
  48. team.members.add(self.org_user)
  49. res = self.client.get(url)
  50. self.assertContains(res, self.user.email)
  51. def test_organization_members_detail(self):
  52. other_user = baker.make("users.user")
  53. other_organization = baker.make("organizations_ext.Organization")
  54. other_org_user = other_organization.add_user(other_user)
  55. team = baker.make("teams.Team", organization=self.organization)
  56. team.members.add(self.org_user)
  57. url = self.get_org_member_detail_url(self.organization.slug, self.org_user.pk)
  58. res = self.client.get(url)
  59. self.assertContains(res, self.user.email)
  60. self.assertContains(res, team.slug)
  61. self.assertNotContains(res, other_user.email)
  62. url = self.get_org_member_detail_url(self.organization.slug, other_org_user.pk)
  63. res = self.client.get(url)
  64. self.assertEqual(res.status_code, 404)
  65. def test_organization_users_add_team_member(self):
  66. team = baker.make("teams.Team", organization=self.organization)
  67. url = (
  68. self.get_org_member_detail_url(self.organization.slug, self.org_user.pk)
  69. + f"teams/{team.slug}/"
  70. )
  71. self.assertEqual(team.members.count(), 0)
  72. res = self.client.post(url)
  73. self.assertEqual(res.status_code, 201)
  74. self.assertEqual(team.members.count(), 1)
  75. res = self.client.delete(url)
  76. self.assertEqual(res.status_code, 200)
  77. self.assertEqual(team.members.count(), 0)
  78. def test_organization_users_add_self_team_member(self):
  79. team = baker.make("teams.Team", organization=self.organization)
  80. url = reverse(
  81. "api:add_member_to_team", args=[self.organization.slug, "me", team.slug]
  82. )
  83. self.assertEqual(team.members.count(), 0)
  84. res = self.client.post(url)
  85. self.assertEqual(res.status_code, 201)
  86. self.assertEqual(team.members.count(), 1)
  87. res = self.client.delete(url)
  88. self.assertEqual(res.status_code, 200)
  89. self.assertEqual(team.members.count(), 0)
  90. def test_organization_users_create_and_accept_invite(self):
  91. data = {
  92. "email": "new@example.com",
  93. "orgRole": OrganizationUserRole.MANAGER.label.lower(),
  94. "teamRoles": [],
  95. }
  96. res = self.client.post(self.members_url, data, content_type="application/json")
  97. self.assertTrue(res.json()["pending"])
  98. body = mail.outbox[0].body
  99. html_content = mail.outbox[0].alternatives[0][0]
  100. self.assertFalse("<a>No</a><script>HtmlInOrgName</script>" in body)
  101. self.assertTrue("NoHtmlInOrgName" in body)
  102. self.assertFalse("<a>No</a><script>HtmlInOrgName</script>" in html_content)
  103. self.assertTrue("NoHtmlInOrgName" in html_content)
  104. body_split = body[body.find("http://localhost:8000/accept/") :].split("/")
  105. org_user_id = body_split[4]
  106. token = body_split[5]
  107. url = reverse("api:get_accept_invite", args=[org_user_id, token])
  108. # Check that we can determine organization name from GET request to accept invite endpoint
  109. self.client.logout()
  110. res = self.client.get(url)
  111. self.assertContains(res, self.organization.name)
  112. user = baker.make("users.user")
  113. self.client.force_login(user)
  114. data = {"acceptInvite": True}
  115. res = self.client.post(url, data, content_type="application/json")
  116. self.assertContains(res, self.organization.name)
  117. self.assertFalse(res.json()["orgUser"]["pending"])
  118. self.assertTrue(
  119. OrganizationUser.objects.filter(
  120. user=user, organization=self.organization
  121. ).exists()
  122. )
  123. def test_closed_user_registration(self):
  124. data = {
  125. "email": "new@example.com",
  126. "orgRole": OrganizationUserRole.MANAGER.label.lower(),
  127. "teamRoles": [],
  128. }
  129. with override_settings(ENABLE_USER_REGISTRATION=False):
  130. # Non-existing user cannot be invited
  131. res = self.client.post(
  132. self.members_url, data, content_type="application/json"
  133. )
  134. self.assertEqual(res.status_code, 403)
  135. # Existing user can be invited
  136. self.user = baker.make("users.user", email="new@example.com")
  137. res = self.client.post(
  138. self.members_url, data, content_type="application/json"
  139. )
  140. self.assertEqual(res.status_code, 201)
  141. def test_organization_users_invite_twice(self):
  142. """Don't allow inviting user who is already in the group"""
  143. data = {
  144. "email": "new@example.com",
  145. "orgRole": OrganizationUserRole.MANAGER.label.lower(),
  146. "teamRoles": [],
  147. "reinvite": False,
  148. }
  149. res = self.client.post(self.members_url, data, content_type="application/json")
  150. self.assertEqual(res.status_code, 201)
  151. with transaction.atomic():
  152. res = self.client.post(
  153. self.members_url, data, content_type="application/json"
  154. )
  155. self.assertEqual(res.status_code, 409)
  156. data["email"] = self.user.email
  157. res = self.client.post(self.members_url, data, content_type="application/json")
  158. self.assertEqual(res.status_code, 409)
  159. def test_organization_users_create(self):
  160. team = baker.make("teams.Team", organization=self.organization)
  161. data = {
  162. "email": "new@example.com",
  163. "orgRole": OrganizationUserRole.MANAGER.label.lower(),
  164. "teamRoles": [{"teamSlug": team.slug}],
  165. }
  166. res = self.client.post(
  167. self.members_url, json.dumps(data), content_type="application/json"
  168. )
  169. self.assertContains(res, data["email"], status_code=201)
  170. self.assertEqual(res.json()["role"], "manager")
  171. self.assertTrue(
  172. OrganizationUser.objects.filter(
  173. organization=self.organization,
  174. email=data["email"],
  175. user=None,
  176. role=OrganizationUserRole.MANAGER,
  177. ).exists()
  178. )
  179. self.assertTrue(team.members.exists())
  180. self.assertEqual(len(mail.outbox), 1)
  181. def test_organization_users_create_and_accept(self):
  182. data = {
  183. "email": "new@example.com",
  184. "orgRole": OrganizationUserRole.MANAGER.label.lower(),
  185. "teamRoles": [],
  186. }
  187. self.client.post(self.members_url, data, content_type="application/json")
  188. body = mail.outbox[0].body
  189. body[body.find("http://localhost:8000/accept/") :].split("/")[4]
  190. def test_organization_users_create_without_permissions(self):
  191. """Admin cannot add users to org"""
  192. other_user = baker.make("users.user")
  193. self.organization.add_user(other_user, role=OrganizationUserRole.MANAGER)
  194. self.org_user.role = OrganizationUserRole.ADMIN
  195. self.org_user.save()
  196. data = {
  197. "email": "new@example.com",
  198. "orgRole": OrganizationUserRole.MANAGER.label.lower(),
  199. "teamRoles": [],
  200. }
  201. res = self.client.post(self.members_url, data, content_type="application/json")
  202. self.assertEqual(res.status_code, 403)
  203. def test_organization_users_reinvite(self):
  204. other_user = baker.make("users.user")
  205. baker.make(
  206. "organizations_ext.OrganizationUser",
  207. email=other_user.email,
  208. organization=self.organization,
  209. )
  210. data = {
  211. "email": other_user.email,
  212. "orgRole": OrganizationUserRole.MANAGER.label.lower(),
  213. "teamRoles": [],
  214. }
  215. res = self.client.post(self.members_url, data, content_type="application/json")
  216. self.assertContains(res, other_user.email, status_code=201)
  217. self.assertTrue(len(mail.outbox))
  218. def test_organization_users_update(self):
  219. other_user = baker.make("users.user")
  220. other_org_user = self.organization.add_user(other_user)
  221. url = self.get_org_member_detail_url(self.organization.slug, other_org_user.pk)
  222. new_role = OrganizationUserRole.ADMIN
  223. data = {"orgRole": new_role.label.lower(), "teamRoles": []}
  224. res = self.client.put(url, data, content_type="application/json")
  225. self.assertContains(res, other_user.email)
  226. self.assertTrue(
  227. OrganizationUser.objects.filter(
  228. organization=self.organization, role=new_role, user=other_user
  229. ).exists()
  230. )
  231. def test_organization_users_update_without_permissions(self):
  232. self.org_user.role = OrganizationUserRole.ADMIN
  233. self.org_user.save()
  234. other_user = baker.make("users.user")
  235. other_org_user = self.organization.add_user(other_user)
  236. url = self.get_org_member_detail_url(self.organization.slug, other_org_user.pk)
  237. new_role = OrganizationUserRole.ADMIN
  238. data = {"orgRole": new_role.label.lower(), "teamRoles": []}
  239. res = self.client.put(url, data, content_type="application/json")
  240. self.assertEqual(res.status_code, 403)
  241. def test_organization_users_delete(self):
  242. other_user = baker.make("users.user")
  243. other_org_user = self.organization.add_user(other_user)
  244. url = self.get_org_member_detail_url(self.organization.slug, other_org_user.pk)
  245. res = self.client.delete(url)
  246. self.assertEqual(res.status_code, 204)
  247. self.assertEqual(other_user.organizations_ext_organizationuser.count(), 0)
  248. url = self.get_org_member_detail_url(self.organization.slug, self.org_user.pk)
  249. res = self.client.delete(url)
  250. self.assertEqual(
  251. res.status_code,
  252. 400,
  253. "Org owner should not be able to remove themselves from org",
  254. )
  255. third_user = baker.make("users.user")
  256. third_org_user = self.organization.add_user(third_user)
  257. change_ownership_url = (
  258. self.get_org_member_detail_url(self.organization.slug, third_org_user.pk)
  259. + "set_owner/"
  260. )
  261. self.client.post(change_ownership_url)
  262. res = self.client.delete(url)
  263. self.assertEqual(
  264. res.status_code,
  265. 204,
  266. "Can remove self after transferring ownership",
  267. )
  268. def test_organization_users_delete_without_permissions(self):
  269. self.org_user.role = OrganizationUserRole.ADMIN
  270. self.org_user.save()
  271. other_user = baker.make("users.user")
  272. other_org_user = self.organization.add_user(other_user)
  273. url = self.get_org_member_detail_url(self.organization.slug, other_org_user.pk)
  274. res = self.client.delete(url)
  275. self.assertEqual(res.status_code, 403)
  276. self.assertEqual(other_user.organizations_ext_organizationuser.count(), 1)
  277. def test_organization_members_set_owner(self):
  278. other_user = baker.make("users.user")
  279. other_org_user = self.organization.add_user(other_user)
  280. random_org_user = baker.make("organizations_ext.OrganizationUser")
  281. url = reverse(
  282. "api:set_organization_owner",
  283. args=[self.organization.slug, random_org_user.pk],
  284. )
  285. res = self.client.post(url)
  286. self.assertEqual(
  287. res.status_code, 404, "Don't set random unrelated users as owner"
  288. )
  289. url = (
  290. self.get_org_member_detail_url(self.organization.slug, other_org_user.pk)
  291. + "set_owner/"
  292. )
  293. res = self.client.post(url)
  294. self.assertTrue(
  295. res.json()["isOwner"], "Current owner may set another org member as owner"
  296. )
  297. url = reverse(
  298. "api:set_organization_owner",
  299. args=[self.organization.slug, self.org_user.pk],
  300. )
  301. url = (
  302. self.get_org_member_detail_url(self.organization.slug, self.org_user.pk)
  303. + "set_owner/"
  304. )
  305. self.org_user.role = OrganizationUserRole.MANAGER
  306. self.org_user.save()
  307. res = self.client.post(url)
  308. self.assertEqual(
  309. res.status_code, 403, "Can't set self as owner with only manager role"
  310. )
  311. self.org_user.role = OrganizationUserRole.OWNER
  312. self.org_user.save()
  313. res = self.client.post(url)
  314. self.assertTrue(res.json()["isOwner"], "Owner role may set org member as owner")
  315. self.assertEqual(self.organization.owners.count(), 1)