test_create_page.py 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656
  1. import datetime
  2. import unittest
  3. from unittest import mock
  4. from django.contrib.auth.models import Group, Permission
  5. from django.http import HttpRequest, HttpResponse
  6. from django.test import TestCase
  7. from django.test.utils import override_settings
  8. from django.urls import reverse
  9. from django.utils import timezone
  10. from django.utils.translation import gettext_lazy as _
  11. from wagtail.admin.tests.pages.timestamps import submittable_timestamp
  12. from wagtail.models import GroupPagePermission, Locale, Page, PageRevision
  13. from wagtail.signals import page_published
  14. from wagtail.test.testapp.models import (
  15. BusinessChild,
  16. BusinessIndex,
  17. BusinessSubIndex,
  18. DefaultStreamPage,
  19. PersonPage,
  20. SimplePage,
  21. SingletonPage,
  22. SingletonPageViaMaxCount,
  23. StandardChild,
  24. StandardIndex,
  25. )
  26. from wagtail.test.utils import WagtailTestUtils
  27. class TestPageCreation(TestCase, WagtailTestUtils):
  28. def setUp(self):
  29. # Find root page
  30. self.root_page = Page.objects.get(id=2)
  31. # Login
  32. self.user = self.login()
  33. def test_add_subpage(self):
  34. response = self.client.get(
  35. reverse("wagtailadmin_pages:add_subpage", args=(self.root_page.id,))
  36. )
  37. self.assertEqual(response.status_code, 200)
  38. self.assertContains(response, "Simple page")
  39. target_url = reverse(
  40. "wagtailadmin_pages:add", args=("tests", "simplepage", self.root_page.id)
  41. )
  42. self.assertContains(response, 'href="%s"' % target_url)
  43. self.assertContains(response, "A simple page description")
  44. # List of available page types should not contain pages with is_creatable = False
  45. self.assertNotContains(response, "MTI base page")
  46. # List of available page types should not contain abstract pages
  47. self.assertNotContains(response, "Abstract page")
  48. # List of available page types should not contain pages whose parent_page_types forbid it
  49. self.assertNotContains(response, "Business child")
  50. def test_add_subpage_with_subpage_types(self):
  51. # Add a BusinessIndex to test business rules in
  52. business_index = BusinessIndex(
  53. title="Hello world!",
  54. slug="hello-world",
  55. )
  56. self.root_page.add_child(instance=business_index)
  57. response = self.client.get(
  58. reverse("wagtailadmin_pages:add_subpage", args=(business_index.id,))
  59. )
  60. self.assertEqual(response.status_code, 200)
  61. self.assertContains(response, "Business child")
  62. # List should not contain page types not in the subpage_types list
  63. self.assertNotContains(response, "Simple page")
  64. def test_add_subpage_with_one_valid_subpage_type(self):
  65. # Add a BusinessSubIndex to test business rules in
  66. business_index = BusinessIndex(
  67. title="Hello world!",
  68. slug="hello-world",
  69. )
  70. self.root_page.add_child(instance=business_index)
  71. business_subindex = BusinessSubIndex(
  72. title="Hello world!",
  73. slug="hello-world",
  74. )
  75. business_index.add_child(instance=business_subindex)
  76. response = self.client.get(
  77. reverse("wagtailadmin_pages:add_subpage", args=(business_subindex.id,))
  78. )
  79. # Should be redirected to the 'add' page for BusinessChild, the only valid subpage type
  80. self.assertRedirects(
  81. response,
  82. reverse(
  83. "wagtailadmin_pages:add",
  84. args=("tests", "businesschild", business_subindex.id),
  85. ),
  86. )
  87. def test_add_subpage_bad_permissions(self):
  88. # Remove privileges from user
  89. self.user.is_superuser = False
  90. self.user.user_permissions.add(
  91. Permission.objects.get(
  92. content_type__app_label="wagtailadmin", codename="access_admin"
  93. )
  94. )
  95. self.user.save()
  96. # Get add subpage page
  97. response = self.client.get(
  98. reverse("wagtailadmin_pages:add_subpage", args=(self.root_page.id,))
  99. )
  100. # Check that the user received a 403 response
  101. self.assertEqual(response.status_code, 302)
  102. def test_add_subpage_nonexistantparent(self):
  103. response = self.client.get(
  104. reverse("wagtailadmin_pages:add_subpage", args=(100000,))
  105. )
  106. self.assertEqual(response.status_code, 404)
  107. def test_add_subpage_with_next_param(self):
  108. response = self.client.get(
  109. reverse("wagtailadmin_pages:add_subpage", args=(self.root_page.id,)),
  110. {"next": "/admin/users/"},
  111. )
  112. self.assertEqual(response.status_code, 200)
  113. self.assertContains(response, "Simple page")
  114. target_url = reverse(
  115. "wagtailadmin_pages:add", args=("tests", "simplepage", self.root_page.id)
  116. )
  117. self.assertContains(response, 'href="%s?next=/admin/users/"' % target_url)
  118. def test_create_simplepage(self):
  119. response = self.client.get(
  120. reverse(
  121. "wagtailadmin_pages:add",
  122. args=("tests", "simplepage", self.root_page.id),
  123. )
  124. )
  125. self.assertEqual(response.status_code, 200)
  126. self.assertEqual(response["Content-Type"], "text/html; charset=utf-8")
  127. self.assertContains(
  128. response,
  129. '<a href="#tab-content" class="active" data-tab="content">Content</a>',
  130. )
  131. self.assertContains(
  132. response, '<a href="#tab-promote" class="" data-tab="promote">Promote</a>'
  133. )
  134. # test register_page_action_menu_item hook
  135. self.assertContains(
  136. response,
  137. '<button type="submit" name="action-panic" value="Panic!" class="button">Panic!</button>',
  138. )
  139. self.assertContains(response, "testapp/js/siren.js")
  140. # test construct_page_action_menu hook
  141. self.assertContains(
  142. response,
  143. '<button type="submit" name="action-relax" value="Relax." class="button">Relax.</button>',
  144. )
  145. # test that workflow actions are shown
  146. self.assertContains(
  147. response,
  148. '<button type="submit" name="action-submit" value="Submit for moderation" class="button">',
  149. )
  150. @override_settings(WAGTAIL_WORKFLOW_ENABLED=False)
  151. def test_workflow_buttons_not_shown_when_workflow_disabled(self):
  152. response = self.client.get(
  153. reverse(
  154. "wagtailadmin_pages:add",
  155. args=("tests", "simplepage", self.root_page.id),
  156. )
  157. )
  158. self.assertEqual(response.status_code, 200)
  159. self.assertNotContains(response, 'value="Submit for moderation"')
  160. def test_create_multipart(self):
  161. """
  162. Test checks if 'enctype="multipart/form-data"' is added and only to forms that require multipart encoding.
  163. """
  164. # check for SimplePage where is no file field
  165. response = self.client.get(
  166. reverse(
  167. "wagtailadmin_pages:add",
  168. args=("tests", "simplepage", self.root_page.id),
  169. )
  170. )
  171. self.assertEqual(response.status_code, 200)
  172. self.assertNotContains(response, 'enctype="multipart/form-data"')
  173. self.assertTemplateUsed(response, "wagtailadmin/pages/create.html")
  174. # check for FilePage which has file field
  175. response = self.client.get(
  176. reverse(
  177. "wagtailadmin_pages:add", args=("tests", "filepage", self.root_page.id)
  178. )
  179. )
  180. self.assertEqual(response.status_code, 200)
  181. self.assertContains(response, 'enctype="multipart/form-data"')
  182. def test_create_page_without_promote_tab(self):
  183. """
  184. Test that the Promote tab is not rendered for page classes that define it as empty
  185. """
  186. response = self.client.get(
  187. reverse(
  188. "wagtailadmin_pages:add",
  189. args=("tests", "standardindex", self.root_page.id),
  190. )
  191. )
  192. self.assertEqual(response.status_code, 200)
  193. self.assertContains(
  194. response,
  195. '<a href="#tab-content" class="active" data-tab="content">Content</a>',
  196. )
  197. self.assertNotContains(
  198. response, '<a href="#tab-promote" class="" data-tab="promote">Promote</a>'
  199. )
  200. def test_create_page_with_custom_tabs(self):
  201. """
  202. Test that custom edit handlers are rendered
  203. """
  204. response = self.client.get(
  205. reverse(
  206. "wagtailadmin_pages:add",
  207. args=("tests", "standardchild", self.root_page.id),
  208. )
  209. )
  210. self.assertEqual(response.status_code, 200)
  211. self.assertContains(
  212. response,
  213. '<a href="#tab-content" class="active" data-tab="content">Content</a>',
  214. )
  215. self.assertContains(
  216. response, '<a href="#tab-promote" class="" data-tab="promote">Promote</a>'
  217. )
  218. self.assertContains(
  219. response,
  220. '<a href="#tab-dinosaurs" class="" data-tab="dinosaurs">Dinosaurs</a>',
  221. )
  222. def test_create_page_with_non_model_field(self):
  223. """
  224. Test that additional fields defined on the form rather than the model are accepted and rendered
  225. """
  226. response = self.client.get(
  227. reverse(
  228. "wagtailadmin_pages:add",
  229. args=("tests", "formclassadditionalfieldpage", self.root_page.id),
  230. )
  231. )
  232. self.assertEqual(response.status_code, 200)
  233. self.assertTemplateUsed(response, "wagtailadmin/pages/create.html")
  234. self.assertContains(response, "Enter SMS authentication code")
  235. def test_create_simplepage_bad_permissions(self):
  236. # Remove privileges from user
  237. self.user.is_superuser = False
  238. self.user.user_permissions.add(
  239. Permission.objects.get(
  240. content_type__app_label="wagtailadmin", codename="access_admin"
  241. )
  242. )
  243. self.user.save()
  244. # Get page
  245. response = self.client.get(
  246. reverse(
  247. "wagtailadmin_pages:add",
  248. args=(
  249. "tests",
  250. "simplepage",
  251. self.root_page.id,
  252. ),
  253. )
  254. )
  255. # Check that the user received a 403 response
  256. self.assertEqual(response.status_code, 302)
  257. def test_cannot_create_page_with_is_creatable_false(self):
  258. # tests.MTIBasePage has is_creatable=False, so attempting to add a new one
  259. # should fail with permission denied
  260. response = self.client.get(
  261. reverse(
  262. "wagtailadmin_pages:add",
  263. args=("tests", "mtibasepage", self.root_page.id),
  264. )
  265. )
  266. self.assertRedirects(response, "/admin/")
  267. def test_cannot_create_page_when_can_create_at_returns_false(self):
  268. # issue #2892
  269. # Check that creating a second SingletonPage results in a permission
  270. # denied error.
  271. # SingletonPage overrides the can_create_at method to make it return
  272. # False if another SingletonPage already exists.
  273. # The Page model now has a max_count attribute (issue 4841),
  274. # but we are leaving this test in place to cover existing behaviour and
  275. # ensure it does not break any code doing this in the wild.
  276. add_url = reverse(
  277. "wagtailadmin_pages:add",
  278. args=[
  279. SingletonPage._meta.app_label,
  280. SingletonPage._meta.model_name,
  281. self.root_page.pk,
  282. ],
  283. )
  284. # A single singleton page should be creatable
  285. self.assertTrue(SingletonPage.can_create_at(self.root_page))
  286. response = self.client.get(add_url)
  287. self.assertEqual(response.status_code, 200)
  288. # Create a singleton page
  289. self.root_page.add_child(
  290. instance=SingletonPage(title="singleton", slug="singleton")
  291. )
  292. # A second singleton page should not be creatable
  293. self.assertFalse(SingletonPage.can_create_at(self.root_page))
  294. response = self.client.get(add_url)
  295. self.assertRedirects(response, "/admin/")
  296. def test_cannot_create_singleton_page_with_max_count(self):
  297. # Check that creating a second SingletonPageViaMaxCount results in a permission
  298. # denied error.
  299. # SingletonPageViaMaxCount uses the max_count attribute to limit the number of
  300. # instance it can have.
  301. add_url = reverse(
  302. "wagtailadmin_pages:add",
  303. args=[
  304. SingletonPageViaMaxCount._meta.app_label,
  305. SingletonPageViaMaxCount._meta.model_name,
  306. self.root_page.pk,
  307. ],
  308. )
  309. # A single singleton page should be creatable
  310. self.assertTrue(SingletonPageViaMaxCount.can_create_at(self.root_page))
  311. response = self.client.get(add_url)
  312. self.assertEqual(response.status_code, 200)
  313. # Create a singleton page
  314. self.root_page.add_child(
  315. instance=SingletonPageViaMaxCount(title="singleton", slug="singleton")
  316. )
  317. # A second singleton page should not be creatable
  318. self.assertFalse(SingletonPageViaMaxCount.can_create_at(self.root_page))
  319. response = self.client.get(add_url)
  320. self.assertRedirects(response, "/admin/")
  321. def test_cannot_create_page_with_wrong_parent_page_types(self):
  322. # tests.BusinessChild has limited parent_page_types, so attempting to add
  323. # a new one at the root level should fail with permission denied
  324. response = self.client.get(
  325. reverse(
  326. "wagtailadmin_pages:add",
  327. args=("tests", "businesschild", self.root_page.id),
  328. )
  329. )
  330. self.assertRedirects(response, "/admin/")
  331. def test_cannot_create_page_with_wrong_subpage_types(self):
  332. # Add a BusinessIndex to test business rules in
  333. business_index = BusinessIndex(
  334. title="Hello world!",
  335. slug="hello-world",
  336. )
  337. self.root_page.add_child(instance=business_index)
  338. # BusinessIndex has limited subpage_types, so attempting to add a SimplePage
  339. # underneath it should fail with permission denied
  340. response = self.client.get(
  341. reverse(
  342. "wagtailadmin_pages:add",
  343. args=("tests", "simplepage", business_index.id),
  344. )
  345. )
  346. self.assertRedirects(response, "/admin/")
  347. def test_create_simplepage_post(self):
  348. post_data = {
  349. "title": "New page!",
  350. "content": "Some content",
  351. "slug": "hello-world",
  352. }
  353. response = self.client.post(
  354. reverse(
  355. "wagtailadmin_pages:add",
  356. args=("tests", "simplepage", self.root_page.id),
  357. ),
  358. post_data,
  359. )
  360. # Find the page and check it
  361. page = Page.objects.get(
  362. path__startswith=self.root_page.path, slug="hello-world"
  363. ).specific
  364. # Should be redirected to edit page
  365. self.assertRedirects(
  366. response, reverse("wagtailadmin_pages:edit", args=(page.id,))
  367. )
  368. self.assertEqual(page.title, post_data["title"])
  369. self.assertEqual(page.draft_title, post_data["title"])
  370. self.assertIsInstance(page, SimplePage)
  371. self.assertFalse(page.live)
  372. self.assertFalse(page.first_published_at)
  373. # treebeard should report no consistency problems with the tree
  374. self.assertFalse(
  375. any(Page.find_problems()), "treebeard found consistency problems"
  376. )
  377. def test_create_simplepage_scheduled(self):
  378. go_live_at = timezone.now() + datetime.timedelta(days=1)
  379. expire_at = timezone.now() + datetime.timedelta(days=2)
  380. post_data = {
  381. "title": "New page!",
  382. "content": "Some content",
  383. "slug": "hello-world",
  384. "go_live_at": submittable_timestamp(go_live_at),
  385. "expire_at": submittable_timestamp(expire_at),
  386. }
  387. response = self.client.post(
  388. reverse(
  389. "wagtailadmin_pages:add",
  390. args=("tests", "simplepage", self.root_page.id),
  391. ),
  392. post_data,
  393. )
  394. # Should be redirected to explorer page
  395. self.assertEqual(response.status_code, 302)
  396. # Find the page and check the scheduled times
  397. page = Page.objects.get(
  398. path__startswith=self.root_page.path, slug="hello-world"
  399. ).specific
  400. self.assertEqual(page.go_live_at.date(), go_live_at.date())
  401. self.assertEqual(page.expire_at.date(), expire_at.date())
  402. self.assertIs(page.expired, False)
  403. self.assertTrue(page.status_string, "draft")
  404. # No revisions with approved_go_live_at
  405. self.assertFalse(
  406. PageRevision.objects.filter(page=page)
  407. .exclude(approved_go_live_at__isnull=True)
  408. .exists()
  409. )
  410. def test_create_simplepage_scheduled_go_live_before_expiry(self):
  411. post_data = {
  412. "title": "New page!",
  413. "content": "Some content",
  414. "slug": "hello-world",
  415. "go_live_at": submittable_timestamp(
  416. timezone.now() + datetime.timedelta(days=2)
  417. ),
  418. "expire_at": submittable_timestamp(
  419. timezone.now() + datetime.timedelta(days=1)
  420. ),
  421. }
  422. response = self.client.post(
  423. reverse(
  424. "wagtailadmin_pages:add",
  425. args=("tests", "simplepage", self.root_page.id),
  426. ),
  427. post_data,
  428. )
  429. self.assertEqual(response.status_code, 200)
  430. # Check that a form error was raised
  431. self.assertFormError(
  432. response,
  433. "form",
  434. "go_live_at",
  435. "Go live date/time must be before expiry date/time",
  436. )
  437. self.assertFormError(
  438. response,
  439. "form",
  440. "expire_at",
  441. "Go live date/time must be before expiry date/time",
  442. )
  443. # form should be marked as having unsaved changes for the purposes of the dirty-forms warning
  444. self.assertContains(response, "alwaysDirty: true")
  445. def test_create_simplepage_scheduled_expire_in_the_past(self):
  446. post_data = {
  447. "title": "New page!",
  448. "content": "Some content",
  449. "slug": "hello-world",
  450. "expire_at": submittable_timestamp(
  451. timezone.now() + datetime.timedelta(days=-1)
  452. ),
  453. }
  454. response = self.client.post(
  455. reverse(
  456. "wagtailadmin_pages:add",
  457. args=("tests", "simplepage", self.root_page.id),
  458. ),
  459. post_data,
  460. )
  461. self.assertEqual(response.status_code, 200)
  462. # Check that a form error was raised
  463. self.assertFormError(
  464. response, "form", "expire_at", "Expiry date/time must be in the future"
  465. )
  466. # form should be marked as having unsaved changes for the purposes of the dirty-forms warning
  467. self.assertContains(response, "alwaysDirty: true")
  468. def test_create_simplepage_post_publish(self):
  469. # Connect a mock signal handler to page_published signal
  470. mock_handler = mock.MagicMock()
  471. page_published.connect(mock_handler)
  472. # Post
  473. post_data = {
  474. "title": "New page!",
  475. "content": "Some content",
  476. "slug": "hello-world",
  477. "action-publish": "Publish",
  478. }
  479. response = self.client.post(
  480. reverse(
  481. "wagtailadmin_pages:add",
  482. args=("tests", "simplepage", self.root_page.id),
  483. ),
  484. post_data,
  485. )
  486. # Find the page and check it
  487. page = Page.objects.get(
  488. path__startswith=self.root_page.path, slug="hello-world"
  489. ).specific
  490. # Should be redirected to explorer
  491. self.assertRedirects(
  492. response, reverse("wagtailadmin_explore", args=(self.root_page.id,))
  493. )
  494. self.assertEqual(page.title, post_data["title"])
  495. self.assertEqual(page.draft_title, post_data["title"])
  496. self.assertIsInstance(page, SimplePage)
  497. self.assertTrue(page.live)
  498. self.assertTrue(page.first_published_at)
  499. # Check that the page_published signal was fired
  500. self.assertEqual(mock_handler.call_count, 1)
  501. mock_call = mock_handler.mock_calls[0][2]
  502. self.assertEqual(mock_call["sender"], page.specific_class)
  503. self.assertEqual(mock_call["instance"], page)
  504. self.assertIsInstance(mock_call["instance"], page.specific_class)
  505. # treebeard should report no consistency problems with the tree
  506. self.assertFalse(
  507. any(Page.find_problems()), "treebeard found consistency problems"
  508. )
  509. def test_create_simplepage_post_publish_scheduled(self):
  510. go_live_at = timezone.now() + datetime.timedelta(days=1)
  511. expire_at = timezone.now() + datetime.timedelta(days=2)
  512. post_data = {
  513. "title": "New page!",
  514. "content": "Some content",
  515. "slug": "hello-world",
  516. "action-publish": "Publish",
  517. "go_live_at": submittable_timestamp(go_live_at),
  518. "expire_at": submittable_timestamp(expire_at),
  519. }
  520. response = self.client.post(
  521. reverse(
  522. "wagtailadmin_pages:add",
  523. args=("tests", "simplepage", self.root_page.id),
  524. ),
  525. post_data,
  526. )
  527. # Should be redirected to explorer page
  528. self.assertEqual(response.status_code, 302)
  529. # Find the page and check it
  530. page = Page.objects.get(
  531. path__startswith=self.root_page.path, slug="hello-world"
  532. ).specific
  533. self.assertEqual(page.go_live_at.date(), go_live_at.date())
  534. self.assertEqual(page.expire_at.date(), expire_at.date())
  535. self.assertIs(page.expired, False)
  536. # A revision with approved_go_live_at should exist now
  537. self.assertTrue(
  538. PageRevision.objects.filter(page=page)
  539. .exclude(approved_go_live_at__isnull=True)
  540. .exists()
  541. )
  542. # But Page won't be live
  543. self.assertFalse(page.live)
  544. self.assertFalse(page.first_published_at)
  545. self.assertTrue(page.status_string, "scheduled")
  546. def test_create_simplepage_post_submit(self):
  547. # Create a moderator user for testing email
  548. self.create_superuser("moderator", "moderator@email.com", "password")
  549. # Submit
  550. post_data = {
  551. "title": "New page!",
  552. "content": "Some content",
  553. "slug": "hello-world",
  554. "action-submit": "Submit",
  555. }
  556. response = self.client.post(
  557. reverse(
  558. "wagtailadmin_pages:add",
  559. args=("tests", "simplepage", self.root_page.id),
  560. ),
  561. post_data,
  562. )
  563. # Find the page and check it
  564. page = Page.objects.get(
  565. path__startswith=self.root_page.path, slug="hello-world"
  566. ).specific
  567. # Should be redirected to explorer
  568. self.assertRedirects(
  569. response, reverse("wagtailadmin_explore", args=(self.root_page.id,))
  570. )
  571. self.assertEqual(page.title, post_data["title"])
  572. self.assertIsInstance(page, SimplePage)
  573. self.assertFalse(page.live)
  574. self.assertFalse(page.first_published_at)
  575. # The page should now be in moderation
  576. self.assertEqual(
  577. page.current_workflow_state.status,
  578. page.current_workflow_state.STATUS_IN_PROGRESS,
  579. )
  580. def test_create_simplepage_post_existing_slug(self):
  581. # This tests the existing slug checking on page save
  582. # Create a page
  583. self.child_page = SimplePage(
  584. title="Hello world!", slug="hello-world", content="hello"
  585. )
  586. self.root_page.add_child(instance=self.child_page)
  587. # Attempt to create a new one with the same slug
  588. post_data = {
  589. "title": "New page!",
  590. "content": "Some content",
  591. "slug": "hello-world",
  592. "action-publish": "Publish",
  593. }
  594. response = self.client.post(
  595. reverse(
  596. "wagtailadmin_pages:add",
  597. args=("tests", "simplepage", self.root_page.id),
  598. ),
  599. post_data,
  600. )
  601. # Should not be redirected (as the save should fail)
  602. self.assertEqual(response.status_code, 200)
  603. # Check that a form error was raised
  604. self.assertFormError(response, "form", "slug", "This slug is already in use")
  605. # form should be marked as having unsaved changes for the purposes of the dirty-forms warning
  606. self.assertContains(response, "alwaysDirty: true")
  607. def test_create_nonexistantparent(self):
  608. response = self.client.get(
  609. reverse("wagtailadmin_pages:add", args=("tests", "simplepage", 100000))
  610. )
  611. self.assertEqual(response.status_code, 404)
  612. def test_create_nonpagetype(self):
  613. response = self.client.get(
  614. reverse(
  615. "wagtailadmin_pages:add",
  616. args=("wagtailimages", "image", self.root_page.id),
  617. )
  618. )
  619. self.assertEqual(response.status_code, 404)
  620. def test_preview_on_create(self):
  621. post_data = {
  622. "title": "New page!",
  623. "content": "Some content",
  624. "slug": "hello-world",
  625. "action-submit": "Submit",
  626. }
  627. preview_url = reverse(
  628. "wagtailadmin_pages:preview_on_add",
  629. args=("tests", "simplepage", self.root_page.id),
  630. )
  631. response = self.client.post(preview_url, post_data)
  632. # Check the JSON response
  633. self.assertEqual(response.status_code, 200)
  634. self.assertJSONEqual(response.content.decode(), {"is_valid": True})
  635. response = self.client.get(preview_url)
  636. # Check the HTML response
  637. self.assertEqual(response.status_code, 200)
  638. self.assertTemplateUsed(response, "tests/simple_page.html")
  639. self.assertContains(response, "New page!")
  640. # Check that the treebeard attributes were set correctly on the page object
  641. self.assertEqual(response.context["self"].depth, self.root_page.depth + 1)
  642. self.assertTrue(response.context["self"].path.startswith(self.root_page.path))
  643. self.assertEqual(response.context["self"].get_parent(), self.root_page)
  644. def test_whitespace_titles(self):
  645. post_data = {
  646. "title": " ", # Single space on purpose
  647. "content": "Some content",
  648. "slug": "hello-world",
  649. "action-submit": "Submit",
  650. }
  651. response = self.client.post(
  652. reverse(
  653. "wagtailadmin_pages:add",
  654. args=("tests", "simplepage", self.root_page.id),
  655. ),
  656. post_data,
  657. )
  658. # Check that a form error was raised
  659. self.assertFormError(response, "form", "title", "This field is required.")
  660. def test_whitespace_titles_with_tab(self):
  661. post_data = {
  662. "title": "\t", # Single space on purpose
  663. "content": "Some content",
  664. "slug": "hello-world",
  665. "action-submit": "Submit",
  666. }
  667. response = self.client.post(
  668. reverse(
  669. "wagtailadmin_pages:add",
  670. args=("tests", "simplepage", self.root_page.id),
  671. ),
  672. post_data,
  673. )
  674. # Check that a form error was raised
  675. self.assertFormError(response, "form", "title", "This field is required.")
  676. def test_whitespace_titles_with_tab_in_seo_title(self):
  677. post_data = {
  678. "title": "Hello",
  679. "content": "Some content",
  680. "slug": "hello-world",
  681. "action-submit": "Submit",
  682. "seo_title": "\t",
  683. }
  684. response = self.client.post(
  685. reverse(
  686. "wagtailadmin_pages:add",
  687. args=("tests", "simplepage", self.root_page.id),
  688. ),
  689. post_data,
  690. )
  691. # Should be successful, as seo_title is not required
  692. self.assertEqual(response.status_code, 302)
  693. # The tab should be automatically stripped from the seo_title
  694. page = Page.objects.order_by("-id").first()
  695. self.assertEqual(page.seo_title, "")
  696. def test_whitespace_is_stripped_from_titles(self):
  697. post_data = {
  698. "title": " Hello ",
  699. "content": "Some content",
  700. "slug": "hello-world",
  701. "action-submit": "Submit",
  702. "seo_title": " hello SEO ",
  703. }
  704. response = self.client.post(
  705. reverse(
  706. "wagtailadmin_pages:add",
  707. args=("tests", "simplepage", self.root_page.id),
  708. ),
  709. post_data,
  710. )
  711. # Should be successful, as both title and seo_title are non-empty after stripping
  712. self.assertEqual(response.status_code, 302)
  713. # Whitespace should be automatically stripped from title and seo_title
  714. page = Page.objects.order_by("-id").first()
  715. self.assertEqual(page.title, "Hello")
  716. self.assertEqual(page.draft_title, "Hello")
  717. self.assertEqual(page.seo_title, "hello SEO")
  718. def test_long_slug(self):
  719. post_data = {
  720. "title": "Hello world",
  721. "content": "Some content",
  722. "slug": "hello-world-hello-world-hello-world-hello-world-hello-world-hello-world-"
  723. "hello-world-hello-world-hello-world-hello-world-hello-world-hello-world-"
  724. "hello-world-hello-world-hello-world-hello-world-hello-world-hello-world-"
  725. "hello-world-hello-world-hello-world-hello-world-hello-world-hello-world",
  726. "action-submit": "Submit",
  727. }
  728. response = self.client.post(
  729. reverse(
  730. "wagtailadmin_pages:add",
  731. args=("tests", "simplepage", self.root_page.id),
  732. ),
  733. post_data,
  734. )
  735. # Check that a form error was raised
  736. self.assertEqual(response.status_code, 200)
  737. self.assertFormError(
  738. response,
  739. "form",
  740. "slug",
  741. "Ensure this value has at most 255 characters (it has 287).",
  742. )
  743. def test_before_create_page_hook(self):
  744. def hook_func(request, parent_page, page_class):
  745. self.assertIsInstance(request, HttpRequest)
  746. self.assertEqual(parent_page.id, self.root_page.id)
  747. self.assertEqual(page_class, SimplePage)
  748. return HttpResponse("Overridden!")
  749. with self.register_hook("before_create_page", hook_func):
  750. response = self.client.get(
  751. reverse(
  752. "wagtailadmin_pages:add",
  753. args=("tests", "simplepage", self.root_page.id),
  754. )
  755. )
  756. self.assertEqual(response.status_code, 200)
  757. self.assertEqual(response.content, b"Overridden!")
  758. def test_before_create_page_hook_post(self):
  759. def hook_func(request, parent_page, page_class):
  760. self.assertIsInstance(request, HttpRequest)
  761. self.assertEqual(parent_page.id, self.root_page.id)
  762. self.assertEqual(page_class, SimplePage)
  763. return HttpResponse("Overridden!")
  764. with self.register_hook("before_create_page", hook_func):
  765. post_data = {
  766. "title": "New page!",
  767. "content": "Some content",
  768. "slug": "hello-world",
  769. }
  770. response = self.client.post(
  771. reverse(
  772. "wagtailadmin_pages:add",
  773. args=("tests", "simplepage", self.root_page.id),
  774. ),
  775. post_data,
  776. )
  777. self.assertEqual(response.status_code, 200)
  778. self.assertEqual(response.content, b"Overridden!")
  779. # page should not be created
  780. self.assertFalse(Page.objects.filter(title="New page!").exists())
  781. def test_after_create_page_hook(self):
  782. def hook_func(request, page):
  783. self.assertIsInstance(request, HttpRequest)
  784. self.assertIsInstance(page, SimplePage)
  785. # Both are None as this is only a draft
  786. self.assertIsNone(page.first_published_at)
  787. self.assertIsNone(page.last_published_at)
  788. return HttpResponse("Overridden!")
  789. with self.register_hook("after_create_page", hook_func):
  790. post_data = {
  791. "title": "New page!",
  792. "content": "Some content",
  793. "slug": "hello-world",
  794. }
  795. response = self.client.post(
  796. reverse(
  797. "wagtailadmin_pages:add",
  798. args=("tests", "simplepage", self.root_page.id),
  799. ),
  800. post_data,
  801. )
  802. self.assertEqual(response.status_code, 200)
  803. self.assertEqual(response.content, b"Overridden!")
  804. # page should be created
  805. self.assertTrue(Page.objects.filter(title="New page!").exists())
  806. def test_after_create_page_hook_with_page_publish(self):
  807. def hook_func(request, page):
  808. self.assertIsInstance(request, HttpRequest)
  809. self.assertIsInstance(page, SimplePage)
  810. self.assertIsNotNone(page.first_published_at)
  811. self.assertIsNotNone(page.last_published_at)
  812. return HttpResponse("Overridden!")
  813. with self.register_hook("after_create_page", hook_func):
  814. post_data = {
  815. "title": "New page!",
  816. "content": "Some content",
  817. "slug": "hello-world",
  818. "action-publish": "Publish",
  819. }
  820. response = self.client.post(
  821. reverse(
  822. "wagtailadmin_pages:add",
  823. args=("tests", "simplepage", self.root_page.id),
  824. ),
  825. post_data,
  826. )
  827. self.assertEqual(response.status_code, 200)
  828. self.assertEqual(response.content, b"Overridden!")
  829. # page should be created
  830. self.assertTrue(Page.objects.filter(title="New page!").exists())
  831. def test_after_publish_page(self):
  832. def hook_func(request, page):
  833. self.assertIsInstance(request, HttpRequest)
  834. self.assertEqual(page.title, "New page!")
  835. self.assertIsNotNone(page.first_published_at)
  836. self.assertIsNotNone(page.last_published_at)
  837. return HttpResponse("Overridden!")
  838. with self.register_hook("after_publish_page", hook_func):
  839. post_data = {
  840. "title": "New page!",
  841. "content": "Some content",
  842. "slug": "hello-world",
  843. "action-publish": "Publish",
  844. }
  845. response = self.client.post(
  846. reverse(
  847. "wagtailadmin_pages:add",
  848. args=("tests", "simplepage", self.root_page.id),
  849. ),
  850. post_data,
  851. )
  852. self.assertEqual(response.status_code, 200)
  853. self.assertEqual(response.content, b"Overridden!")
  854. self.root_page.refresh_from_db()
  855. self.assertEqual(self.root_page.get_children()[0].status_string, _("live"))
  856. def test_before_publish_page(self):
  857. def hook_func(request, page):
  858. self.assertIsInstance(request, HttpRequest)
  859. self.assertEqual(page.title, "New page!")
  860. self.assertIsNone(page.first_published_at)
  861. self.assertIsNone(page.last_published_at)
  862. return HttpResponse("Overridden!")
  863. with self.register_hook("before_publish_page", hook_func):
  864. post_data = {
  865. "title": "New page!",
  866. "content": "Some content",
  867. "slug": "hello-world",
  868. "action-publish": "Publish",
  869. }
  870. response = self.client.post(
  871. reverse(
  872. "wagtailadmin_pages:add",
  873. args=("tests", "simplepage", self.root_page.id),
  874. ),
  875. post_data,
  876. )
  877. self.assertEqual(response.status_code, 200)
  878. self.assertEqual(response.content, b"Overridden!")
  879. self.root_page.refresh_from_db()
  880. self.assertEqual(
  881. self.root_page.get_children()[0].status_string, _("live + draft")
  882. )
  883. def test_display_moderation_button_by_default(self):
  884. """
  885. Tests that by default the "Submit for Moderation" button is shown in the action menu.
  886. """
  887. response = self.client.get(
  888. reverse(
  889. "wagtailadmin_pages:add",
  890. args=("tests", "simplepage", self.root_page.id),
  891. )
  892. )
  893. self.assertContains(
  894. response,
  895. '<button type="submit" name="action-submit" value="Submit for moderation" class="button">'
  896. '<svg class="icon icon-resubmit icon" aria-hidden="true"><use href="#icon-resubmit"></use></svg>'
  897. "Submit for moderation</button>",
  898. )
  899. @override_settings(WAGTAIL_MODERATION_ENABLED=False)
  900. def test_hide_moderation_button(self):
  901. """
  902. Tests that if WAGTAIL_MODERATION_ENABLED is set to False, the "Submit for Moderation" button is not shown.
  903. """
  904. response = self.client.get(
  905. reverse(
  906. "wagtailadmin_pages:add",
  907. args=("tests", "simplepage", self.root_page.id),
  908. )
  909. )
  910. self.assertNotContains(
  911. response,
  912. '<button type="submit" name="action-submit" value="Submit for moderation" class="button">Submit for moderation</button>',
  913. )
  914. def test_create_sets_locale_to_parent_locale(self):
  915. # We need to make sure the page's locale it set to the parent in the create view so that any customisations
  916. # for that language will take effect.
  917. fr_locale = Locale.objects.create(language_code="fr")
  918. fr_homepage = self.root_page.add_child(
  919. instance=Page(
  920. title="Home",
  921. slug="home-fr",
  922. locale=fr_locale,
  923. )
  924. )
  925. response = self.client.get(
  926. reverse(
  927. "wagtailadmin_pages:add", args=("tests", "simplepage", fr_homepage.id)
  928. )
  929. )
  930. self.assertEqual(response.context["page"].locale, fr_locale)
  931. class TestPermissionedFieldPanels(TestCase, WagtailTestUtils):
  932. fixtures = ["test.json"]
  933. def setUp(self):
  934. # Find root page
  935. self.root_page = Page.objects.get(id=2)
  936. GroupPagePermission.objects.create(
  937. group=Group.objects.get(name="Site-wide editors"),
  938. page=self.root_page,
  939. permission_type="add",
  940. )
  941. def test_create_page_with_permissioned_field_panel(self):
  942. """
  943. Test that permission rules on field panels are honoured
  944. """
  945. # non-superusers should not see secret_data
  946. self.login(username="siteeditor", password="password")
  947. response = self.client.get(
  948. reverse(
  949. "wagtailadmin_pages:add",
  950. args=("tests", "secretpage", self.root_page.id),
  951. )
  952. )
  953. self.assertEqual(response.status_code, 200)
  954. self.assertContains(response, '"boring_data"')
  955. self.assertNotContains(response, '"secret_data"')
  956. # superusers should see secret_data
  957. self.login(username="superuser", password="password")
  958. response = self.client.get(
  959. reverse(
  960. "wagtailadmin_pages:add",
  961. args=("tests", "secretpage", self.root_page.id),
  962. )
  963. )
  964. self.assertEqual(response.status_code, 200)
  965. self.assertContains(response, '"boring_data"')
  966. self.assertContains(response, '"secret_data"')
  967. class TestSubpageBusinessRules(TestCase, WagtailTestUtils):
  968. def setUp(self):
  969. # Find root page
  970. self.root_page = Page.objects.get(id=2)
  971. # Add standard page (allows subpages of any type)
  972. self.standard_index = StandardIndex()
  973. self.standard_index.title = "Standard Index"
  974. self.standard_index.slug = "standard-index"
  975. self.root_page.add_child(instance=self.standard_index)
  976. # Add business page (allows BusinessChild and BusinessSubIndex as subpages)
  977. self.business_index = BusinessIndex()
  978. self.business_index.title = "Business Index"
  979. self.business_index.slug = "business-index"
  980. self.root_page.add_child(instance=self.business_index)
  981. # Add business child (allows no subpages)
  982. self.business_child = BusinessChild()
  983. self.business_child.title = "Business Child"
  984. self.business_child.slug = "business-child"
  985. self.business_index.add_child(instance=self.business_child)
  986. # Add business subindex (allows only BusinessChild as subpages)
  987. self.business_subindex = BusinessSubIndex()
  988. self.business_subindex.title = "Business Subindex"
  989. self.business_subindex.slug = "business-subindex"
  990. self.business_index.add_child(instance=self.business_subindex)
  991. # Login
  992. self.login()
  993. def test_standard_subpage(self):
  994. add_subpage_url = reverse(
  995. "wagtailadmin_pages:add_subpage", args=(self.standard_index.id,)
  996. )
  997. # explorer should contain a link to 'add child page'
  998. response = self.client.get(
  999. reverse("wagtailadmin_explore", args=(self.standard_index.id,))
  1000. )
  1001. self.assertEqual(response.status_code, 200)
  1002. self.assertContains(response, add_subpage_url)
  1003. # add_subpage should give us choices of StandardChild, and BusinessIndex.
  1004. # BusinessSubIndex and BusinessChild are not allowed
  1005. response = self.client.get(add_subpage_url)
  1006. self.assertEqual(response.status_code, 200)
  1007. self.assertContains(response, StandardChild.get_verbose_name())
  1008. self.assertContains(response, BusinessIndex.get_verbose_name())
  1009. self.assertNotContains(response, BusinessSubIndex.get_verbose_name())
  1010. self.assertNotContains(response, BusinessChild.get_verbose_name())
  1011. def test_business_subpage(self):
  1012. add_subpage_url = reverse(
  1013. "wagtailadmin_pages:add_subpage", args=(self.business_index.id,)
  1014. )
  1015. # explorer should contain a link to 'add child page'
  1016. response = self.client.get(
  1017. reverse("wagtailadmin_explore", args=(self.business_index.id,))
  1018. )
  1019. self.assertEqual(response.status_code, 200)
  1020. self.assertContains(response, add_subpage_url)
  1021. # add_subpage should give us a cut-down set of page types to choose
  1022. response = self.client.get(add_subpage_url)
  1023. self.assertEqual(response.status_code, 200)
  1024. self.assertNotContains(response, StandardIndex.get_verbose_name())
  1025. self.assertNotContains(response, StandardChild.get_verbose_name())
  1026. self.assertContains(response, BusinessSubIndex.get_verbose_name())
  1027. self.assertContains(response, BusinessChild.get_verbose_name())
  1028. def test_business_child_subpage(self):
  1029. add_subpage_url = reverse(
  1030. "wagtailadmin_pages:add_subpage", args=(self.business_child.id,)
  1031. )
  1032. # explorer should not contain a link to 'add child page', as this page doesn't accept subpages
  1033. response = self.client.get(
  1034. reverse("wagtailadmin_explore", args=(self.business_child.id,))
  1035. )
  1036. self.assertEqual(response.status_code, 200)
  1037. self.assertNotContains(response, add_subpage_url)
  1038. # this also means that fetching add_subpage is blocked at the permission-check level
  1039. response = self.client.get(
  1040. reverse("wagtailadmin_pages:add_subpage", args=(self.business_child.id,))
  1041. )
  1042. self.assertEqual(response.status_code, 302)
  1043. def test_cannot_add_invalid_subpage_type(self):
  1044. # cannot add StandardChild as a child of BusinessIndex, as StandardChild is not present in subpage_types
  1045. response = self.client.get(
  1046. reverse(
  1047. "wagtailadmin_pages:add",
  1048. args=("tests", "standardchild", self.business_index.id),
  1049. )
  1050. )
  1051. self.assertRedirects(response, "/admin/")
  1052. # likewise for BusinessChild which has an empty subpage_types list
  1053. response = self.client.get(
  1054. reverse(
  1055. "wagtailadmin_pages:add",
  1056. args=("tests", "standardchild", self.business_child.id),
  1057. )
  1058. )
  1059. self.assertRedirects(response, "/admin/")
  1060. # cannot add BusinessChild to StandardIndex, as BusinessChild restricts is parent page types
  1061. response = self.client.get(
  1062. reverse(
  1063. "wagtailadmin_pages:add",
  1064. args=("tests", "businesschild", self.standard_index.id),
  1065. )
  1066. )
  1067. self.assertRedirects(response, "/admin/")
  1068. # but we can add a BusinessChild to BusinessIndex
  1069. response = self.client.get(
  1070. reverse(
  1071. "wagtailadmin_pages:add",
  1072. args=("tests", "businesschild", self.business_index.id),
  1073. )
  1074. )
  1075. self.assertEqual(response.status_code, 200)
  1076. def test_not_prompted_for_page_type_when_only_one_choice(self):
  1077. response = self.client.get(
  1078. reverse("wagtailadmin_pages:add_subpage", args=(self.business_subindex.id,))
  1079. )
  1080. # BusinessChild is the only valid subpage type of BusinessSubIndex, so redirect straight there
  1081. self.assertRedirects(
  1082. response,
  1083. reverse(
  1084. "wagtailadmin_pages:add",
  1085. args=("tests", "businesschild", self.business_subindex.id),
  1086. ),
  1087. )
  1088. class TestInlinePanelMedia(TestCase, WagtailTestUtils):
  1089. """
  1090. Test that form media required by InlinePanels is correctly pulled in to the edit page
  1091. """
  1092. def test_inline_panel_media(self):
  1093. homepage = Page.objects.get(id=2)
  1094. self.login()
  1095. # simplepage does not need draftail...
  1096. response = self.client.get(
  1097. reverse("wagtailadmin_pages:add", args=("tests", "simplepage", homepage.id))
  1098. )
  1099. self.assertEqual(response.status_code, 200)
  1100. self.assertNotContains(response, "wagtailadmin/js/draftail.js")
  1101. # but sectionedrichtextpage does
  1102. response = self.client.get(
  1103. reverse(
  1104. "wagtailadmin_pages:add",
  1105. args=("tests", "sectionedrichtextpage", homepage.id),
  1106. )
  1107. )
  1108. self.assertEqual(response.status_code, 200)
  1109. self.assertContains(response, "wagtailadmin/js/draftail.js")
  1110. class TestInlineStreamField(TestCase, WagtailTestUtils):
  1111. """
  1112. Test that streamfields inside an inline child work
  1113. """
  1114. def test_inline_streamfield(self):
  1115. homepage = Page.objects.get(id=2)
  1116. self.login()
  1117. response = self.client.get(
  1118. reverse(
  1119. "wagtailadmin_pages:add",
  1120. args=("tests", "inlinestreampage", homepage.id),
  1121. )
  1122. )
  1123. self.assertEqual(response.status_code, 200)
  1124. # response should include HTML declarations for streamfield child blocks
  1125. self.assertContains(response, '<div id="sections-__prefix__-body" data-block="')
  1126. class TestIssue2994(TestCase, WagtailTestUtils):
  1127. """
  1128. In contrast to most "standard" form fields, StreamField form widgets generally won't
  1129. provide a postdata field with a name exactly matching the field name. To prevent Django
  1130. from wrongly interpreting this as the field being omitted from the form,
  1131. we need to provide a custom value_omitted_from_data method.
  1132. """
  1133. def setUp(self):
  1134. self.root_page = Page.objects.get(id=2)
  1135. self.user = self.login()
  1136. def test_page_edit_post_publish_url(self):
  1137. # Post
  1138. post_data = {
  1139. "title": "Issue 2994 test",
  1140. "slug": "issue-2994-test",
  1141. "body-count": "1",
  1142. "body-0-deleted": "",
  1143. "body-0-order": "0",
  1144. "body-0-type": "text",
  1145. "body-0-value": "hello world",
  1146. "action-publish": "Publish",
  1147. }
  1148. self.client.post(
  1149. reverse(
  1150. "wagtailadmin_pages:add",
  1151. args=("tests", "defaultstreampage", self.root_page.id),
  1152. ),
  1153. post_data,
  1154. )
  1155. new_page = DefaultStreamPage.objects.get(slug="issue-2994-test")
  1156. self.assertEqual(1, len(new_page.body))
  1157. self.assertEqual("hello world", new_page.body[0].value)
  1158. class TestInlinePanelWithTags(TestCase, WagtailTestUtils):
  1159. # https://github.com/wagtail/wagtail/issues/5414#issuecomment-567080707
  1160. def setUp(self):
  1161. self.root_page = Page.objects.get(id=2)
  1162. self.user = self.login()
  1163. def test_create(self):
  1164. post_data = {
  1165. "title": "Mr Benn",
  1166. "slug": "mr-benn",
  1167. "first_name": "William",
  1168. "last_name": "Benn",
  1169. "addresses-TOTAL_FORMS": 1,
  1170. "addresses-INITIAL_FORMS": 0,
  1171. "addresses-MIN_NUM_FORMS": 0,
  1172. "addresses-MAX_NUM_FORMS": 1000,
  1173. "addresses-0-address": "52 Festive Road, London",
  1174. "addresses-0-tags": "shopkeeper, bowler-hat",
  1175. "action-publish": "Publish",
  1176. "comments-TOTAL_FORMS": 0,
  1177. "comments-INITIAL_FORMS": 0,
  1178. "comments-MIN_NUM_FORMS": 0,
  1179. "comments-MAX_NUM_FORMS": 1000,
  1180. }
  1181. response = self.client.post(
  1182. reverse(
  1183. "wagtailadmin_pages:add",
  1184. args=("tests", "personpage", self.root_page.id),
  1185. ),
  1186. post_data,
  1187. )
  1188. self.assertRedirects(
  1189. response, reverse("wagtailadmin_explore", args=(self.root_page.id,))
  1190. )
  1191. new_page = PersonPage.objects.get(slug="mr-benn")
  1192. self.assertEqual(new_page.addresses.first().tags.count(), 2)
  1193. class TestInlinePanelNonFieldErrors(TestCase, WagtailTestUtils):
  1194. """
  1195. Test that non field errors will render for InlinePanels
  1196. https://github.com/wagtail/wagtail/issues/3890
  1197. """
  1198. fixtures = ["demosite.json"]
  1199. def setUp(self):
  1200. self.root_page = Page.objects.get(id=2)
  1201. self.user = self.login()
  1202. def test_create(self):
  1203. post_data = {
  1204. "title": "Issue 3890 test",
  1205. "slug": "issue-3890-test",
  1206. "related_links-TOTAL_FORMS": 1,
  1207. "related_links-INITIAL_FORMS": 0,
  1208. "related_links-MIN_NUM_FORMS": 0,
  1209. "related_links-MAX_NUM_FORMS": 1000,
  1210. "related_links-0-id": 0,
  1211. "related_links-0-ORDER": 1,
  1212. # Leaving all fields empty should raise a validation error
  1213. "related_links-0-link_page": "",
  1214. "related_links-0-link_document": "",
  1215. "related_links-0-link_external": "",
  1216. "carousel_items-INITIAL_FORMS": 0,
  1217. "carousel_items-MAX_NUM_FORMS": 1000,
  1218. "carousel_items-TOTAL_FORMS": 0,
  1219. "action-publish": "Publish",
  1220. "comments-TOTAL_FORMS": 0,
  1221. "comments-INITIAL_FORMS": 0,
  1222. "comments-MIN_NUM_FORMS": 0,
  1223. "comments-MAX_NUM_FORMS": 1000,
  1224. }
  1225. response = self.client.post(
  1226. reverse(
  1227. "wagtailadmin_pages:add",
  1228. args=("demosite", "homepage", self.root_page.id),
  1229. ),
  1230. post_data,
  1231. )
  1232. self.assertEqual(response.status_code, 200)
  1233. self.assertContains(
  1234. response, "The page could not be created due to validation errors"
  1235. )
  1236. self.assertContains(
  1237. response,
  1238. "You must provide a related page, related document or an external URL",
  1239. count=1,
  1240. )
  1241. @override_settings(WAGTAIL_I18N_ENABLED=True)
  1242. class TestLocaleSelector(TestCase, WagtailTestUtils):
  1243. fixtures = ["test.json"]
  1244. def setUp(self):
  1245. self.events_page = Page.objects.get(url_path="/home/events/")
  1246. self.fr_locale = Locale.objects.create(language_code="fr")
  1247. self.translated_events_page = self.events_page.copy_for_translation(
  1248. self.fr_locale, copy_parents=True
  1249. )
  1250. self.user = self.login()
  1251. @unittest.expectedFailure # TODO: Page editor header rewrite
  1252. def test_locale_selector(self):
  1253. response = self.client.get(
  1254. reverse(
  1255. "wagtailadmin_pages:add",
  1256. args=["tests", "eventpage", self.events_page.id],
  1257. )
  1258. )
  1259. self.assertContains(response, '<li class="header-meta--locale">')
  1260. add_translation_url = reverse(
  1261. "wagtailadmin_pages:add",
  1262. args=["tests", "eventpage", self.translated_events_page.id],
  1263. )
  1264. self.assertContains(
  1265. response,
  1266. f'<a href="{add_translation_url}" aria-label="French" class="u-link is-live">',
  1267. )
  1268. @override_settings(WAGTAIL_I18N_ENABLED=False)
  1269. def test_locale_selector_not_present_when_i18n_disabled(self):
  1270. response = self.client.get(
  1271. reverse(
  1272. "wagtailadmin_pages:add",
  1273. args=["tests", "eventpage", self.events_page.id],
  1274. )
  1275. )
  1276. self.assertNotContains(response, '<li class="header-meta--locale">')
  1277. add_translation_url = reverse(
  1278. "wagtailadmin_pages:add",
  1279. args=["tests", "eventpage", self.translated_events_page.id],
  1280. )
  1281. self.assertNotContains(
  1282. response,
  1283. f'<a href="{add_translation_url}" aria-label="French" class="u-link is-live">',
  1284. )
  1285. @unittest.expectedFailure # TODO: Page editor header rewrite
  1286. def test_locale_selector_not_present_without_permission_to_add(self):
  1287. # Remove user's permissions to add in the French tree
  1288. group = Group.objects.get(name="Moderators")
  1289. GroupPagePermission.objects.create(
  1290. group=group,
  1291. page=self.events_page,
  1292. permission_type="add",
  1293. )
  1294. self.user.is_superuser = False
  1295. self.user.user_permissions.add(
  1296. Permission.objects.get(
  1297. content_type__app_label="wagtailadmin", codename="access_admin"
  1298. )
  1299. )
  1300. self.user.groups.add(group)
  1301. self.user.save()
  1302. # Locale indicator should exist, but the "French" option should be hidden
  1303. response = self.client.get(
  1304. reverse(
  1305. "wagtailadmin_pages:add",
  1306. args=["tests", "eventpage", self.events_page.id],
  1307. )
  1308. )
  1309. self.assertContains(response, '<li class="header-meta--locale">')
  1310. add_translation_url = reverse(
  1311. "wagtailadmin_pages:add",
  1312. args=["tests", "eventpage", self.translated_events_page.id],
  1313. )
  1314. self.assertNotContains(
  1315. response,
  1316. f'<a href="{add_translation_url}" aria-label="French" class="u-link is-live">',
  1317. )
  1318. @override_settings(WAGTAIL_I18N_ENABLED=True)
  1319. class TestLocaleSelectorOnRootPage(TestCase, WagtailTestUtils):
  1320. fixtures = ["test.json"]
  1321. def setUp(self):
  1322. self.root_page = Page.objects.get(id=1)
  1323. self.fr_locale = Locale.objects.create(language_code="fr")
  1324. self.user = self.login()
  1325. @unittest.expectedFailure # TODO: Page editor header rewrite
  1326. def test_locale_selector(self):
  1327. response = self.client.get(
  1328. reverse(
  1329. "wagtailadmin_pages:add",
  1330. args=["demosite", "homepage", self.root_page.id],
  1331. )
  1332. )
  1333. self.assertContains(response, '<li class="header-meta--locale">')
  1334. add_translation_url = (
  1335. reverse(
  1336. "wagtailadmin_pages:add",
  1337. args=["demosite", "homepage", self.root_page.id],
  1338. )
  1339. + "?locale=fr"
  1340. )
  1341. self.assertContains(
  1342. response,
  1343. f'<a href="{add_translation_url}" aria-label="French" class="u-link is-live">',
  1344. )
  1345. @override_settings(WAGTAIL_I18N_ENABLED=False)
  1346. def test_locale_selector_not_present_when_i18n_disabled(self):
  1347. response = self.client.get(
  1348. reverse(
  1349. "wagtailadmin_pages:add",
  1350. args=["demosite", "homepage", self.root_page.id],
  1351. )
  1352. )
  1353. self.assertNotContains(response, '<li class="header-meta--locale">')
  1354. add_translation_url = (
  1355. reverse(
  1356. "wagtailadmin_pages:add",
  1357. args=["demosite", "homepage", self.root_page.id],
  1358. )
  1359. + "?locale=fr"
  1360. )
  1361. self.assertNotContains(
  1362. response,
  1363. f'<a href="{add_translation_url}" aria-label="French" class="u-link is-live">',
  1364. )
  1365. class TestPageSubscriptionSettings(TestCase, WagtailTestUtils):
  1366. def setUp(self):
  1367. # Find root page
  1368. self.root_page = Page.objects.get(id=2)
  1369. # Login
  1370. self.user = self.login()
  1371. def test_commment_notifications_switched_on_by_default(self):
  1372. response = self.client.get(
  1373. reverse(
  1374. "wagtailadmin_pages:add",
  1375. args=["tests", "simplepage", self.root_page.id],
  1376. )
  1377. )
  1378. self.assertEqual(response.status_code, 200)
  1379. self.assertContains(
  1380. response,
  1381. '<input type="checkbox" name="comment_notifications" id="id_comment_notifications" checked>',
  1382. )
  1383. def test_post_with_comment_notifications_switched_on(self):
  1384. post_data = {
  1385. "title": "New page!",
  1386. "content": "Some content",
  1387. "slug": "hello-world",
  1388. "comment_notifications": "on",
  1389. }
  1390. response = self.client.post(
  1391. reverse(
  1392. "wagtailadmin_pages:add",
  1393. args=["tests", "simplepage", self.root_page.id],
  1394. ),
  1395. post_data,
  1396. )
  1397. page = Page.objects.get(
  1398. path__startswith=self.root_page.path, slug="hello-world"
  1399. ).specific
  1400. self.assertRedirects(
  1401. response, reverse("wagtailadmin_pages:edit", args=[page.id])
  1402. )
  1403. # Check the subscription
  1404. subscription = page.subscribers.get()
  1405. self.assertEqual(subscription.user, self.user)
  1406. self.assertTrue(subscription.comment_notifications)
  1407. def test_post_with_comment_notifications_switched_off(self):
  1408. post_data = {
  1409. "title": "New page!",
  1410. "content": "Some content",
  1411. "slug": "hello-world",
  1412. }
  1413. response = self.client.post(
  1414. reverse(
  1415. "wagtailadmin_pages:add",
  1416. args=["tests", "simplepage", self.root_page.id],
  1417. ),
  1418. post_data,
  1419. )
  1420. page = Page.objects.get(
  1421. path__startswith=self.root_page.path, slug="hello-world"
  1422. ).specific
  1423. self.assertRedirects(
  1424. response, reverse("wagtailadmin_pages:edit", args=[page.id])
  1425. )
  1426. # Check the subscription
  1427. subscription = page.subscribers.get()
  1428. self.assertEqual(subscription.user, self.user)
  1429. self.assertFalse(subscription.comment_notifications)