test_users_api.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. from datetime import timedelta
  2. from django.contrib.auth import get_user_model
  3. from misago.acl.testutils import override_acl
  4. from misago.conf import settings
  5. from misago.core import threadstore
  6. from misago.core.cache import cache
  7. from misago.forums.models import Forum
  8. from misago.threads.models import Thread, Post
  9. from misago.threads.testutils import post_thread
  10. from misago.users.models import Rank
  11. from misago.users.testutils import AuthenticatedUserTestCase
  12. class ActivePostersListTests(AuthenticatedUserTestCase):
  13. """
  14. tests for active posters list (GET /users/?list=active)
  15. """
  16. def setUp(self):
  17. super(ActivePostersListTests, self).setUp()
  18. self.link = '/api/users/?list=active'
  19. cache.clear()
  20. threadstore.clear()
  21. self.forum = Forum.objects.all_forums().filter(role="forum")[:1][0]
  22. self.forum.labels = []
  23. def test_empty_list(self):
  24. """empty list is served"""
  25. response = self.client.get(self.link)
  26. self.assertEqual(response.status_code, 200)
  27. self.assertNotIn(self.user.username, response.content)
  28. response = self.client.get(self.link)
  29. self.assertEqual(response.status_code, 200)
  30. self.assertNotIn(self.user.username, response.content)
  31. def test_filled_list(self):
  32. """filled list is served"""
  33. post_thread(self.forum, poster=self.user)
  34. self.user.posts = 1
  35. self.user.save()
  36. response = self.client.get(self.link)
  37. self.assertEqual(response.status_code, 200)
  38. self.assertIn(self.user.username, response.content)
  39. self.assertIn('"is_online":true', response.content)
  40. self.assertIn('"is_offline":false', response.content)
  41. self.logout_user()
  42. response = self.client.get(self.link)
  43. self.assertEqual(response.status_code, 200)
  44. self.assertIn(self.user.username, response.content)
  45. self.assertIn('"is_online":false', response.content)
  46. self.assertIn('"is_offline":true', response.content)
  47. class FollowersListTests(AuthenticatedUserTestCase):
  48. """
  49. tests for generic list (GET /users/) filtered by followers
  50. """
  51. def setUp(self):
  52. super(FollowersListTests, self).setUp()
  53. self.link = '/api/users/?&followers='
  54. def test_nonexistent_user(self):
  55. """list for non-existing user returns 404"""
  56. response = self.client.get(self.link + 'this-user-is-fake')
  57. self.assertEqual(response.status_code, 404)
  58. def test_empty_list(self):
  59. """user without followers returns 200"""
  60. rank_slug = self.user.rank.slug
  61. response = self.client.get(self.link + self.user.slug)
  62. self.assertEqual(response.status_code, 200)
  63. def test_filled_list(self):
  64. """user with followers returns 200"""
  65. User = get_user_model()
  66. test_follower = User.objects.create_user(
  67. "TestFollower", "test@follower.com", self.USER_PASSWORD)
  68. self.user.followed_by.add(test_follower)
  69. response = self.client.get(self.link + self.user.slug)
  70. self.assertEqual(response.status_code, 200)
  71. self.assertIn(test_follower.username, response.content)
  72. class FollowsListTests(AuthenticatedUserTestCase):
  73. """
  74. tests for generic list (GET /users/) filtered by follows
  75. """
  76. def setUp(self):
  77. super(FollowsListTests, self).setUp()
  78. self.link = '/api/users/?&follows='
  79. def test_nonexistent_user(self):
  80. """list for non-existing user returns 404"""
  81. response = self.client.get(self.link + 'this-user-is-fake')
  82. self.assertEqual(response.status_code, 404)
  83. def test_empty_list(self):
  84. """user without follows returns 200"""
  85. rank_slug = self.user.rank.slug
  86. response = self.client.get(self.link + self.user.slug)
  87. self.assertEqual(response.status_code, 200)
  88. def test_filled_list(self):
  89. """user with follows returns 200"""
  90. User = get_user_model()
  91. test_follower = User.objects.create_user(
  92. "TestFollower", "test@follower.com", self.USER_PASSWORD)
  93. self.user.follows.add(test_follower)
  94. response = self.client.get(self.link + self.user.slug)
  95. self.assertEqual(response.status_code, 200)
  96. self.assertIn(test_follower.username, response.content)
  97. class RankListTests(AuthenticatedUserTestCase):
  98. """
  99. tests for generic list (GET /users/) filtered by rank
  100. """
  101. def setUp(self):
  102. super(RankListTests, self).setUp()
  103. self.link = '/api/users/?rank='
  104. def test_nonexistent_rank(self):
  105. """list for non-existing rank returns 404"""
  106. response = self.client.get(self.link + 'this-rank-is-non-existing')
  107. self.assertEqual(response.status_code, 404)
  108. def test_empty_list(self):
  109. """tab rank without members returns 200"""
  110. test_rank = Rank.objects.create(
  111. name="Test rank",
  112. slug="test-rank",
  113. is_tab=True
  114. )
  115. response = self.client.get(self.link + test_rank.slug)
  116. self.assertEqual(response.status_code, 200)
  117. def test_disabled_list(self):
  118. """non-tab rank returns 404"""
  119. self.user.rank.is_tab = False
  120. self.user.rank.save()
  121. response = self.client.get(self.link + self.user.rank.slug)
  122. self.assertEqual(response.status_code, 404)
  123. def test_filled_list(self):
  124. """tab rank with members return 200"""
  125. self.user.rank.is_tab = True
  126. self.user.rank.save()
  127. response = self.client.get(self.link + self.user.rank.slug)
  128. self.assertEqual(response.status_code, 200)
  129. self.assertIn(self.user.username, response.content)
  130. class SearchNamesListTests(AuthenticatedUserTestCase):
  131. """
  132. tests for generic list (GET /users/) filtered by username
  133. """
  134. def setUp(self):
  135. super(SearchNamesListTests, self).setUp()
  136. self.link = '/api/users/?&name='
  137. def test_empty_list(self):
  138. """empty list returns 200"""
  139. response = self.client.get(self.link + 'this-user-is-fake')
  140. self.assertEqual(response.status_code, 200)
  141. def test_filled_list(self):
  142. """filled list returns 200"""
  143. response = self.client.get(self.link + self.user.slug)
  144. self.assertEqual(response.status_code, 200)
  145. self.assertIn(self.user.username, response.content)
  146. class UserForumOptionsTests(AuthenticatedUserTestCase):
  147. """
  148. tests for user forum options RPC (POST to /api/users/1/forum-options/)
  149. """
  150. def setUp(self):
  151. super(UserForumOptionsTests, self).setUp()
  152. self.link = '/api/users/%s/forum-options/' % self.user.pk
  153. def test_empty_request(self):
  154. """empty request is handled"""
  155. response = self.client.post(self.link)
  156. self.assertEqual(response.status_code, 400)
  157. fields = (
  158. 'limits_private_thread_invites_to',
  159. 'subscribe_to_started_threads',
  160. 'subscribe_to_replied_threads'
  161. )
  162. for field in fields:
  163. self.assertIn('"%s"' % field, response.content)
  164. def test_change_forum_options(self):
  165. """forum options are changed"""
  166. response = self.client.post(self.link, data={
  167. 'limits_private_thread_invites_to': 1,
  168. 'subscribe_to_started_threads': 2,
  169. 'subscribe_to_replied_threads': 1
  170. })
  171. self.assertEqual(response.status_code, 200)
  172. self.reload_user();
  173. self.assertFalse(self.user.is_hiding_presence)
  174. self.assertEqual(self.user.limits_private_thread_invites_to, 1)
  175. self.assertEqual(self.user.subscribe_to_started_threads, 2)
  176. self.assertEqual(self.user.subscribe_to_replied_threads, 1)
  177. class UserFollowTests(AuthenticatedUserTestCase):
  178. """
  179. tests for user follow RPC (POST to /api/users/1/follow/)
  180. """
  181. def setUp(self):
  182. super(UserFollowTests, self).setUp()
  183. User = get_user_model()
  184. self.other_user = User.objects.create_user(
  185. "OtherUser", "other@user.com", "pass123")
  186. self.link = '/api/users/%s/follow/' % self.other_user.pk
  187. def test_follow_unauthenticated(self):
  188. """you have to sign in to follow users"""
  189. self.logout_user()
  190. response = self.client.post(self.link)
  191. self.assertEqual(response.status_code, 403)
  192. self.assertIn("action is not available to guests", response.content)
  193. def test_follow_myself(self):
  194. """you can't follow yourself"""
  195. response = self.client.post('/api/users/%s/follow/' % self.user.pk)
  196. self.assertEqual(response.status_code, 403)
  197. self.assertIn("can't add yourself to followed", response.content)
  198. def test_cant_follow(self):
  199. """no permission to follow users"""
  200. override_acl(self.user, {
  201. 'can_follow_users': 0,
  202. })
  203. response = self.client.post(self.link)
  204. self.assertEqual(response.status_code, 403)
  205. self.assertIn("can't follow other users", response.content)
  206. def test_follow(self):
  207. """follow and unfollow other user"""
  208. response = self.client.post(self.link)
  209. self.assertEqual(response.status_code, 200)
  210. User = get_user_model()
  211. user = User.objects.get(pk=self.user.pk)
  212. self.assertEqual(user.followers, 0)
  213. self.assertEqual(user.following, 1)
  214. self.assertEqual(user.follows.count(), 1)
  215. self.assertEqual(user.followed_by.count(), 0)
  216. followed = User.objects.get(pk=self.other_user.pk)
  217. self.assertEqual(followed.followers, 1)
  218. self.assertEqual(followed.following, 0)
  219. self.assertEqual(followed.follows.count(), 0)
  220. self.assertEqual(followed.followed_by.count(), 1)
  221. response = self.client.post(self.link)
  222. self.assertEqual(response.status_code, 200)
  223. user = User.objects.get(pk=self.user.pk)
  224. self.assertEqual(user.followers, 0)
  225. self.assertEqual(user.following, 0)
  226. self.assertEqual(user.follows.count(), 0)
  227. self.assertEqual(user.followed_by.count(), 0)
  228. followed = User.objects.get(pk=self.other_user.pk)
  229. self.assertEqual(followed.followers, 0)
  230. self.assertEqual(followed.following, 0)
  231. self.assertEqual(followed.follows.count(), 0)
  232. self.assertEqual(followed.followed_by.count(), 0)
  233. class UserDeleteTests(AuthenticatedUserTestCase):
  234. """
  235. tests for user delete RPC (POST to /api/users/1/delete/)
  236. """
  237. def setUp(self):
  238. super(UserDeleteTests, self).setUp()
  239. User = get_user_model()
  240. self.other_user = User.objects.create_user(
  241. "OtherUser", "other@user.com", "pass123")
  242. self.link = '/api/users/%s/delete/' % self.other_user.pk
  243. self.threads = Thread.objects.count()
  244. self.posts = Post.objects.count()
  245. self.forum = Forum.objects.all_forums().filter(role="forum")[:1][0]
  246. post_thread(self.forum, poster=self.other_user)
  247. self.other_user.posts = 1
  248. self.other_user.threads = 1
  249. self.other_user.save()
  250. def test_delete_no_permission(self):
  251. """raises 403 error when no permission to delete"""
  252. override_acl(self.user, {
  253. 'can_delete_users_newer_than': 0,
  254. 'can_delete_users_with_less_posts_than': 0,
  255. })
  256. response = self.client.post(self.link)
  257. self.assertEqual(response.status_code, 403)
  258. self.assertIn("can't delete users", response.content)
  259. def test_delete_too_many_posts(self):
  260. """raises 403 error when user has too many posts"""
  261. override_acl(self.user, {
  262. 'can_delete_users_newer_than': 0,
  263. 'can_delete_users_with_less_posts_than': 5,
  264. })
  265. self.other_user.posts = 6
  266. self.other_user.save()
  267. response = self.client.post(self.link)
  268. self.assertEqual(response.status_code, 403)
  269. self.assertIn("can't delete users", response.content)
  270. def test_delete_too_many_posts(self):
  271. """raises 403 error when user has too many posts"""
  272. override_acl(self.user, {
  273. 'can_delete_users_newer_than': 0,
  274. 'can_delete_users_with_less_posts_than': 5,
  275. })
  276. self.other_user.posts = 6
  277. self.other_user.save()
  278. response = self.client.post(self.link)
  279. self.assertEqual(response.status_code, 403)
  280. self.assertIn("can't delete users", response.content)
  281. self.assertIn("made more than 5 posts", response.content)
  282. def test_delete_too_old_member(self):
  283. """raises 403 error when user is too old"""
  284. override_acl(self.user, {
  285. 'can_delete_users_newer_than': 5,
  286. 'can_delete_users_with_less_posts_than': 0,
  287. })
  288. self.other_user.joined_on -= timedelta(days=6)
  289. self.other_user.save()
  290. response = self.client.post(self.link)
  291. self.assertEqual(response.status_code, 403)
  292. self.assertIn("can't delete users", response.content)
  293. self.assertIn("members for more than 5 days", response.content)
  294. def test_delete_self(self):
  295. """raises 403 error when attempting to delete oneself"""
  296. override_acl(self.user, {
  297. 'can_delete_users_newer_than': 10,
  298. 'can_delete_users_with_less_posts_than': 10,
  299. })
  300. response = self.client.post('/api/users/%s/delete/' % self.user.pk)
  301. self.assertEqual(response.status_code, 403)
  302. self.assertIn("can't delete yourself", response.content)
  303. def test_delete_admin(self):
  304. """raises 403 error when attempting to delete admin"""
  305. override_acl(self.user, {
  306. 'can_delete_users_newer_than': 10,
  307. 'can_delete_users_with_less_posts_than': 10,
  308. })
  309. self.other_user.is_staff = True
  310. self.other_user.save()
  311. response = self.client.post(self.link)
  312. self.assertEqual(response.status_code, 403)
  313. self.assertIn("can't delete administrators", response.content)
  314. def test_delete_superadmin(self):
  315. """raises 403 error when attempting to delete superadmin"""
  316. override_acl(self.user, {
  317. 'can_delete_users_newer_than': 10,
  318. 'can_delete_users_with_less_posts_than': 10,
  319. })
  320. self.other_user.is_superuser = True
  321. self.other_user.save()
  322. response = self.client.post(self.link)
  323. self.assertEqual(response.status_code, 403)
  324. self.assertIn("can't delete administrators", response.content)
  325. def test_delete_with_content(self):
  326. """returns 200 and deletes user with content"""
  327. override_acl(self.user, {
  328. 'can_delete_users_newer_than': 10,
  329. 'can_delete_users_with_less_posts_than': 10,
  330. })
  331. response = self.client.post(self.link, data={'with_content': True})
  332. self.assertEqual(response.status_code, 200)
  333. User = get_user_model()
  334. with self.assertRaises(User.DoesNotExist):
  335. User.objects.get(pk=self.other_user.pk)
  336. self.assertEqual(Thread.objects.count(), self.threads)
  337. self.assertEqual(Post.objects.count(), self.posts)
  338. def test_delete_without_content(self):
  339. """returns 200 and deletes user without content"""
  340. override_acl(self.user, {
  341. 'can_delete_users_newer_than': 10,
  342. 'can_delete_users_with_less_posts_than': 10,
  343. })
  344. response = self.client.post(self.link, data={'with_content': False})
  345. self.assertEqual(response.status_code, 200)
  346. User = get_user_model()
  347. with self.assertRaises(User.DoesNotExist):
  348. User.objects.get(pk=self.other_user.pk)
  349. self.assertEqual(Thread.objects.count(), self.threads + 1)
  350. self.assertEqual(Post.objects.count(), self.posts + 1)