test_organization_users.py 16 KB

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