test_threadslists.py 58 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633
  1. from datetime import timedelta
  2. from json import loads as json_loads
  3. from django.conf import settings
  4. from django.utils import timezone
  5. from misago.acl.testutils import override_acl
  6. from misago.categories.models import Category
  7. from misago.core import threadstore
  8. from misago.core.cache import cache
  9. from misago.readtracker import categoriestracker, threadstracker
  10. from misago.users.testutils import AuthenticatedUserTestCase
  11. from misago.threads import testutils
  12. LISTS_URLS = (
  13. '',
  14. 'my/',
  15. 'new/',
  16. 'unread/',
  17. 'subscribed/',
  18. )
  19. class ThreadsListTestCase(AuthenticatedUserTestCase):
  20. def setUp(self):
  21. super(ThreadsListTestCase, self).setUp()
  22. self.api_link = '/api/threads/'
  23. self.root = Category.objects.root_category()
  24. self.first_category = Category.objects.get(slug='first-category')
  25. """
  26. Create categories tree for test cases:
  27. First category (created by migration)
  28. Category A
  29. + Category B
  30. + Subcategory C
  31. + Subcategory D
  32. Category E
  33. + Subcategory F
  34. """
  35. Category(
  36. name='Category A',
  37. slug='category-a',
  38. css_class='showing-category-a',
  39. ).insert_at(self.root, position='last-child', save=True)
  40. Category(
  41. name='Category E',
  42. slug='category-e',
  43. css_class='showing-category-e',
  44. ).insert_at(self.root, position='last-child', save=True)
  45. self.root = Category.objects.root_category()
  46. self.category_a = Category.objects.get(slug='category-a')
  47. Category(
  48. name='Category B',
  49. slug='category-b',
  50. css_class='showing-category-b',
  51. ).insert_at(self.category_a, position='last-child', save=True)
  52. self.category_b = Category.objects.get(slug='category-b')
  53. Category(
  54. name='Category C',
  55. slug='category-c',
  56. css_class='showing-category-c',
  57. ).insert_at(self.category_b, position='last-child', save=True)
  58. Category(
  59. name='Category D',
  60. slug='category-d',
  61. css_class='showing-category-d',
  62. ).insert_at(self.category_b, position='last-child', save=True)
  63. self.category_c = Category.objects.get(slug='category-c')
  64. self.category_d = Category.objects.get(slug='category-d')
  65. self.category_e = Category.objects.get(slug='category-e')
  66. Category(
  67. name='Category F',
  68. slug='category-f',
  69. css_class='showing-category-f',
  70. ).insert_at(self.category_e, position='last-child', save=True)
  71. self.category_f = Category.objects.get(slug='category-f')
  72. self.clear_state()
  73. Category.objects.partial_rebuild(self.root.tree_id)
  74. self.root = Category.objects.root_category()
  75. self.category_a = Category.objects.get(slug='category-a')
  76. self.category_b = Category.objects.get(slug='category-b')
  77. self.category_c = Category.objects.get(slug='category-c')
  78. self.category_d = Category.objects.get(slug='category-d')
  79. self.category_e = Category.objects.get(slug='category-e')
  80. self.category_f = Category.objects.get(slug='category-f')
  81. self.access_all_categories()
  82. def access_all_categories(self, category_acl=None, base_acl=None):
  83. self.clear_state()
  84. categories_acl = {
  85. 'categories': {},
  86. 'visible_categories': [],
  87. 'can_approve_content': [],
  88. }
  89. if base_acl:
  90. categories_acl.update(base_acl)
  91. for category in Category.objects.all_categories(include_root=True):
  92. categories_acl['visible_categories'].append(category.pk)
  93. categories_acl['categories'][category.pk] = {
  94. 'can_see': 1,
  95. 'can_browse': 1,
  96. 'can_see_all_threads': 1,
  97. 'can_see_own_threads': 0,
  98. 'can_hide_threads': 0,
  99. 'can_approve_content': 0,
  100. }
  101. if category_acl:
  102. categories_acl['categories'][category.pk].update(category_acl)
  103. if category_acl.get('can_approve_content'):
  104. categories_acl['can_approve_content'].append(category.pk)
  105. override_acl(self.user, categories_acl)
  106. return categories_acl
  107. class AllThreadsListTests(ThreadsListTestCase):
  108. def test_list_renders_empty(self):
  109. """empty threads list renders"""
  110. for url in LISTS_URLS:
  111. self.access_all_categories()
  112. response = self.client.get('/' + url)
  113. self.assertEqual(response.status_code, 200)
  114. self.assertIn("empty-message", response.content)
  115. self.access_all_categories()
  116. response = self.client.get(self.category_b.get_absolute_url() + url)
  117. self.assertEqual(response.status_code, 200)
  118. self.assertIn(self.category_b.name, response.content)
  119. self.assertIn("empty-message", response.content)
  120. self.access_all_categories()
  121. response = self.client.get(
  122. '%s?list=%s' % (self.api_link, url.strip('/')))
  123. self.assertEqual(response.status_code, 200)
  124. response_json = json_loads(response.content)
  125. self.assertEqual(len(response_json['results']), 0)
  126. def test_list_authenticated_only_views(self):
  127. """authenticated only views return 403 for guests"""
  128. for url in LISTS_URLS:
  129. self.access_all_categories()
  130. response = self.client.get('/' + url)
  131. self.assertEqual(response.status_code, 200)
  132. self.access_all_categories()
  133. response = self.client.get(self.category_b.get_absolute_url() + url)
  134. self.assertEqual(response.status_code, 200)
  135. self.assertIn(self.category_b.name, response.content)
  136. self.access_all_categories()
  137. self.access_all_categories()
  138. response = self.client.get('%s?category=%s&list=%s' % (
  139. self.api_link,
  140. self.category_b.pk,
  141. url.strip('/'),
  142. ))
  143. self.assertEqual(response.status_code, 200)
  144. self.logout_user()
  145. self.user = self.get_anonymous_user()
  146. for url in LISTS_URLS[1:]:
  147. self.access_all_categories()
  148. response = self.client.get('/' + url)
  149. self.assertEqual(response.status_code, 403)
  150. self.access_all_categories()
  151. response = self.client.get(self.category_b.get_absolute_url() + url)
  152. self.assertEqual(response.status_code, 403)
  153. self.access_all_categories()
  154. response = self.client.get('%s?category=%s&list=%s' % (
  155. self.api_link,
  156. self.category_b.pk,
  157. url.strip('/'),
  158. ))
  159. self.assertEqual(response.status_code, 403)
  160. def test_empty_list_hides_categories_picker(self):
  161. """categories picker is hidden on empty list"""
  162. Category(
  163. name='Hidden Category',
  164. slug='hidden-category',
  165. ).insert_at(self.root, position='last-child', save=True)
  166. test_category = Category.objects.get(slug='hidden-category')
  167. self.access_all_categories()
  168. response = self.client.get('/')
  169. self.assertEqual(response.status_code, 200)
  170. self.assertNotIn(
  171. 'subcategory-%s' % self.category_a.css_class, response.content)
  172. self.assertNotIn(
  173. 'subcategory-%s' % self.category_e.css_class, response.content)
  174. self.access_all_categories()
  175. response = self.client.get(self.category_a.get_absolute_url())
  176. self.assertEqual(response.status_code, 200)
  177. self.assertNotIn(
  178. 'subcategory-%s' % self.category_b.css_class, response.content)
  179. self.access_all_categories()
  180. response = self.client.get(self.api_link)
  181. self.assertEqual(response.status_code, 200)
  182. response_json = json_loads(response.content)
  183. self.assertEqual(len(response_json['subcategories']), 0)
  184. def test_list_renders_categories_picker(self):
  185. """categories picker renders valid categories"""
  186. Category(
  187. name='Hidden Category',
  188. slug='hidden-category',
  189. ).insert_at(self.root, position='last-child', save=True)
  190. test_category = Category.objects.get(slug='hidden-category')
  191. testutils.post_thread(
  192. category=self.category_b,
  193. )
  194. response = self.client.get('/')
  195. self.assertEqual(response.status_code, 200)
  196. self.assertIn(
  197. 'subcategory-%s' % self.category_a.css_class, response.content)
  198. # readable categories, but non-accessible directly
  199. self.assertNotIn(
  200. 'subcategory-%s' % self.category_b.css_class, response.content)
  201. self.assertNotIn(
  202. 'subcategory-%s' % self.category_c.css_class, response.content)
  203. self.assertNotIn(
  204. 'subcategory-%s' % self.category_d.css_class, response.content)
  205. self.assertNotIn(
  206. 'subcategory-%s' % self.category_f.css_class, response.content)
  207. # hidden category
  208. self.assertNotIn(
  209. 'subcategory-%s' % test_category.css_class, response.content)
  210. self.access_all_categories()
  211. response = self.client.get(self.api_link)
  212. self.assertEqual(response.status_code, 200)
  213. response_json = json_loads(response.content)
  214. self.assertEqual(
  215. response_json['subcategories'][0], self.category_a.pk)
  216. # test category view
  217. self.access_all_categories()
  218. response = self.client.get(self.category_a.get_absolute_url())
  219. self.assertEqual(response.status_code, 200)
  220. self.assertIn(
  221. 'subcategory-%s' % self.category_b.css_class, response.content)
  222. # readable categories, but non-accessible directly
  223. self.assertNotIn(
  224. 'subcategory-%s' % self.category_c.css_class, response.content)
  225. self.assertNotIn(
  226. 'subcategory-%s' % self.category_d.css_class, response.content)
  227. self.assertNotIn(
  228. 'subcategory-%s' % self.category_f.css_class, response.content)
  229. self.access_all_categories()
  230. response = self.client.get(
  231. '%s?category=%s' % (self.api_link, self.category_a.pk))
  232. self.assertEqual(response.status_code, 200)
  233. response_json = json_loads(response.content)
  234. self.assertEqual(
  235. response_json['subcategories'][0], self.category_b.pk)
  236. def test_display_pinned_threads(self):
  237. """
  238. threads list displays globally pinned threads first
  239. and locally ones inbetween other
  240. """
  241. globally = testutils.post_thread(
  242. category=self.first_category,
  243. is_global=True,
  244. )
  245. locally = testutils.post_thread(
  246. category=self.first_category,
  247. is_pinned=True,
  248. )
  249. standard = testutils.post_thread(category=self.first_category)
  250. response = self.client.get('/')
  251. self.assertEqual(response.status_code, 200)
  252. positions = {
  253. 'g': response.content.find(globally.get_absolute_url()),
  254. 'l': response.content.find(locally.get_absolute_url()),
  255. 's': response.content.find(standard.get_absolute_url()),
  256. }
  257. # global announcement before others
  258. self.assertTrue(positions['g'] < positions['l'])
  259. self.assertTrue(positions['g'] < positions['s'])
  260. # standard in the middle
  261. self.assertTrue(positions['s'] < positions['l'])
  262. self.assertTrue(positions['s'] > positions['g'])
  263. # pinned last
  264. self.assertTrue(positions['l'] > positions['g'])
  265. self.assertTrue(positions['l'] > positions['s'])
  266. # API behaviour is identic
  267. response = self.client.get('/api/threads/')
  268. self.assertEqual(response.status_code, 200)
  269. positions = {
  270. 'g': response.content.find(globally.get_absolute_url()),
  271. 'l': response.content.find(locally.get_absolute_url()),
  272. 's': response.content.find(standard.get_absolute_url()),
  273. }
  274. # global announcement before others
  275. self.assertTrue(positions['g'] < positions['l'])
  276. self.assertTrue(positions['g'] < positions['s'])
  277. # standard in the middle
  278. self.assertTrue(positions['s'] < positions['l'])
  279. self.assertTrue(positions['s'] > positions['g'])
  280. # pinned last
  281. self.assertTrue(positions['l'] > positions['g'])
  282. self.assertTrue(positions['l'] > positions['s'])
  283. def test_noscript_pagination(self):
  284. """threads list is paginated for users with js disabled"""
  285. threads = []
  286. for i in xrange(24 * 3):
  287. threads.append(testutils.post_thread(category=self.first_category))
  288. # secondary page renders
  289. response = self.client.get('/?page=2')
  290. self.assertEqual(response.status_code, 200)
  291. for thread in threads[:24]:
  292. self.assertNotIn(thread.get_absolute_url(), response.content)
  293. for thread in threads[24:48]:
  294. self.assertIn(thread.get_absolute_url(), response.content)
  295. for thread in threads[48:]:
  296. self.assertNotIn(thread.get_absolute_url(), response.content)
  297. self.assertNotIn('/?page=1', response.content)
  298. self.assertIn('/?page=3', response.content)
  299. # third page renders
  300. response = self.client.get('/?page=3')
  301. self.assertEqual(response.status_code, 200)
  302. for thread in threads[24:]:
  303. self.assertNotIn(thread.get_absolute_url(), response.content)
  304. for thread in threads[:24]:
  305. self.assertIn(thread.get_absolute_url(), response.content)
  306. self.assertIn('/?page=2', response.content)
  307. self.assertNotIn('/?page=4', response.content)
  308. # excessive page gives 404
  309. response = self.client.get('/?page=4')
  310. self.assertEqual(response.status_code, 404)
  311. class CategoryThreadsListTests(ThreadsListTestCase):
  312. def test_access_hidden_category(self):
  313. """hidden category returns 404"""
  314. Category(
  315. name='Hidden Category',
  316. slug='hidden-category',
  317. ).insert_at(self.root, position='last-child', save=True)
  318. test_category = Category.objects.get(slug='hidden-category')
  319. for url in LISTS_URLS:
  320. response = self.client.get(test_category.get_absolute_url() + url)
  321. self.assertEqual(response.status_code, 404)
  322. response = self.client.get(
  323. '%s?category=%s' % (self.api_link, test_category.pk))
  324. self.assertEqual(response.status_code, 404)
  325. def test_access_protected_category(self):
  326. """protected category returns 403"""
  327. Category(
  328. name='Hidden Category',
  329. slug='hidden-category',
  330. ).insert_at(self.root, position='last-child', save=True)
  331. test_category = Category.objects.get(slug='hidden-category')
  332. for url in LISTS_URLS:
  333. override_acl(self.user, {
  334. 'visible_categories': [test_category.pk],
  335. 'categories': {
  336. test_category.pk: {
  337. 'can_see': 1,
  338. 'can_browse': 0,
  339. }
  340. }
  341. });
  342. response = self.client.get(test_category.get_absolute_url() + url)
  343. self.assertEqual(response.status_code, 403)
  344. override_acl(self.user, {
  345. 'visible_categories': [test_category.pk],
  346. 'categories': {
  347. test_category.pk: {
  348. 'can_see': 1,
  349. 'can_browse': 0,
  350. }
  351. }
  352. });
  353. response = self.client.get('%s?category=%s&list=%s' % (
  354. self.api_link,
  355. test_category.pk,
  356. url.strip('/'),
  357. ))
  358. self.assertEqual(response.status_code, 403)
  359. def test_display_pinned_threads(self):
  360. """
  361. category threads list displays globally pinned threads first
  362. then locally ones and unpinned last
  363. """
  364. globally = testutils.post_thread(
  365. category=self.first_category,
  366. is_global=True,
  367. )
  368. locally = testutils.post_thread(
  369. category=self.first_category,
  370. is_pinned=True,
  371. )
  372. standard = testutils.post_thread(category=self.first_category)
  373. response = self.client.get(self.first_category.get_absolute_url())
  374. self.assertEqual(response.status_code, 200)
  375. positions = {
  376. 'g': response.content.find(globally.get_absolute_url()),
  377. 'l': response.content.find(locally.get_absolute_url()),
  378. 's': response.content.find(standard.get_absolute_url()),
  379. }
  380. # global announcement before others
  381. self.assertTrue(positions['g'] < positions['l'])
  382. self.assertTrue(positions['g'] < positions['s'])
  383. # pinned in the middle
  384. self.assertTrue(positions['l'] < positions['s'])
  385. self.assertTrue(positions['l'] > positions['g'])
  386. # standard last
  387. self.assertTrue(positions['s'] > positions['g'])
  388. self.assertTrue(positions['s'] > positions['g'])
  389. # API behaviour is identic
  390. response = self.client.get(
  391. '/api/threads/?category=%s' % self.first_category.pk)
  392. self.assertEqual(response.status_code, 200)
  393. positions = {
  394. 'g': response.content.find(globally.get_absolute_url()),
  395. 'l': response.content.find(locally.get_absolute_url()),
  396. 's': response.content.find(standard.get_absolute_url()),
  397. }
  398. # global announcement before others
  399. self.assertTrue(positions['g'] < positions['l'])
  400. self.assertTrue(positions['g'] < positions['s'])
  401. # pinned in the middle
  402. self.assertTrue(positions['l'] < positions['s'])
  403. self.assertTrue(positions['l'] > positions['g'])
  404. # standard last
  405. self.assertTrue(positions['s'] > positions['g'])
  406. self.assertTrue(positions['s'] > positions['g'])
  407. class ThreadsVisibilityTests(ThreadsListTestCase):
  408. def test_list_renders_test_thread(self):
  409. """list renders test thread with valid top category"""
  410. test_thread = testutils.post_thread(
  411. category=self.category_c,
  412. )
  413. response = self.client.get('/')
  414. self.assertEqual(response.status_code, 200)
  415. self.assertIn(test_thread.get_absolute_url(), response.content)
  416. self.assertIn(
  417. 'subcategory-%s' % self.category_a.css_class, response.content)
  418. self.assertIn(
  419. 'thread-category-%s' % self.category_a.css_class, response.content)
  420. self.assertIn(
  421. 'thread-category-%s' % self.category_c.css_class, response.content)
  422. # other top category is hidden from user
  423. self.assertNotIn(
  424. 'subcategory-%s' % self.category_e.css_class, response.content)
  425. # api displays same data
  426. self.access_all_categories()
  427. response = self.client.get(self.api_link)
  428. self.assertEqual(response.status_code, 200)
  429. response_json = json_loads(response.content)
  430. self.assertEqual(response_json['results'][0]['id'], test_thread.pk)
  431. self.assertEqual(len(response_json['subcategories']), 1)
  432. self.assertEqual(
  433. response_json['subcategories'][0], self.category_a.pk)
  434. # test category view
  435. self.access_all_categories()
  436. response = self.client.get(self.category_b.get_absolute_url())
  437. self.assertEqual(response.status_code, 200)
  438. # thread displays
  439. self.assertIn(test_thread.get_absolute_url(), response.content)
  440. self.assertNotIn(
  441. 'thread-category-%s' % self.category_b.css_class, response.content)
  442. self.assertIn(
  443. 'thread-category-%s' % self.category_c.css_class, response.content)
  444. # category picker was changed
  445. self.assertIn(
  446. 'subcategory-%s' % self.category_c.css_class, response.content)
  447. self.assertNotIn(
  448. 'subcategory-%s' % self.category_d.css_class, response.content)
  449. # api displays same data
  450. self.access_all_categories()
  451. response = self.client.get(
  452. '%s?category=%s' % (self.api_link, self.category_b.pk))
  453. self.assertEqual(response.status_code, 200)
  454. response_json = json_loads(response.content)
  455. self.assertEqual(response_json['results'][0]['id'], test_thread.pk)
  456. self.assertEqual(len(response_json['subcategories']), 1)
  457. self.assertEqual(
  458. response_json['subcategories'][0], self.category_c.pk)
  459. def test_list_hides_hidden_thread(self):
  460. """list renders empty due to no permission to see thread"""
  461. Category(
  462. name='Hidden Category',
  463. slug='hidden-category',
  464. ).insert_at(self.root, position='last-child', save=True)
  465. test_category = Category.objects.get(slug='hidden-category')
  466. test_thread = testutils.post_thread(
  467. category=test_category,
  468. )
  469. response = self.client.get('/')
  470. self.assertEqual(response.status_code, 200)
  471. self.assertIn("empty-message", response.content)
  472. def test_api_hides_hidden_thread(self):
  473. """api returns empty due to no permission to see thread"""
  474. Category(
  475. name='Hidden Category',
  476. slug='hidden-category',
  477. ).insert_at(self.root, position='last-child', save=True)
  478. test_category = Category.objects.get(slug='hidden-category')
  479. test_thread = testutils.post_thread(
  480. category=test_category,
  481. )
  482. response = self.client.get(self.api_link)
  483. self.assertEqual(response.status_code, 200)
  484. response_json = json_loads(response.content)
  485. self.assertEqual(len(response_json['results']), 0)
  486. def test_list_user_see_own_unapproved_thread(self):
  487. """list renders unapproved thread that belongs to viewer"""
  488. test_thread = testutils.post_thread(
  489. category=self.category_a,
  490. poster=self.user,
  491. is_unapproved=True,
  492. )
  493. response = self.client.get('/')
  494. self.assertEqual(response.status_code, 200)
  495. self.assertIn(test_thread.get_absolute_url(), response.content)
  496. # test api
  497. self.access_all_categories()
  498. response = self.client.get(self.api_link)
  499. self.assertEqual(response.status_code, 200)
  500. response_json = json_loads(response.content)
  501. self.assertEqual(response_json['results'][0]['id'], test_thread.pk)
  502. def test_list_user_cant_see_unapproved_thread(self):
  503. """list hides unapproved thread that belongs to other user"""
  504. test_thread = testutils.post_thread(
  505. category=self.category_a,
  506. is_unapproved=True,
  507. )
  508. response = self.client.get('/')
  509. self.assertEqual(response.status_code, 200)
  510. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  511. # test api
  512. self.access_all_categories()
  513. response = self.client.get(self.api_link)
  514. self.assertEqual(response.status_code, 200)
  515. response_json = json_loads(response.content)
  516. self.assertEqual(len(response_json['results']), 0)
  517. def test_list_user_cant_see_hidden_thread(self):
  518. """list hides hidden thread that belongs to other user"""
  519. test_thread = testutils.post_thread(
  520. category=self.category_a,
  521. is_hidden=True,
  522. )
  523. response = self.client.get('/')
  524. self.assertEqual(response.status_code, 200)
  525. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  526. # test api
  527. self.access_all_categories()
  528. response = self.client.get(self.api_link)
  529. self.assertEqual(response.status_code, 200)
  530. response_json = json_loads(response.content)
  531. self.assertEqual(len(response_json['results']), 0)
  532. def test_list_user_cant_see_own_hidden_thread(self):
  533. """list hides hidden thread that belongs to viewer"""
  534. test_thread = testutils.post_thread(
  535. category=self.category_a,
  536. poster=self.user,
  537. is_hidden=True,
  538. )
  539. response = self.client.get('/')
  540. self.assertEqual(response.status_code, 200)
  541. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  542. # test api
  543. self.access_all_categories()
  544. response = self.client.get(self.api_link)
  545. self.assertEqual(response.status_code, 200)
  546. response_json = json_loads(response.content)
  547. self.assertEqual(len(response_json['results']), 0)
  548. def test_list_user_can_see_own_hidden_thread(self):
  549. """list shows hidden thread that belongs to viewer due to permission"""
  550. test_thread = testutils.post_thread(
  551. category=self.category_a,
  552. poster=self.user,
  553. is_hidden=True,
  554. )
  555. self.access_all_categories({
  556. 'can_hide_threads': 1
  557. })
  558. response = self.client.get('/')
  559. self.assertEqual(response.status_code, 200)
  560. self.assertIn(test_thread.get_absolute_url(), response.content)
  561. # test api
  562. self.access_all_categories({
  563. 'can_hide_threads': 1
  564. })
  565. response = self.client.get(self.api_link)
  566. self.assertEqual(response.status_code, 200)
  567. response_json = json_loads(response.content)
  568. self.assertEqual(response_json['results'][0]['id'], test_thread.pk)
  569. def test_list_user_can_see_hidden_thread(self):
  570. """
  571. list shows hidden thread that belongs to other user due to permission
  572. """
  573. test_thread = testutils.post_thread(
  574. category=self.category_a,
  575. is_hidden=True,
  576. )
  577. self.access_all_categories({
  578. 'can_hide_threads': 1
  579. })
  580. response = self.client.get('/')
  581. self.assertEqual(response.status_code, 200)
  582. self.assertIn(test_thread.get_absolute_url(), response.content)
  583. # test api
  584. self.access_all_categories({
  585. 'can_hide_threads': 1
  586. })
  587. response = self.client.get(self.api_link)
  588. self.assertEqual(response.status_code, 200)
  589. response_json = json_loads(response.content)
  590. self.assertEqual(response_json['results'][0]['id'], test_thread.pk)
  591. def test_list_user_can_see_unapproved_thread(self):
  592. """
  593. list shows hidden thread that belongs to other user due to permission
  594. """
  595. test_thread = testutils.post_thread(
  596. category=self.category_a,
  597. is_unapproved=True,
  598. )
  599. self.access_all_categories({
  600. 'can_approve_content': 1
  601. })
  602. response = self.client.get('/')
  603. self.assertEqual(response.status_code, 200)
  604. self.assertIn(test_thread.get_absolute_url(), response.content)
  605. # test api
  606. self.access_all_categories({
  607. 'can_approve_content': 1
  608. })
  609. response = self.client.get(self.api_link)
  610. self.assertEqual(response.status_code, 200)
  611. response_json = json_loads(response.content)
  612. self.assertEqual(response_json['results'][0]['id'], test_thread.pk)
  613. class MyThreadsListTests(ThreadsListTestCase):
  614. def test_list_renders_empty(self):
  615. """list renders empty"""
  616. self.access_all_categories()
  617. response = self.client.get('/my/')
  618. self.assertEqual(response.status_code, 200)
  619. self.assertIn("empty-message", response.content)
  620. self.access_all_categories()
  621. response = self.client.get(self.category_a.get_absolute_url() + 'my/')
  622. self.assertEqual(response.status_code, 200)
  623. self.assertIn("empty-message", response.content)
  624. # test api
  625. self.access_all_categories()
  626. response = self.client.get('%s?list=my' % self.api_link)
  627. self.assertEqual(response.status_code, 200)
  628. response_json = json_loads(response.content)
  629. self.assertEqual(len(response_json['results']), 0)
  630. self.access_all_categories()
  631. response = self.client.get(
  632. '%s?list=my&category=%s' % (self.api_link, self.category_a.pk))
  633. response_json = json_loads(response.content)
  634. self.assertEqual(len(response_json['results']), 0)
  635. def test_list_renders_test_thread(self):
  636. """list renders only threads posted by user"""
  637. test_thread = testutils.post_thread(
  638. category=self.category_a,
  639. poster=self.user,
  640. )
  641. other_thread = testutils.post_thread(
  642. category=self.category_a,
  643. )
  644. self.access_all_categories()
  645. response = self.client.get('/my/')
  646. self.assertEqual(response.status_code, 200)
  647. self.assertIn(test_thread.get_absolute_url(), response.content)
  648. self.assertNotIn(other_thread.get_absolute_url(), response.content)
  649. self.access_all_categories()
  650. response = self.client.get(self.category_a.get_absolute_url() + 'my/')
  651. self.assertEqual(response.status_code, 200)
  652. self.assertIn(test_thread.get_absolute_url(), response.content)
  653. self.assertNotIn(other_thread.get_absolute_url(), response.content)
  654. # test api
  655. self.access_all_categories()
  656. response = self.client.get('%s?list=my' % self.api_link)
  657. self.assertEqual(response.status_code, 200)
  658. response_json = json_loads(response.content)
  659. self.assertEqual(len(response_json['results']), 1)
  660. self.assertEqual(response_json['results'][0]['id'], test_thread.pk)
  661. self.access_all_categories()
  662. response = self.client.get(
  663. '%s?list=my&category=%s' % (self.api_link, self.category_a.pk))
  664. self.assertEqual(response.status_code, 200)
  665. response_json = json_loads(response.content)
  666. self.assertEqual(len(response_json['results']), 1)
  667. self.assertEqual(response_json['results'][0]['id'], test_thread.pk)
  668. class NewThreadsListTests(ThreadsListTestCase):
  669. def test_list_renders_empty(self):
  670. """list renders empty"""
  671. self.access_all_categories()
  672. response = self.client.get('/new/')
  673. self.assertEqual(response.status_code, 200)
  674. self.assertIn("empty-message", response.content)
  675. self.access_all_categories()
  676. response = self.client.get(self.category_a.get_absolute_url() + 'new/')
  677. self.assertEqual(response.status_code, 200)
  678. self.assertIn("empty-message", response.content)
  679. # test api
  680. self.access_all_categories()
  681. response = self.client.get('%s?list=new' % self.api_link)
  682. self.assertEqual(response.status_code, 200)
  683. response_json = json_loads(response.content)
  684. self.assertEqual(len(response_json['results']), 0)
  685. self.access_all_categories()
  686. response = self.client.get(
  687. '%s?list=new&category=%s' % (self.api_link, self.category_a.pk))
  688. response_json = json_loads(response.content)
  689. self.assertEqual(len(response_json['results']), 0)
  690. def test_list_renders_new_thread(self):
  691. """list renders new thread"""
  692. test_thread = testutils.post_thread(
  693. category=self.category_a,
  694. )
  695. self.access_all_categories()
  696. response = self.client.get('/new/')
  697. self.assertEqual(response.status_code, 200)
  698. self.assertIn(test_thread.get_absolute_url(), response.content)
  699. self.access_all_categories()
  700. response = self.client.get(self.category_a.get_absolute_url() + 'new/')
  701. self.assertEqual(response.status_code, 200)
  702. self.assertIn(test_thread.get_absolute_url(), response.content)
  703. # test api
  704. self.access_all_categories()
  705. response = self.client.get('%s?list=new' % self.api_link)
  706. self.assertEqual(response.status_code, 200)
  707. response_json = json_loads(response.content)
  708. self.assertEqual(len(response_json['results']), 1)
  709. self.assertEqual(response_json['results'][0]['id'], test_thread.pk)
  710. self.access_all_categories()
  711. response = self.client.get(
  712. '%s?list=new&category=%s' % (self.api_link, self.category_a.pk))
  713. self.assertEqual(response.status_code, 200)
  714. response_json = json_loads(response.content)
  715. self.assertEqual(len(response_json['results']), 1)
  716. self.assertEqual(response_json['results'][0]['id'], test_thread.pk)
  717. def test_list_renders_thread_bumped_after_user_cutoff(self):
  718. """list renders new thread bumped after user cutoff"""
  719. self.user.joined_on = timezone.now() - timedelta(days=10)
  720. self.user.save()
  721. test_thread = testutils.post_thread(
  722. category=self.category_a,
  723. started_on=self.user.joined_on - timedelta(days=2)
  724. )
  725. testutils.reply_thread(test_thread,
  726. posted_on=self.user.joined_on + timedelta(days=4)
  727. )
  728. self.access_all_categories()
  729. response = self.client.get('/new/')
  730. self.assertEqual(response.status_code, 200)
  731. self.assertIn(test_thread.get_absolute_url(), response.content)
  732. self.access_all_categories()
  733. response = self.client.get(
  734. self.category_a.get_absolute_url() + 'new/')
  735. self.assertEqual(response.status_code, 200)
  736. self.assertIn(test_thread.get_absolute_url(), response.content)
  737. # test api
  738. self.access_all_categories()
  739. response = self.client.get('%s?list=new' % self.api_link)
  740. self.assertEqual(response.status_code, 200)
  741. response_json = json_loads(response.content)
  742. self.assertEqual(len(response_json['results']), 1)
  743. self.assertEqual(response_json['results'][0]['id'], test_thread.pk)
  744. self.access_all_categories()
  745. response = self.client.get(
  746. '%s?list=new&category=%s' % (self.api_link, self.category_a.pk))
  747. self.assertEqual(response.status_code, 200)
  748. response_json = json_loads(response.content)
  749. self.assertEqual(len(response_json['results']), 1)
  750. self.assertEqual(response_json['results'][0]['id'], test_thread.pk)
  751. def test_list_hides_global_cutoff_thread(self):
  752. """list hides thread started before global cutoff"""
  753. self.user.joined_on = timezone.now() - timedelta(days=10)
  754. self.user.save()
  755. test_thread = testutils.post_thread(
  756. category=self.category_a,
  757. started_on=timezone.now() - timedelta(
  758. days=settings.MISAGO_FRESH_CONTENT_PERIOD + 1
  759. )
  760. )
  761. self.access_all_categories()
  762. response = self.client.get('/new/')
  763. self.assertEqual(response.status_code, 200)
  764. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  765. self.access_all_categories()
  766. response = self.client.get(self.category_a.get_absolute_url() + 'new/')
  767. self.assertEqual(response.status_code, 200)
  768. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  769. # test api
  770. self.access_all_categories()
  771. response = self.client.get('%s?list=new' % self.api_link)
  772. self.assertEqual(response.status_code, 200)
  773. response_json = json_loads(response.content)
  774. self.assertEqual(len(response_json['results']), 0)
  775. self.access_all_categories()
  776. response = self.client.get(
  777. '%s?list=new&category=%s' % (self.api_link, self.category_a.pk))
  778. self.assertEqual(response.status_code, 200)
  779. response_json = json_loads(response.content)
  780. self.assertEqual(len(response_json['results']), 0)
  781. def test_list_hides_user_cutoff_thread(self):
  782. """list hides thread started before users cutoff"""
  783. self.user.joined_on = timezone.now() - timedelta(days=5)
  784. self.user.save()
  785. test_thread = testutils.post_thread(
  786. category=self.category_a,
  787. started_on=self.user.joined_on - timedelta(minutes=1)
  788. )
  789. self.access_all_categories()
  790. response = self.client.get('/new/')
  791. self.assertEqual(response.status_code, 200)
  792. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  793. self.access_all_categories()
  794. response = self.client.get(self.category_a.get_absolute_url() + 'new/')
  795. self.assertEqual(response.status_code, 200)
  796. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  797. # test api
  798. self.access_all_categories()
  799. response = self.client.get('%s?list=new' % self.api_link)
  800. self.assertEqual(response.status_code, 200)
  801. response_json = json_loads(response.content)
  802. self.assertEqual(len(response_json['results']), 0)
  803. self.access_all_categories()
  804. response = self.client.get(
  805. '%s?list=new&category=%s' % (self.api_link, self.category_a.pk))
  806. self.assertEqual(response.status_code, 200)
  807. response_json = json_loads(response.content)
  808. self.assertEqual(len(response_json['results']), 0)
  809. def test_list_hides_user_read_thread(self):
  810. """list hides thread already read by user"""
  811. self.user.joined_on = timezone.now() - timedelta(days=5)
  812. self.user.save()
  813. test_thread = testutils.post_thread(
  814. category=self.category_a
  815. )
  816. threadstracker.make_thread_read_aware(self.user, test_thread)
  817. threadstracker.read_thread(
  818. self.user, test_thread, test_thread.last_post)
  819. self.access_all_categories()
  820. response = self.client.get('/new/')
  821. self.assertEqual(response.status_code, 200)
  822. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  823. self.access_all_categories()
  824. response = self.client.get(self.category_a.get_absolute_url() + 'new/')
  825. self.assertEqual(response.status_code, 200)
  826. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  827. # test api
  828. self.access_all_categories()
  829. response = self.client.get('%s?list=new' % self.api_link)
  830. self.assertEqual(response.status_code, 200)
  831. response_json = json_loads(response.content)
  832. self.assertEqual(len(response_json['results']), 0)
  833. self.access_all_categories()
  834. response = self.client.get(
  835. '%s?list=new&category=%s' % (self.api_link, self.category_a.pk))
  836. self.assertEqual(response.status_code, 200)
  837. response_json = json_loads(response.content)
  838. self.assertEqual(len(response_json['results']), 0)
  839. def test_list_hides_category_read_thread(self):
  840. """list hides thread already read by user"""
  841. self.user.joined_on = timezone.now() - timedelta(days=5)
  842. self.user.save()
  843. test_thread = testutils.post_thread(
  844. category=self.category_a
  845. )
  846. self.user.categoryread_set.create(
  847. category=self.category_a,
  848. last_read_on=timezone.now(),
  849. )
  850. self.access_all_categories()
  851. response = self.client.get('/new/')
  852. self.assertEqual(response.status_code, 200)
  853. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  854. self.access_all_categories()
  855. response = self.client.get(self.category_a.get_absolute_url() + 'new/')
  856. self.assertEqual(response.status_code, 200)
  857. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  858. # test api
  859. self.access_all_categories()
  860. response = self.client.get('%s?list=new' % self.api_link)
  861. self.assertEqual(response.status_code, 200)
  862. response_json = json_loads(response.content)
  863. self.assertEqual(len(response_json['results']), 0)
  864. self.access_all_categories()
  865. response = self.client.get(
  866. '%s?list=new&category=%s' % (self.api_link, self.category_a.pk))
  867. self.assertEqual(response.status_code, 200)
  868. response_json = json_loads(response.content)
  869. self.assertEqual(len(response_json['results']), 0)
  870. class UnreadThreadsListTests(ThreadsListTestCase):
  871. def test_list_renders_empty(self):
  872. """list renders empty"""
  873. self.access_all_categories()
  874. response = self.client.get('/unread/')
  875. self.assertEqual(response.status_code, 200)
  876. self.assertIn("empty-message", response.content)
  877. self.access_all_categories()
  878. response = self.client.get(
  879. self.category_a.get_absolute_url() + 'unread/')
  880. self.assertEqual(response.status_code, 200)
  881. self.assertIn("empty-message", response.content)
  882. # test api
  883. self.access_all_categories()
  884. response = self.client.get('%s?list=unread' % self.api_link)
  885. self.assertEqual(response.status_code, 200)
  886. response_json = json_loads(response.content)
  887. self.assertEqual(len(response_json['results']), 0)
  888. self.access_all_categories()
  889. response = self.client.get(
  890. '%s?list=unread&category=%s' % (self.api_link, self.category_a.pk))
  891. self.assertEqual(response.status_code, 200)
  892. response_json = json_loads(response.content)
  893. self.assertEqual(len(response_json['results']), 0)
  894. def test_list_renders_unread_thread(self):
  895. """list renders thread with unread posts"""
  896. self.user.joined_on = timezone.now() - timedelta(days=5)
  897. self.user.save()
  898. test_thread = testutils.post_thread(
  899. category=self.category_a
  900. )
  901. threadstracker.make_thread_read_aware(self.user, test_thread)
  902. threadstracker.read_thread(
  903. self.user, test_thread, test_thread.last_post)
  904. testutils.reply_thread(test_thread)
  905. self.access_all_categories()
  906. response = self.client.get('/unread/')
  907. self.assertEqual(response.status_code, 200)
  908. self.assertIn(test_thread.get_absolute_url(), response.content)
  909. self.access_all_categories()
  910. response = self.client.get(
  911. self.category_a.get_absolute_url() + 'unread/')
  912. self.assertEqual(response.status_code, 200)
  913. self.assertIn(test_thread.get_absolute_url(), response.content)
  914. # test api
  915. self.access_all_categories()
  916. response = self.client.get('%s?list=unread' % self.api_link)
  917. self.assertEqual(response.status_code, 200)
  918. response_json = json_loads(response.content)
  919. self.assertEqual(len(response_json['results']), 1)
  920. self.assertEqual(response_json['results'][0]['id'], test_thread.pk)
  921. self.access_all_categories()
  922. response = self.client.get(
  923. '%s?list=unread&category=%s' % (self.api_link, self.category_a.pk))
  924. self.assertEqual(response.status_code, 200)
  925. response_json = json_loads(response.content)
  926. self.assertEqual(len(response_json['results']), 1)
  927. self.assertEqual(response_json['results'][0]['id'], test_thread.pk)
  928. def test_list_hides_never_read_thread(self):
  929. """list hides never read thread"""
  930. self.user.joined_on = timezone.now() - timedelta(days=5)
  931. self.user.save()
  932. test_thread = testutils.post_thread(
  933. category=self.category_a
  934. )
  935. self.access_all_categories()
  936. response = self.client.get('/unread/')
  937. self.assertEqual(response.status_code, 200)
  938. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  939. self.access_all_categories()
  940. response = self.client.get(
  941. self.category_a.get_absolute_url() + 'unread/')
  942. self.assertEqual(response.status_code, 200)
  943. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  944. # test api
  945. self.access_all_categories()
  946. response = self.client.get('%s?list=unread' % self.api_link)
  947. self.assertEqual(response.status_code, 200)
  948. response_json = json_loads(response.content)
  949. self.assertEqual(len(response_json['results']), 0)
  950. self.access_all_categories()
  951. response = self.client.get(
  952. '%s?list=unread&category=%s' % (self.api_link, self.category_a.pk))
  953. self.assertEqual(response.status_code, 200)
  954. response_json = json_loads(response.content)
  955. self.assertEqual(len(response_json['results']), 0)
  956. def test_list_hides_read_thread(self):
  957. """list hides read thread"""
  958. self.user.joined_on = timezone.now() - timedelta(days=5)
  959. self.user.save()
  960. test_thread = testutils.post_thread(
  961. category=self.category_a
  962. )
  963. threadstracker.make_thread_read_aware(self.user, test_thread)
  964. threadstracker.read_thread(
  965. self.user, test_thread, test_thread.last_post)
  966. self.access_all_categories()
  967. response = self.client.get('/unread/')
  968. self.assertEqual(response.status_code, 200)
  969. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  970. self.access_all_categories()
  971. response = self.client.get(
  972. self.category_a.get_absolute_url() + 'unread/')
  973. self.assertEqual(response.status_code, 200)
  974. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  975. # test api
  976. self.access_all_categories()
  977. response = self.client.get('%s?list=unread' % self.api_link)
  978. self.assertEqual(response.status_code, 200)
  979. response_json = json_loads(response.content)
  980. self.assertEqual(len(response_json['results']), 0)
  981. self.access_all_categories()
  982. response = self.client.get(
  983. '%s?list=unread&category=%s' % (self.api_link, self.category_a.pk))
  984. self.assertEqual(response.status_code, 200)
  985. response_json = json_loads(response.content)
  986. self.assertEqual(len(response_json['results']), 0)
  987. def test_list_hides_global_cutoff_thread(self):
  988. """list hides thread replied before global cutoff"""
  989. self.user.joined_on = timezone.now() - timedelta(days=10)
  990. self.user.save()
  991. test_thread = testutils.post_thread(
  992. category=self.category_a,
  993. started_on=timezone.now() - timedelta(
  994. days=settings.MISAGO_FRESH_CONTENT_PERIOD + 5
  995. )
  996. )
  997. threadstracker.make_thread_read_aware(self.user, test_thread)
  998. threadstracker.read_thread(
  999. self.user, test_thread, test_thread.last_post)
  1000. testutils.reply_thread(test_thread,
  1001. posted_on=test_thread.started_on + timedelta(days=1)
  1002. )
  1003. self.access_all_categories()
  1004. response = self.client.get('/unread/')
  1005. self.assertEqual(response.status_code, 200)
  1006. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  1007. self.access_all_categories()
  1008. response = self.client.get(
  1009. self.category_a.get_absolute_url() + 'unread/')
  1010. self.assertEqual(response.status_code, 200)
  1011. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  1012. # test api
  1013. self.access_all_categories()
  1014. response = self.client.get('%s?list=unread' % self.api_link)
  1015. self.assertEqual(response.status_code, 200)
  1016. response_json = json_loads(response.content)
  1017. self.assertEqual(len(response_json['results']), 0)
  1018. self.access_all_categories()
  1019. response = self.client.get(
  1020. '%s?list=unread&category=%s' % (self.api_link, self.category_a.pk))
  1021. self.assertEqual(response.status_code, 200)
  1022. response_json = json_loads(response.content)
  1023. self.assertEqual(len(response_json['results']), 0)
  1024. def test_list_hides_user_cutoff_thread(self):
  1025. """list hides thread replied before user cutoff"""
  1026. self.user.joined_on = timezone.now() - timedelta(days=10)
  1027. self.user.save()
  1028. test_thread = testutils.post_thread(
  1029. category=self.category_a,
  1030. started_on=self.user.joined_on - timedelta(days=2)
  1031. )
  1032. threadstracker.make_thread_read_aware(self.user, test_thread)
  1033. threadstracker.read_thread(
  1034. self.user, test_thread, test_thread.last_post)
  1035. testutils.reply_thread(test_thread,
  1036. posted_on=test_thread.started_on + timedelta(days=1)
  1037. )
  1038. self.access_all_categories()
  1039. response = self.client.get('/unread/')
  1040. self.assertEqual(response.status_code, 200)
  1041. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  1042. self.access_all_categories()
  1043. response = self.client.get(
  1044. self.category_a.get_absolute_url() + 'unread/')
  1045. self.assertEqual(response.status_code, 200)
  1046. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  1047. # test api
  1048. self.access_all_categories()
  1049. response = self.client.get('%s?list=unread' % self.api_link)
  1050. self.assertEqual(response.status_code, 200)
  1051. response_json = json_loads(response.content)
  1052. self.assertEqual(len(response_json['results']), 0)
  1053. self.access_all_categories()
  1054. response = self.client.get(
  1055. '%s?list=unread&category=%s' % (self.api_link, self.category_a.pk))
  1056. self.assertEqual(response.status_code, 200)
  1057. response_json = json_loads(response.content)
  1058. self.assertEqual(len(response_json['results']), 0)
  1059. def test_list_hides_category_cutoff_thread(self):
  1060. """list hides thread replied before category cutoff"""
  1061. self.user.joined_on = timezone.now() - timedelta(days=10)
  1062. self.user.save()
  1063. test_thread = testutils.post_thread(
  1064. category=self.category_a,
  1065. started_on=self.user.joined_on - timedelta(days=2)
  1066. )
  1067. threadstracker.make_thread_read_aware(self.user, test_thread)
  1068. threadstracker.read_thread(
  1069. self.user, test_thread, test_thread.last_post)
  1070. testutils.reply_thread(test_thread)
  1071. self.user.categoryread_set.create(
  1072. category=self.category_a,
  1073. last_read_on=timezone.now(),
  1074. )
  1075. self.access_all_categories()
  1076. response = self.client.get('/unread/')
  1077. self.assertEqual(response.status_code, 200)
  1078. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  1079. self.access_all_categories()
  1080. response = self.client.get(
  1081. self.category_a.get_absolute_url() + 'unread/')
  1082. self.assertEqual(response.status_code, 200)
  1083. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  1084. # test api
  1085. self.access_all_categories()
  1086. response = self.client.get('%s?list=unread' % self.api_link)
  1087. self.assertEqual(response.status_code, 200)
  1088. response_json = json_loads(response.content)
  1089. self.assertEqual(len(response_json['results']), 0)
  1090. self.access_all_categories()
  1091. response = self.client.get(
  1092. '%s?list=unread&category=%s' % (self.api_link, self.category_a.pk))
  1093. self.assertEqual(response.status_code, 200)
  1094. response_json = json_loads(response.content)
  1095. self.assertEqual(len(response_json['results']), 0)
  1096. class SubscribedThreadsListTests(ThreadsListTestCase):
  1097. def test_list_shows_subscribed_thread(self):
  1098. """list shows subscribed thread"""
  1099. test_thread = testutils.post_thread(category=self.category_a)
  1100. self.user.subscription_set.create(
  1101. thread=test_thread,
  1102. category=self.category_a,
  1103. last_read_on=test_thread.last_post_on,
  1104. )
  1105. self.access_all_categories()
  1106. response = self.client.get('/subscribed/')
  1107. self.assertEqual(response.status_code, 200)
  1108. self.assertIn(test_thread.get_absolute_url(), response.content)
  1109. self.access_all_categories()
  1110. response = self.client.get(
  1111. self.category_a.get_absolute_url() + 'subscribed/')
  1112. self.assertEqual(response.status_code, 200)
  1113. self.assertIn(test_thread.get_absolute_url(), response.content)
  1114. # test api
  1115. self.access_all_categories()
  1116. response = self.client.get('%s?list=subscribed' % self.api_link)
  1117. self.assertEqual(response.status_code, 200)
  1118. response_json = json_loads(response.content)
  1119. self.assertEqual(len(response_json['results']), 1)
  1120. self.assertIn(test_thread.get_absolute_url(), response.content)
  1121. self.access_all_categories()
  1122. response = self.client.get(
  1123. '%s?list=subscribed&category=%s' % (
  1124. self.api_link, self.category_a.pk
  1125. ))
  1126. self.assertEqual(response.status_code, 200)
  1127. response_json = json_loads(response.content)
  1128. self.assertEqual(len(response_json['results']), 1)
  1129. self.assertIn(test_thread.get_absolute_url(), response.content)
  1130. def test_list_hides_unsubscribed_thread(self):
  1131. """list shows subscribed thread"""
  1132. test_thread = testutils.post_thread(category=self.category_a)
  1133. self.access_all_categories()
  1134. response = self.client.get('/subscribed/')
  1135. self.assertEqual(response.status_code, 200)
  1136. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  1137. self.access_all_categories()
  1138. response = self.client.get(
  1139. self.category_a.get_absolute_url() + 'subscribed/')
  1140. self.assertEqual(response.status_code, 200)
  1141. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  1142. # test api
  1143. self.access_all_categories()
  1144. response = self.client.get('%s?list=subscribed' % self.api_link)
  1145. self.assertEqual(response.status_code, 200)
  1146. response_json = json_loads(response.content)
  1147. self.assertEqual(len(response_json['results']), 0)
  1148. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  1149. self.access_all_categories()
  1150. response = self.client.get(
  1151. '%s?list=subscribed&category=%s' % (
  1152. self.api_link, self.category_a.pk
  1153. ))
  1154. self.assertEqual(response.status_code, 200)
  1155. response_json = json_loads(response.content)
  1156. self.assertEqual(len(response_json['results']), 0)
  1157. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  1158. class UnapprovedListTests(ThreadsListTestCase):
  1159. def test_list_errors_without_permission(self):
  1160. """list errors if user has no permission to access it"""
  1161. TEST_URLS = (
  1162. '/unapproved/',
  1163. self.category_a.get_absolute_url() + 'unapproved/',
  1164. '%s?list=unapproved' % self.api_link,
  1165. )
  1166. for test_url in TEST_URLS:
  1167. self.access_all_categories()
  1168. response = self.client.get(test_url)
  1169. self.assertEqual(response.status_code, 403)
  1170. # approval perm has no influence on visibility
  1171. for test_url in TEST_URLS:
  1172. self.access_all_categories({
  1173. 'can_approve_content': True
  1174. })
  1175. self.access_all_categories()
  1176. response = self.client.get(test_url)
  1177. self.assertEqual(response.status_code, 403)
  1178. # approval perm has no influence on visibility
  1179. for test_url in TEST_URLS:
  1180. self.access_all_categories(base_acl={
  1181. 'can_see_unapproved_content_lists': True
  1182. })
  1183. self.access_all_categories()
  1184. response = self.client.get(test_url)
  1185. self.assertEqual(response.status_code, 200)
  1186. def test_list_shows_all_threads_for_approving_user(self):
  1187. """list shows all threads with unapproved posts when user has perm"""
  1188. visible_thread = testutils.post_thread(
  1189. category=self.category_b,
  1190. is_unapproved=True,
  1191. )
  1192. hidden_thread = testutils.post_thread(
  1193. category=self.category_b,
  1194. is_unapproved=False,
  1195. )
  1196. self.access_all_categories({
  1197. 'can_approve_content': True
  1198. }, {
  1199. 'can_see_unapproved_content_lists': True
  1200. })
  1201. response = self.client.get('/unapproved/')
  1202. self.assertEqual(response.status_code, 200)
  1203. self.assertIn(visible_thread.get_absolute_url(), response.content)
  1204. self.assertNotIn(hidden_thread.get_absolute_url(), response.content)
  1205. self.access_all_categories({
  1206. 'can_approve_content': True
  1207. }, {
  1208. 'can_see_unapproved_content_lists': True
  1209. })
  1210. response = self.client.get(
  1211. self.category_a.get_absolute_url() + 'unapproved/')
  1212. self.assertEqual(response.status_code, 200)
  1213. self.assertIn(visible_thread.get_absolute_url(), response.content)
  1214. self.assertNotIn(hidden_thread.get_absolute_url(), response.content)
  1215. # test api
  1216. self.access_all_categories({
  1217. 'can_approve_content': True
  1218. }, {
  1219. 'can_see_unapproved_content_lists': True
  1220. })
  1221. response = self.client.get('%s?list=unapproved' % self.api_link)
  1222. self.assertEqual(response.status_code, 200)
  1223. self.assertIn(visible_thread.get_absolute_url(), response.content)
  1224. self.assertNotIn(hidden_thread.get_absolute_url(), response.content)
  1225. def test_list_shows_owned_threads_for_unapproving_user(self):
  1226. """
  1227. list shows owned threads with unapproved posts for user without perm
  1228. """
  1229. visible_thread = testutils.post_thread(
  1230. poster=self.user,
  1231. category=self.category_b,
  1232. is_unapproved=True,
  1233. )
  1234. hidden_thread = testutils.post_thread(
  1235. category=self.category_b,
  1236. is_unapproved=True,
  1237. )
  1238. self.access_all_categories(base_acl={
  1239. 'can_see_unapproved_content_lists': True
  1240. })
  1241. response = self.client.get('/unapproved/')
  1242. self.assertEqual(response.status_code, 200)
  1243. self.assertIn(visible_thread.get_absolute_url(), response.content)
  1244. self.assertNotIn(hidden_thread.get_absolute_url(), response.content)
  1245. self.access_all_categories(base_acl={
  1246. 'can_see_unapproved_content_lists': True
  1247. })
  1248. response = self.client.get(
  1249. self.category_a.get_absolute_url() + 'unapproved/')
  1250. self.assertEqual(response.status_code, 200)
  1251. self.assertIn(visible_thread.get_absolute_url(), response.content)
  1252. self.assertNotIn(hidden_thread.get_absolute_url(), response.content)
  1253. # test api
  1254. self.access_all_categories(base_acl={
  1255. 'can_see_unapproved_content_lists': True
  1256. })
  1257. response = self.client.get('%s?list=unapproved' % self.api_link)
  1258. self.assertEqual(response.status_code, 200)
  1259. self.assertIn(visible_thread.get_absolute_url(), response.content)
  1260. self.assertNotIn(hidden_thread.get_absolute_url(), response.content)