test_threadslists.py 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338
  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. cache.clear()
  24. threadstore.clear()
  25. self.root = Category.objects.root_category()
  26. self.first_category = Category.objects.get(slug='first-category')
  27. """
  28. Create categories tree for test cases:
  29. First category (created by migration)
  30. Category A
  31. + Category B
  32. + Subcategory C
  33. + Subcategory D
  34. Category E
  35. + Subcategory F
  36. """
  37. Category(
  38. name='Category A',
  39. slug='category-a',
  40. css_class='showing-category-a',
  41. ).insert_at(self.root, position='last-child', save=True)
  42. Category(
  43. name='Category E',
  44. slug='category-e',
  45. css_class='showing-category-e',
  46. ).insert_at(self.root, position='last-child', save=True)
  47. self.root = Category.objects.root_category()
  48. self.category_a = Category.objects.get(slug='category-a')
  49. Category(
  50. name='Category B',
  51. slug='category-b',
  52. css_class='showing-category-b',
  53. ).insert_at(self.category_a, position='last-child', save=True)
  54. self.category_b = Category.objects.get(slug='category-b')
  55. Category(
  56. name='Category C',
  57. slug='category-c',
  58. css_class='showing-category-c',
  59. ).insert_at(self.category_b, position='last-child', save=True)
  60. Category(
  61. name='Category D',
  62. slug='category-d',
  63. css_class='showing-category-d',
  64. ).insert_at(self.category_b, position='last-child', save=True)
  65. self.category_c = Category.objects.get(slug='category-c')
  66. self.category_d = Category.objects.get(slug='category-d')
  67. self.category_e = Category.objects.get(slug='category-e')
  68. Category(
  69. name='Category F',
  70. slug='category-f',
  71. css_class='showing-category-f',
  72. ).insert_at(self.category_e, position='last-child', save=True)
  73. self.category_f = Category.objects.get(slug='category-f')
  74. self.access_all_categories()
  75. def access_all_categories(self, extra=None):
  76. cache.clear()
  77. threadstore.clear()
  78. categories_acl = {'categories': {}, 'visible_categories': []}
  79. for category in Category.objects.all_categories():
  80. categories_acl['visible_categories'].append(category.pk)
  81. categories_acl['categories'][category.pk] = {
  82. 'can_see': 1,
  83. 'can_browse': 1,
  84. 'can_see_all_threads': 1,
  85. 'can_see_own_threads': 0,
  86. 'can_hide_threads': 0,
  87. 'can_review_moderated_content': 0,
  88. }
  89. if extra:
  90. categories_acl['categories'][category.pk].update(extra)
  91. override_acl(self.user, categories_acl)
  92. return categories_acl
  93. class ListsTests(ThreadsListTestCase):
  94. def test_list_renders_empty(self):
  95. """empty threads list renders"""
  96. for url in LISTS_URLS:
  97. self.access_all_categories()
  98. response = self.client.get('/' + url)
  99. self.assertEqual(response.status_code, 200)
  100. self.assertIn("empty-message", response.content)
  101. self.access_all_categories()
  102. response = self.client.get(self.category_b.get_absolute_url() + url)
  103. self.assertEqual(response.status_code, 200)
  104. self.assertIn(self.category_b.name, response.content)
  105. self.assertIn("empty-message", response.content)
  106. self.access_all_categories()
  107. response = self.client.get(
  108. '%s?list=%s' % (self.api_link, url.strip('/')))
  109. self.assertEqual(response.status_code, 200)
  110. response_json = json_loads(response.content)
  111. self.assertEqual(len(response_json['results']), 0)
  112. def test_list_authenticated_only_views(self):
  113. """authenticated only views return 403 for guests"""
  114. for url in LISTS_URLS:
  115. self.access_all_categories()
  116. response = self.client.get('/' + url)
  117. self.assertEqual(response.status_code, 200)
  118. self.access_all_categories()
  119. response = self.client.get(self.category_b.get_absolute_url() + url)
  120. self.assertEqual(response.status_code, 200)
  121. self.assertIn(self.category_b.name, response.content)
  122. self.access_all_categories()
  123. self.access_all_categories()
  124. response = self.client.get('%s?category=%s&list=%s' % (
  125. self.api_link,
  126. self.category_b.pk,
  127. url.strip('/'),
  128. ))
  129. self.assertEqual(response.status_code, 200)
  130. self.logout_user()
  131. self.user = self.get_anonymous_user()
  132. for url in LISTS_URLS[1:]:
  133. self.access_all_categories()
  134. response = self.client.get('/' + url)
  135. self.assertEqual(response.status_code, 403)
  136. self.access_all_categories()
  137. response = self.client.get(self.category_b.get_absolute_url() + url)
  138. self.assertEqual(response.status_code, 403)
  139. self.access_all_categories()
  140. response = self.client.get('%s?category=%s&list=%s' % (
  141. self.api_link,
  142. self.category_b.pk,
  143. url.strip('/'),
  144. ))
  145. self.assertEqual(response.status_code, 403)
  146. def test_empty_list_hides_categories_picker(self):
  147. """categories picker is hidden on empty list"""
  148. Category(
  149. name='Hidden Category',
  150. slug='hidden-category',
  151. ).insert_at(self.root, position='last-child', save=True)
  152. test_category = Category.objects.get(slug='hidden-category')
  153. self.access_all_categories()
  154. response = self.client.get('/')
  155. self.assertEqual(response.status_code, 200)
  156. self.assertNotIn(
  157. 'subcategory-%s' % self.category_a.css_class, response.content)
  158. self.assertNotIn(
  159. 'subcategory-%s' % self.category_e.css_class, response.content)
  160. self.access_all_categories()
  161. response = self.client.get(self.category_a.get_absolute_url())
  162. self.assertEqual(response.status_code, 200)
  163. self.assertNotIn(
  164. 'subcategory-%s' % self.category_b.css_class, response.content)
  165. self.access_all_categories()
  166. response = self.client.get(self.api_link)
  167. self.assertEqual(response.status_code, 200)
  168. response_json = json_loads(response.content)
  169. self.assertEqual(len(response_json['subcategories']), 0)
  170. def test_list_renders_categories_picker(self):
  171. """categories picker renders valid categories"""
  172. Category(
  173. name='Hidden Category',
  174. slug='hidden-category',
  175. ).insert_at(self.root, position='last-child', save=True)
  176. test_category = Category.objects.get(slug='hidden-category')
  177. testutils.post_thread(
  178. category=self.category_b,
  179. )
  180. response = self.client.get('/')
  181. self.assertEqual(response.status_code, 200)
  182. self.assertIn(
  183. 'subcategory-%s' % self.category_a.css_class, response.content)
  184. # readable categories, but non-accessible directly
  185. self.assertNotIn(
  186. 'subcategory-%s' % self.category_b.css_class, response.content)
  187. self.assertNotIn(
  188. 'subcategory-%s' % self.category_c.css_class, response.content)
  189. self.assertNotIn(
  190. 'subcategory-%s' % self.category_d.css_class, response.content)
  191. self.assertNotIn(
  192. 'subcategory-%s' % self.category_f.css_class, response.content)
  193. # hidden category
  194. self.assertNotIn(
  195. 'subcategory-%s' % test_category.css_class, response.content)
  196. self.access_all_categories()
  197. response = self.client.get(self.api_link)
  198. self.assertEqual(response.status_code, 200)
  199. response_json = json_loads(response.content)
  200. self.assertEqual(
  201. response_json['subcategories'][0], self.category_a.pk)
  202. # test category view
  203. self.access_all_categories()
  204. response = self.client.get(self.category_a.get_absolute_url())
  205. self.assertEqual(response.status_code, 200)
  206. self.assertIn(
  207. 'subcategory-%s' % self.category_b.css_class, response.content)
  208. # readable categories, but non-accessible directly
  209. self.assertNotIn(
  210. 'subcategory-%s' % self.category_c.css_class, response.content)
  211. self.assertNotIn(
  212. 'subcategory-%s' % self.category_d.css_class, response.content)
  213. self.assertNotIn(
  214. 'subcategory-%s' % self.category_f.css_class, response.content)
  215. self.access_all_categories()
  216. response = self.client.get(
  217. '%s?category=%s' % (self.api_link, self.category_a.pk))
  218. self.assertEqual(response.status_code, 200)
  219. response_json = json_loads(response.content)
  220. self.assertEqual(
  221. response_json['subcategories'][0], self.category_b.pk)
  222. class CategoryThreadsListTests(ThreadsListTestCase):
  223. def test_access_hidden_category(self):
  224. """hidden category returns 404"""
  225. Category(
  226. name='Hidden Category',
  227. slug='hidden-category',
  228. ).insert_at(self.root, position='last-child', save=True)
  229. test_category = Category.objects.get(slug='hidden-category')
  230. for url in LISTS_URLS:
  231. response = self.client.get(test_category.get_absolute_url() + url)
  232. self.assertEqual(response.status_code, 404)
  233. response = self.client.get(
  234. '%s?category=%s' % (self.api_link, test_category.pk))
  235. self.assertEqual(response.status_code, 404)
  236. def test_access_protected_category(self):
  237. """protected category returns 403"""
  238. Category(
  239. name='Hidden Category',
  240. slug='hidden-category',
  241. ).insert_at(self.root, position='last-child', save=True)
  242. test_category = Category.objects.get(slug='hidden-category')
  243. for url in LISTS_URLS:
  244. override_acl(self.user, {
  245. 'visible_categories': [test_category.pk],
  246. 'categories': {
  247. test_category.pk: {
  248. 'can_see': 1,
  249. 'can_browse': 0,
  250. }
  251. }
  252. });
  253. response = self.client.get(test_category.get_absolute_url() + url)
  254. self.assertEqual(response.status_code, 403)
  255. override_acl(self.user, {
  256. 'visible_categories': [test_category.pk],
  257. 'categories': {
  258. test_category.pk: {
  259. 'can_see': 1,
  260. 'can_browse': 0,
  261. }
  262. }
  263. });
  264. response = self.client.get('%s?category=%s&list=%s' % (
  265. self.api_link,
  266. test_category.pk,
  267. url.strip('/'),
  268. ))
  269. self.assertEqual(response.status_code, 403)
  270. class ThreadsVisibilityTests(ThreadsListTestCase):
  271. def test_list_renders_test_thread(self):
  272. """list renders test thread with valid top category"""
  273. test_thread = testutils.post_thread(
  274. category=self.category_c,
  275. )
  276. response = self.client.get('/')
  277. self.assertEqual(response.status_code, 200)
  278. self.assertIn(test_thread.get_absolute_url(), response.content)
  279. self.assertIn(
  280. 'subcategory-%s' % self.category_a.css_class, response.content)
  281. self.assertIn(
  282. 'thread-category-%s' % self.category_a.css_class, response.content)
  283. self.assertIn(
  284. 'thread-category-%s' % self.category_c.css_class, response.content)
  285. # other top category is hidden from user
  286. self.assertNotIn(
  287. 'subcategory-%s' % self.category_e.css_class, response.content)
  288. # api displays same data
  289. self.access_all_categories()
  290. response = self.client.get(self.api_link)
  291. self.assertEqual(response.status_code, 200)
  292. response_json = json_loads(response.content)
  293. self.assertEqual(response_json['results'][0]['id'], test_thread.pk)
  294. self.assertEqual(len(response_json['subcategories']), 1)
  295. self.assertEqual(
  296. response_json['subcategories'][0], self.category_a.pk)
  297. # test category view
  298. self.access_all_categories()
  299. response = self.client.get(self.category_b.get_absolute_url())
  300. self.assertEqual(response.status_code, 200)
  301. # thread displays
  302. self.assertIn(test_thread.get_absolute_url(), response.content)
  303. self.assertNotIn(
  304. 'thread-category-%s' % self.category_b.css_class, response.content)
  305. self.assertIn(
  306. 'thread-category-%s' % self.category_c.css_class, response.content)
  307. # category picker was changed
  308. self.assertIn(
  309. 'subcategory-%s' % self.category_c.css_class, response.content)
  310. self.assertNotIn(
  311. 'subcategory-%s' % self.category_d.css_class, response.content)
  312. # api displays same data
  313. self.access_all_categories()
  314. response = self.client.get(
  315. '%s?category=%s' % (self.api_link, self.category_b.pk))
  316. self.assertEqual(response.status_code, 200)
  317. response_json = json_loads(response.content)
  318. self.assertEqual(response_json['results'][0]['id'], test_thread.pk)
  319. self.assertEqual(len(response_json['subcategories']), 1)
  320. self.assertEqual(
  321. response_json['subcategories'][0], self.category_c.pk)
  322. def test_list_hides_hidden_thread(self):
  323. """list renders empty due to no permission to see thread"""
  324. Category(
  325. name='Hidden Category',
  326. slug='hidden-category',
  327. ).insert_at(self.root, position='last-child', save=True)
  328. test_category = Category.objects.get(slug='hidden-category')
  329. test_thread = testutils.post_thread(
  330. category=test_category,
  331. )
  332. response = self.client.get('/')
  333. self.assertEqual(response.status_code, 200)
  334. self.assertIn("empty-message", response.content)
  335. def test_api_hides_hidden_thread(self):
  336. """api returns empty due to no permission to see thread"""
  337. Category(
  338. name='Hidden Category',
  339. slug='hidden-category',
  340. ).insert_at(self.root, position='last-child', save=True)
  341. test_category = Category.objects.get(slug='hidden-category')
  342. test_thread = testutils.post_thread(
  343. category=test_category,
  344. )
  345. response = self.client.get(self.api_link)
  346. self.assertEqual(response.status_code, 200)
  347. response_json = json_loads(response.content)
  348. self.assertEqual(len(response_json['results']), 0)
  349. def test_list_user_see_own_moderated_thread(self):
  350. """list renders moderated thread that belongs to viewer"""
  351. test_thread = testutils.post_thread(
  352. category=self.category_a,
  353. poster=self.user,
  354. is_moderated=True,
  355. )
  356. response = self.client.get('/')
  357. self.assertEqual(response.status_code, 200)
  358. self.assertIn(test_thread.get_absolute_url(), response.content)
  359. # test api
  360. self.access_all_categories()
  361. response = self.client.get(self.api_link)
  362. self.assertEqual(response.status_code, 200)
  363. response_json = json_loads(response.content)
  364. self.assertEqual(response_json['results'][0]['id'], test_thread.pk)
  365. def test_list_user_cant_see_moderated_thread(self):
  366. """list hides moderated thread that belongs to other user"""
  367. test_thread = testutils.post_thread(
  368. category=self.category_a,
  369. is_moderated=True,
  370. )
  371. response = self.client.get('/')
  372. self.assertEqual(response.status_code, 200)
  373. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  374. # test api
  375. self.access_all_categories()
  376. response = self.client.get(self.api_link)
  377. self.assertEqual(response.status_code, 200)
  378. response_json = json_loads(response.content)
  379. self.assertEqual(len(response_json['results']), 0)
  380. def test_list_user_cant_see_hidden_thread(self):
  381. """list hides hidden thread that belongs to other user"""
  382. test_thread = testutils.post_thread(
  383. category=self.category_a,
  384. is_hidden=True,
  385. )
  386. response = self.client.get('/')
  387. self.assertEqual(response.status_code, 200)
  388. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  389. # test api
  390. self.access_all_categories()
  391. response = self.client.get(self.api_link)
  392. self.assertEqual(response.status_code, 200)
  393. response_json = json_loads(response.content)
  394. self.assertEqual(len(response_json['results']), 0)
  395. def test_list_user_cant_see_own_hidden_thread(self):
  396. """list hides hidden thread that belongs to viewer"""
  397. test_thread = testutils.post_thread(
  398. category=self.category_a,
  399. poster=self.user,
  400. is_hidden=True,
  401. )
  402. response = self.client.get('/')
  403. self.assertEqual(response.status_code, 200)
  404. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  405. # test api
  406. self.access_all_categories()
  407. response = self.client.get(self.api_link)
  408. self.assertEqual(response.status_code, 200)
  409. response_json = json_loads(response.content)
  410. self.assertEqual(len(response_json['results']), 0)
  411. def test_list_user_can_see_own_hidden_thread(self):
  412. """list shows hidden thread that belongs to viewer due to permission"""
  413. test_thread = testutils.post_thread(
  414. category=self.category_a,
  415. poster=self.user,
  416. is_hidden=True,
  417. )
  418. self.access_all_categories({
  419. 'can_hide_threads': 1
  420. })
  421. response = self.client.get('/')
  422. self.assertEqual(response.status_code, 200)
  423. self.assertIn(test_thread.get_absolute_url(), response.content)
  424. # test api
  425. self.access_all_categories({
  426. 'can_hide_threads': 1
  427. })
  428. response = self.client.get(self.api_link)
  429. self.assertEqual(response.status_code, 200)
  430. response_json = json_loads(response.content)
  431. self.assertEqual(response_json['results'][0]['id'], test_thread.pk)
  432. def test_list_user_can_see_hidden_thread(self):
  433. """
  434. list shows hidden thread that belongs to other user due to permission
  435. """
  436. test_thread = testutils.post_thread(
  437. category=self.category_a,
  438. is_hidden=True,
  439. )
  440. self.access_all_categories({
  441. 'can_hide_threads': 1
  442. })
  443. response = self.client.get('/')
  444. self.assertEqual(response.status_code, 200)
  445. self.assertIn(test_thread.get_absolute_url(), response.content)
  446. # test api
  447. self.access_all_categories({
  448. 'can_hide_threads': 1
  449. })
  450. response = self.client.get(self.api_link)
  451. self.assertEqual(response.status_code, 200)
  452. response_json = json_loads(response.content)
  453. self.assertEqual(response_json['results'][0]['id'], test_thread.pk)
  454. def test_list_user_can_see_moderated_thread(self):
  455. """
  456. list shows hidden thread that belongs to other user due to permission
  457. """
  458. test_thread = testutils.post_thread(
  459. category=self.category_a,
  460. is_moderated=True,
  461. )
  462. self.access_all_categories({
  463. 'can_review_moderated_content': 1
  464. })
  465. response = self.client.get('/')
  466. self.assertEqual(response.status_code, 200)
  467. self.assertIn(test_thread.get_absolute_url(), response.content)
  468. # test api
  469. self.access_all_categories({
  470. 'can_review_moderated_content': 1
  471. })
  472. response = self.client.get(self.api_link)
  473. self.assertEqual(response.status_code, 200)
  474. response_json = json_loads(response.content)
  475. self.assertEqual(response_json['results'][0]['id'], test_thread.pk)
  476. class MyThreadsListTests(ThreadsListTestCase):
  477. def test_list_renders_empty(self):
  478. """list renders empty"""
  479. self.access_all_categories()
  480. response = self.client.get('/my/')
  481. self.assertEqual(response.status_code, 200)
  482. self.assertIn("empty-message", response.content)
  483. self.access_all_categories()
  484. response = self.client.get(self.category_a.get_absolute_url() + 'my/')
  485. self.assertEqual(response.status_code, 200)
  486. self.assertIn("empty-message", response.content)
  487. # test api
  488. self.access_all_categories()
  489. response = self.client.get('%s?list=my' % self.api_link)
  490. self.assertEqual(response.status_code, 200)
  491. response_json = json_loads(response.content)
  492. self.assertEqual(len(response_json['results']), 0)
  493. self.access_all_categories()
  494. response = self.client.get(
  495. '%s?list=my&category=%s' % (self.api_link, self.category_a.pk))
  496. response_json = json_loads(response.content)
  497. self.assertEqual(len(response_json['results']), 0)
  498. def test_list_renders_test_thread(self):
  499. """list renders only threads posted by user"""
  500. test_thread = testutils.post_thread(
  501. category=self.category_a,
  502. poster=self.user,
  503. )
  504. other_thread = testutils.post_thread(
  505. category=self.category_a,
  506. )
  507. self.access_all_categories()
  508. response = self.client.get('/my/')
  509. self.assertEqual(response.status_code, 200)
  510. self.assertIn(test_thread.get_absolute_url(), response.content)
  511. self.assertNotIn(other_thread.get_absolute_url(), response.content)
  512. self.access_all_categories()
  513. response = self.client.get(self.category_a.get_absolute_url() + 'my/')
  514. self.assertEqual(response.status_code, 200)
  515. self.assertIn(test_thread.get_absolute_url(), response.content)
  516. self.assertNotIn(other_thread.get_absolute_url(), response.content)
  517. # test api
  518. self.access_all_categories()
  519. response = self.client.get('%s?list=my' % self.api_link)
  520. self.assertEqual(response.status_code, 200)
  521. response_json = json_loads(response.content)
  522. self.assertEqual(len(response_json['results']), 1)
  523. self.assertEqual(response_json['results'][0]['id'], test_thread.pk)
  524. self.access_all_categories()
  525. response = self.client.get(
  526. '%s?list=my&category=%s' % (self.api_link, self.category_a.pk))
  527. self.assertEqual(response.status_code, 200)
  528. response_json = json_loads(response.content)
  529. self.assertEqual(len(response_json['results']), 1)
  530. self.assertEqual(response_json['results'][0]['id'], test_thread.pk)
  531. class NewThreadsListTests(ThreadsListTestCase):
  532. def test_list_renders_empty(self):
  533. """list renders empty"""
  534. self.access_all_categories()
  535. response = self.client.get('/new/')
  536. self.assertEqual(response.status_code, 200)
  537. self.assertIn("empty-message", response.content)
  538. self.access_all_categories()
  539. response = self.client.get(self.category_a.get_absolute_url() + 'new/')
  540. self.assertEqual(response.status_code, 200)
  541. self.assertIn("empty-message", response.content)
  542. # test api
  543. self.access_all_categories()
  544. response = self.client.get('%s?list=new' % 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. self.access_all_categories()
  549. response = self.client.get(
  550. '%s?list=new&category=%s' % (self.api_link, self.category_a.pk))
  551. response_json = json_loads(response.content)
  552. self.assertEqual(len(response_json['results']), 0)
  553. def test_list_renders_new_thread(self):
  554. """list renders new thread"""
  555. test_thread = testutils.post_thread(
  556. category=self.category_a,
  557. )
  558. self.access_all_categories()
  559. response = self.client.get('/new/')
  560. self.assertEqual(response.status_code, 200)
  561. self.assertIn(test_thread.get_absolute_url(), response.content)
  562. self.access_all_categories()
  563. response = self.client.get(self.category_a.get_absolute_url() + 'new/')
  564. self.assertEqual(response.status_code, 200)
  565. self.assertIn(test_thread.get_absolute_url(), response.content)
  566. # test api
  567. self.access_all_categories()
  568. response = self.client.get('%s?list=new' % self.api_link)
  569. self.assertEqual(response.status_code, 200)
  570. response_json = json_loads(response.content)
  571. self.assertEqual(len(response_json['results']), 1)
  572. self.assertEqual(response_json['results'][0]['id'], test_thread.pk)
  573. self.access_all_categories()
  574. response = self.client.get(
  575. '%s?list=new&category=%s' % (self.api_link, self.category_a.pk))
  576. self.assertEqual(response.status_code, 200)
  577. response_json = json_loads(response.content)
  578. self.assertEqual(len(response_json['results']), 1)
  579. self.assertEqual(response_json['results'][0]['id'], test_thread.pk)
  580. def test_list_renders_thread_bumped_after_user_cutoff(self):
  581. """list renders new thread bumped after user cutoff"""
  582. self.user.joined_on = timezone.now() - timedelta(days=10)
  583. self.user.save()
  584. test_thread = testutils.post_thread(
  585. category=self.category_a,
  586. started_on=self.user.joined_on - timedelta(days=2)
  587. )
  588. testutils.reply_thread(test_thread,
  589. posted_on=self.user.joined_on + timedelta(days=4)
  590. )
  591. self.access_all_categories()
  592. response = self.client.get('/new/')
  593. self.assertEqual(response.status_code, 200)
  594. self.assertIn(test_thread.get_absolute_url(), response.content)
  595. self.access_all_categories()
  596. response = self.client.get(
  597. self.category_a.get_absolute_url() + 'new/')
  598. self.assertEqual(response.status_code, 200)
  599. self.assertIn(test_thread.get_absolute_url(), response.content)
  600. # test api
  601. self.access_all_categories()
  602. response = self.client.get('%s?list=new' % self.api_link)
  603. self.assertEqual(response.status_code, 200)
  604. response_json = json_loads(response.content)
  605. self.assertEqual(len(response_json['results']), 1)
  606. self.assertEqual(response_json['results'][0]['id'], test_thread.pk)
  607. self.access_all_categories()
  608. response = self.client.get(
  609. '%s?list=new&category=%s' % (self.api_link, self.category_a.pk))
  610. self.assertEqual(response.status_code, 200)
  611. response_json = json_loads(response.content)
  612. self.assertEqual(len(response_json['results']), 1)
  613. self.assertEqual(response_json['results'][0]['id'], test_thread.pk)
  614. def test_list_hides_global_cutoff_thread(self):
  615. """list hides thread started before global cutoff"""
  616. self.user.joined_on = timezone.now() - timedelta(days=10)
  617. self.user.save()
  618. test_thread = testutils.post_thread(
  619. category=self.category_a,
  620. started_on=timezone.now() - timedelta(
  621. days=settings.MISAGO_FRESH_CONTENT_PERIOD + 1
  622. )
  623. )
  624. self.access_all_categories()
  625. response = self.client.get('/new/')
  626. self.assertEqual(response.status_code, 200)
  627. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  628. self.access_all_categories()
  629. response = self.client.get(self.category_a.get_absolute_url() + 'new/')
  630. self.assertEqual(response.status_code, 200)
  631. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  632. # test api
  633. self.access_all_categories()
  634. response = self.client.get('%s?list=new' % self.api_link)
  635. self.assertEqual(response.status_code, 200)
  636. response_json = json_loads(response.content)
  637. self.assertEqual(len(response_json['results']), 0)
  638. self.access_all_categories()
  639. response = self.client.get(
  640. '%s?list=new&category=%s' % (self.api_link, self.category_a.pk))
  641. self.assertEqual(response.status_code, 200)
  642. response_json = json_loads(response.content)
  643. self.assertEqual(len(response_json['results']), 0)
  644. def test_list_hides_user_cutoff_thread(self):
  645. """list hides thread started before users cutoff"""
  646. self.user.joined_on = timezone.now() - timedelta(days=5)
  647. self.user.save()
  648. test_thread = testutils.post_thread(
  649. category=self.category_a,
  650. started_on=self.user.joined_on - timedelta(minutes=1)
  651. )
  652. self.access_all_categories()
  653. response = self.client.get('/new/')
  654. self.assertEqual(response.status_code, 200)
  655. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  656. self.access_all_categories()
  657. response = self.client.get(self.category_a.get_absolute_url() + 'new/')
  658. self.assertEqual(response.status_code, 200)
  659. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  660. # test api
  661. self.access_all_categories()
  662. response = self.client.get('%s?list=new' % self.api_link)
  663. self.assertEqual(response.status_code, 200)
  664. response_json = json_loads(response.content)
  665. self.assertEqual(len(response_json['results']), 0)
  666. self.access_all_categories()
  667. response = self.client.get(
  668. '%s?list=new&category=%s' % (self.api_link, self.category_a.pk))
  669. self.assertEqual(response.status_code, 200)
  670. response_json = json_loads(response.content)
  671. self.assertEqual(len(response_json['results']), 0)
  672. def test_list_hides_user_read_thread(self):
  673. """list hides thread already read by user"""
  674. self.user.joined_on = timezone.now() - timedelta(days=5)
  675. self.user.save()
  676. test_thread = testutils.post_thread(
  677. category=self.category_a
  678. )
  679. threadstracker.make_thread_read_aware(self.user, test_thread)
  680. threadstracker.read_thread(
  681. self.user, test_thread, test_thread.last_post)
  682. self.access_all_categories()
  683. response = self.client.get('/new/')
  684. self.assertEqual(response.status_code, 200)
  685. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  686. self.access_all_categories()
  687. response = self.client.get(self.category_a.get_absolute_url() + 'new/')
  688. self.assertEqual(response.status_code, 200)
  689. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  690. # test api
  691. self.access_all_categories()
  692. response = self.client.get('%s?list=new' % self.api_link)
  693. self.assertEqual(response.status_code, 200)
  694. response_json = json_loads(response.content)
  695. self.assertEqual(len(response_json['results']), 0)
  696. self.access_all_categories()
  697. response = self.client.get(
  698. '%s?list=new&category=%s' % (self.api_link, self.category_a.pk))
  699. self.assertEqual(response.status_code, 200)
  700. response_json = json_loads(response.content)
  701. self.assertEqual(len(response_json['results']), 0)
  702. def test_list_hides_category_read_thread(self):
  703. """list hides thread already read by user"""
  704. self.user.joined_on = timezone.now() - timedelta(days=5)
  705. self.user.save()
  706. test_thread = testutils.post_thread(
  707. category=self.category_a
  708. )
  709. self.user.categoryread_set.create(
  710. category=self.category_a,
  711. last_read_on=timezone.now(),
  712. )
  713. self.access_all_categories()
  714. response = self.client.get('/new/')
  715. self.assertEqual(response.status_code, 200)
  716. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  717. self.access_all_categories()
  718. response = self.client.get(self.category_a.get_absolute_url() + 'new/')
  719. self.assertEqual(response.status_code, 200)
  720. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  721. # test api
  722. self.access_all_categories()
  723. response = self.client.get('%s?list=new' % self.api_link)
  724. self.assertEqual(response.status_code, 200)
  725. response_json = json_loads(response.content)
  726. self.assertEqual(len(response_json['results']), 0)
  727. self.access_all_categories()
  728. response = self.client.get(
  729. '%s?list=new&category=%s' % (self.api_link, self.category_a.pk))
  730. self.assertEqual(response.status_code, 200)
  731. response_json = json_loads(response.content)
  732. self.assertEqual(len(response_json['results']), 0)
  733. class UnreadThreadsListTests(ThreadsListTestCase):
  734. def test_list_renders_empty(self):
  735. """list renders empty"""
  736. self.access_all_categories()
  737. response = self.client.get('/unread/')
  738. self.assertEqual(response.status_code, 200)
  739. self.assertIn("empty-message", response.content)
  740. self.access_all_categories()
  741. response = self.client.get(
  742. self.category_a.get_absolute_url() + 'unread/')
  743. self.assertEqual(response.status_code, 200)
  744. self.assertIn("empty-message", response.content)
  745. # test api
  746. self.access_all_categories()
  747. response = self.client.get('%s?list=unread' % self.api_link)
  748. self.assertEqual(response.status_code, 200)
  749. response_json = json_loads(response.content)
  750. self.assertEqual(len(response_json['results']), 0)
  751. self.access_all_categories()
  752. response = self.client.get(
  753. '%s?list=unread&category=%s' % (self.api_link, self.category_a.pk))
  754. self.assertEqual(response.status_code, 200)
  755. response_json = json_loads(response.content)
  756. self.assertEqual(len(response_json['results']), 0)
  757. def test_list_renders_unread_thread(self):
  758. """list renders thread with unread posts"""
  759. self.user.joined_on = timezone.now() - timedelta(days=5)
  760. self.user.save()
  761. test_thread = testutils.post_thread(
  762. category=self.category_a
  763. )
  764. threadstracker.make_thread_read_aware(self.user, test_thread)
  765. threadstracker.read_thread(
  766. self.user, test_thread, test_thread.last_post)
  767. testutils.reply_thread(test_thread)
  768. self.access_all_categories()
  769. response = self.client.get('/unread/')
  770. self.assertEqual(response.status_code, 200)
  771. self.assertIn(test_thread.get_absolute_url(), response.content)
  772. self.access_all_categories()
  773. response = self.client.get(
  774. self.category_a.get_absolute_url() + 'unread/')
  775. self.assertEqual(response.status_code, 200)
  776. self.assertIn(test_thread.get_absolute_url(), response.content)
  777. # test api
  778. self.access_all_categories()
  779. response = self.client.get('%s?list=unread' % self.api_link)
  780. self.assertEqual(response.status_code, 200)
  781. response_json = json_loads(response.content)
  782. self.assertEqual(len(response_json['results']), 1)
  783. self.assertEqual(response_json['results'][0]['id'], test_thread.pk)
  784. self.access_all_categories()
  785. response = self.client.get(
  786. '%s?list=unread&category=%s' % (self.api_link, self.category_a.pk))
  787. self.assertEqual(response.status_code, 200)
  788. response_json = json_loads(response.content)
  789. self.assertEqual(len(response_json['results']), 1)
  790. self.assertEqual(response_json['results'][0]['id'], test_thread.pk)
  791. def test_list_hides_never_read_thread(self):
  792. """list hides never read thread"""
  793. self.user.joined_on = timezone.now() - timedelta(days=5)
  794. self.user.save()
  795. test_thread = testutils.post_thread(
  796. category=self.category_a
  797. )
  798. self.access_all_categories()
  799. response = self.client.get('/unread/')
  800. self.assertEqual(response.status_code, 200)
  801. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  802. self.access_all_categories()
  803. response = self.client.get(
  804. self.category_a.get_absolute_url() + 'unread/')
  805. self.assertEqual(response.status_code, 200)
  806. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  807. # test api
  808. self.access_all_categories()
  809. response = self.client.get('%s?list=unread' % self.api_link)
  810. self.assertEqual(response.status_code, 200)
  811. response_json = json_loads(response.content)
  812. self.assertEqual(len(response_json['results']), 0)
  813. self.access_all_categories()
  814. response = self.client.get(
  815. '%s?list=unread&category=%s' % (self.api_link, self.category_a.pk))
  816. self.assertEqual(response.status_code, 200)
  817. response_json = json_loads(response.content)
  818. self.assertEqual(len(response_json['results']), 0)
  819. def test_list_hides_read_thread(self):
  820. """list hides read thread"""
  821. self.user.joined_on = timezone.now() - timedelta(days=5)
  822. self.user.save()
  823. test_thread = testutils.post_thread(
  824. category=self.category_a
  825. )
  826. threadstracker.make_thread_read_aware(self.user, test_thread)
  827. threadstracker.read_thread(
  828. self.user, test_thread, test_thread.last_post)
  829. self.access_all_categories()
  830. response = self.client.get('/unread/')
  831. self.assertEqual(response.status_code, 200)
  832. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  833. self.access_all_categories()
  834. response = self.client.get(
  835. self.category_a.get_absolute_url() + 'unread/')
  836. self.assertEqual(response.status_code, 200)
  837. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  838. # test api
  839. self.access_all_categories()
  840. response = self.client.get('%s?list=unread' % self.api_link)
  841. self.assertEqual(response.status_code, 200)
  842. response_json = json_loads(response.content)
  843. self.assertEqual(len(response_json['results']), 0)
  844. self.access_all_categories()
  845. response = self.client.get(
  846. '%s?list=unread&category=%s' % (self.api_link, self.category_a.pk))
  847. self.assertEqual(response.status_code, 200)
  848. response_json = json_loads(response.content)
  849. self.assertEqual(len(response_json['results']), 0)
  850. def test_list_hides_global_cutoff_thread(self):
  851. """list hides thread replied before global cutoff"""
  852. self.user.joined_on = timezone.now() - timedelta(days=10)
  853. self.user.save()
  854. test_thread = testutils.post_thread(
  855. category=self.category_a,
  856. started_on=timezone.now() - timedelta(
  857. days=settings.MISAGO_FRESH_CONTENT_PERIOD + 5
  858. )
  859. )
  860. threadstracker.make_thread_read_aware(self.user, test_thread)
  861. threadstracker.read_thread(
  862. self.user, test_thread, test_thread.last_post)
  863. testutils.reply_thread(test_thread,
  864. posted_on=test_thread.started_on + timedelta(days=1)
  865. )
  866. self.access_all_categories()
  867. response = self.client.get('/unread/')
  868. self.assertEqual(response.status_code, 200)
  869. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  870. self.access_all_categories()
  871. response = self.client.get(
  872. self.category_a.get_absolute_url() + 'unread/')
  873. self.assertEqual(response.status_code, 200)
  874. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  875. # test api
  876. self.access_all_categories()
  877. response = self.client.get('%s?list=unread' % self.api_link)
  878. self.assertEqual(response.status_code, 200)
  879. response_json = json_loads(response.content)
  880. self.assertEqual(len(response_json['results']), 0)
  881. self.access_all_categories()
  882. response = self.client.get(
  883. '%s?list=unread&category=%s' % (self.api_link, self.category_a.pk))
  884. self.assertEqual(response.status_code, 200)
  885. response_json = json_loads(response.content)
  886. self.assertEqual(len(response_json['results']), 0)
  887. def test_list_hides_user_cutoff_thread(self):
  888. """list hides thread replied before user cutoff"""
  889. self.user.joined_on = timezone.now() - timedelta(days=10)
  890. self.user.save()
  891. test_thread = testutils.post_thread(
  892. category=self.category_a,
  893. started_on=self.user.joined_on - timedelta(days=2)
  894. )
  895. threadstracker.make_thread_read_aware(self.user, test_thread)
  896. threadstracker.read_thread(
  897. self.user, test_thread, test_thread.last_post)
  898. testutils.reply_thread(test_thread,
  899. posted_on=test_thread.started_on + timedelta(days=1)
  900. )
  901. self.access_all_categories()
  902. response = self.client.get('/unread/')
  903. self.assertEqual(response.status_code, 200)
  904. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  905. self.access_all_categories()
  906. response = self.client.get(
  907. self.category_a.get_absolute_url() + 'unread/')
  908. self.assertEqual(response.status_code, 200)
  909. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  910. # test api
  911. self.access_all_categories()
  912. response = self.client.get('%s?list=unread' % self.api_link)
  913. self.assertEqual(response.status_code, 200)
  914. response_json = json_loads(response.content)
  915. self.assertEqual(len(response_json['results']), 0)
  916. self.access_all_categories()
  917. response = self.client.get(
  918. '%s?list=unread&category=%s' % (self.api_link, self.category_a.pk))
  919. self.assertEqual(response.status_code, 200)
  920. response_json = json_loads(response.content)
  921. self.assertEqual(len(response_json['results']), 0)
  922. def test_list_hides_category_cutoff_thread(self):
  923. """list hides thread replied before category cutoff"""
  924. self.user.joined_on = timezone.now() - timedelta(days=10)
  925. self.user.save()
  926. test_thread = testutils.post_thread(
  927. category=self.category_a,
  928. started_on=self.user.joined_on - timedelta(days=2)
  929. )
  930. threadstracker.make_thread_read_aware(self.user, test_thread)
  931. threadstracker.read_thread(
  932. self.user, test_thread, test_thread.last_post)
  933. testutils.reply_thread(test_thread)
  934. self.user.categoryread_set.create(
  935. category=self.category_a,
  936. last_read_on=timezone.now(),
  937. )
  938. self.access_all_categories()
  939. response = self.client.get('/unread/')
  940. self.assertEqual(response.status_code, 200)
  941. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  942. self.access_all_categories()
  943. response = self.client.get(
  944. self.category_a.get_absolute_url() + 'unread/')
  945. self.assertEqual(response.status_code, 200)
  946. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  947. # test api
  948. self.access_all_categories()
  949. response = self.client.get('%s?list=unread' % self.api_link)
  950. self.assertEqual(response.status_code, 200)
  951. response_json = json_loads(response.content)
  952. self.assertEqual(len(response_json['results']), 0)
  953. self.access_all_categories()
  954. response = self.client.get(
  955. '%s?list=unread&category=%s' % (self.api_link, self.category_a.pk))
  956. self.assertEqual(response.status_code, 200)
  957. response_json = json_loads(response.content)
  958. self.assertEqual(len(response_json['results']), 0)
  959. class SubscribedThreadsListTests(ThreadsListTestCase):
  960. def test_list_shows_subscribed_thread(self):
  961. """list shows subscribed thread"""
  962. test_thread = testutils.post_thread(category=self.category_a)
  963. self.user.subscription_set.create(
  964. thread=test_thread,
  965. category=self.category_a,
  966. last_read_on=test_thread.last_post_on,
  967. )
  968. self.access_all_categories()
  969. response = self.client.get('/subscribed/')
  970. self.assertEqual(response.status_code, 200)
  971. self.assertIn(test_thread.get_absolute_url(), response.content)
  972. self.access_all_categories()
  973. response = self.client.get(
  974. self.category_a.get_absolute_url() + 'subscribed/')
  975. self.assertEqual(response.status_code, 200)
  976. self.assertIn(test_thread.get_absolute_url(), response.content)
  977. # test api
  978. self.access_all_categories()
  979. response = self.client.get('%s?list=subscribed' % self.api_link)
  980. self.assertEqual(response.status_code, 200)
  981. response_json = json_loads(response.content)
  982. self.assertEqual(len(response_json['results']), 1)
  983. self.assertIn(test_thread.get_absolute_url(), response.content)
  984. self.access_all_categories()
  985. response = self.client.get(
  986. '%s?list=subscribed&category=%s' % (
  987. self.api_link, self.category_a.pk
  988. ))
  989. self.assertEqual(response.status_code, 200)
  990. response_json = json_loads(response.content)
  991. self.assertEqual(len(response_json['results']), 1)
  992. self.assertIn(test_thread.get_absolute_url(), response.content)
  993. def test_list_hides_unsubscribed_thread(self):
  994. """list shows subscribed thread"""
  995. test_thread = testutils.post_thread(category=self.category_a)
  996. self.access_all_categories()
  997. response = self.client.get('/subscribed/')
  998. self.assertEqual(response.status_code, 200)
  999. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  1000. self.access_all_categories()
  1001. response = self.client.get(
  1002. self.category_a.get_absolute_url() + 'subscribed/')
  1003. self.assertEqual(response.status_code, 200)
  1004. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  1005. # test api
  1006. self.access_all_categories()
  1007. response = self.client.get('%s?list=subscribed' % self.api_link)
  1008. self.assertEqual(response.status_code, 200)
  1009. response_json = json_loads(response.content)
  1010. self.assertEqual(len(response_json['results']), 0)
  1011. self.assertNotIn(test_thread.get_absolute_url(), response.content)
  1012. self.access_all_categories()
  1013. response = self.client.get(
  1014. '%s?list=subscribed&category=%s' % (
  1015. self.api_link, self.category_a.pk
  1016. ))
  1017. self.assertEqual(response.status_code, 200)
  1018. response_json = json_loads(response.content)
  1019. self.assertEqual(len(response_json['results']), 0)
  1020. self.assertNotIn(test_thread.get_absolute_url(), response.content)