test_organization_users.py 16 KB

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