test_users_api.py 17 KB

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