Merge branch 'page-locking-2' of https://github.com/kaedroho/wagtail into kaedroho-page-locking-2

This commit is contained in:
Matt Westcott 2014-10-07 12:06:13 +01:00
commit 994d0bba3e
28 changed files with 828 additions and 137 deletions

View file

@ -503,6 +503,7 @@
<li class="icon icon-pick">pick</li>
<li class="icon icon-redirect">redirect</li>
<li class="icon icon-view">view</li>
<li class="icon icon-no-view">no-view</li>
<li class="icon icon-collapse-up">collapse-up</li>
<li class="icon icon-collapse-down">collapse-down</li>
<li class="icon icon-help">help</li>

View file

@ -435,7 +435,15 @@
"permission_type": "edit"
}
},
{
"pk": 6,
"model": "wagtailcore.grouppagepermission",
"fields": {
"group": ["Event moderators"],
"page": 3,
"permission_type": "lock"
}
},
{
"pk": 1,
"model": "tests.customuser",

View file

@ -121,7 +121,7 @@
color:lighten($color-grey-2,30%);
-webkit-font-smoothing: auto;
font-size:0.80em;
margin:0 0.5em;
margin:0 0.5em 0.5em 0.5em;
background:white url("#{$static-root}bg-dark-diag.svg");
&.primary{
@ -130,11 +130,17 @@
background:white
}
}
form.status-tag:hover,
a.status-tag:hover,
a.status-tag.primary:hover{
border-color:$color-teal;
color:$color-teal;
}
form.status-tag:hover{
border-color:$color-teal-dark;
background-color:$color-teal-darker;
color:white;
}
.privacy-indicator {
.label-private, .label-public{

View file

@ -297,6 +297,37 @@ input[type=submit], input[type=reset], input[type=button], .button, button{
+ button{
margin-left:1em;
}
// A completely unstyled button
&.unbutton{
@include border-radius(0px);
width:auto;
height:auto;
line-height:auto;
padding:0;
font-size:inherit;
font-weight:normal;
vertical-align: middle;
display:inline;
background-color:transparent;
border:0;
color:inherit;
text-decoration:none;
text-transform:uppercase;
white-space: nowrap;
position:relative;
overflow:hidden;
outline:none;
box-sizing:border-box;
-webkit-font-smoothing: auto;
-moz-appearance: none;
-moz-box-sizing:border-box;
}
&:disabled, &[disabled]{
background-color:$color-grey-2;
border-color:$color-grey-2;
color:lighten($color-grey-2, 15%);
}
}
/* Special styles to counteract Firefox's completely unwarranted assumptions about button styles */

View file

@ -220,11 +220,16 @@
.icon-redirect:before{
content:"3";
}
/* Credit: Icon made by Zurb from Flaticon.com */
.icon-view:before,
.icon-no-view:before{
vertical-align:-3.5px;
font-size:1.1rem;
}
.icon-view:before{
content:"4";
vertical-align:-4.5px;
font-size:1.3rem;
}
.icon-no-view:before{
content:"^";
}
.icon-collapse-down:before{
content:"5";

View file

@ -373,6 +373,9 @@ table.listing{
right:5%;
top:2em;
}
.locked-indicator{
font-size:0.8em;
}
.title{
h2{
@ -388,8 +391,10 @@ table.listing{
}
}
.privacy-indicator{
font-size:0.9em;
.privacy-indicator,
.locked-indicator{
margin-right:0;
font-size:1em;
opacity:0.7;
}

View file

@ -1,7 +1,7 @@
{
"metadata": {
"name": "Wagtail",
"lastOpened": 1405598127608,
"name": "Wagtail 1",
"lastOpened": 1410881728324,
"created": 1405597423787
},
"iconSets": [
@ -430,11 +430,21 @@
},
{
"id": 104,
"order": 0
"order": 66,
"prevSize": 16,
"code": 52,
"name": "eye",
"tempChar": "",
"ligatures": ""
},
{
"id": 105,
"order": 0
"order": 67,
"prevSize": 16,
"code": 94,
"name": "eye-slash",
"tempChar": "",
"ligatures": ""
},
{
"id": 106,
@ -666,7 +676,7 @@
"prevSize": 16,
"code": 64,
"name": "globe",
"tempChar": "",
"tempChar": "",
"ligatures": ""
},
{
@ -1884,7 +1894,7 @@
],
"defaultCode": 61447,
"grid": 16,
"matchesSearch": true
"matchesSearch": false
},
{
"id": 8,
@ -3090,26 +3100,26 @@
{
"id": 104,
"paths": [
"M0 548.571q0-19.429 11.429-39.429 80-130.857 215.143-210.286t285.429-79.429 285.429 79.429 215.143 210.286q11.429 20 11.429 39.429t-11.429 39.429q-80 131.429-215.143 210.571t-285.429 79.143-285.429-79.429-215.143-210.286q-11.429-20-11.429-39.429zM73.143 548.571q76 117.143 190.571 186.571t248.286 69.429 248.286-69.429 190.571-186.571q-86.857-134.857-217.714-201.714 34.857 59.429 34.857 128.571 0 105.714-75.143 180.857t-180.857 75.143-180.857-75.143-75.143-180.857q0-69.143 34.857-128.571-130.857 66.857-217.714 201.714zM338.286 475.429q0 11.429 8 19.429t19.429 8 19.429-8 8-19.429q0-49.143 34.857-84t84-34.857q11.429 0 19.429-8t8-19.429-8-19.429-19.429-8q-71.429 0-122.571 51.143t-51.143 122.571z"
"M62 512.142q0-17.077 10.045-34.655 70.313-115.011 189.091-184.822t250.866-69.811 250.866 69.811 189.091 184.822q10.045 17.578 10.045 34.655t-10.045 34.655q-70.313 115.514-189.091 185.072t-250.866 69.56-250.866-69.811-189.091-184.822q-10.045-17.578-10.045-34.655zM126.286 512.142q66.797 102.958 167.494 163.978t218.22 61.022 218.22-61.022 167.494-163.978q-76.339-118.526-191.35-177.288 30.636 52.233 30.636 113.002 0 92.913-66.044 158.956t-158.956 66.044-158.956-66.044-66.044-158.956q0-60.771 30.636-113.002-115.011 58.761-191.35 177.288zM359.322 447.858q0 10.045 7.031 17.077t17.077 7.031 17.077-7.031 7.031-17.077q0-43.192 30.636-73.828t73.828-30.636q10.045 0 17.077-7.031t7.031-17.077-7.031-17.077-17.077-7.031q-62.78 0-107.728 44.95t-44.95 107.728z"
],
"tags": [
"eye"
],
"defaultCode": 61550,
"grid": 14,
"matchesSearch": false
"grid": 16,
"matchesSearch": true
},
{
"id": 105,
"paths": [
"M0 548.571q0-21.714 11.429-39.429 87.429-134.286 217.143-212t283.429-77.714q50.857 0 102.857 9.714l30.857-55.429q5.714-9.143 16-9.143 2.857 0 10.286 3.429t17.714 8.857 18.857 10.571 18 10.571 11.143 6.571q9.143 5.714 9.143 15.429 0 4-0.571 5.143-60 107.429-180 323.429t-180.571 324l-28 50.857q-5.714 9.143-16 9.143-6.857 0-76.571-40-9.143-5.714-9.143-16 0-6.857 25.143-49.714-81.714-37.143-150.571-98.857t-119.143-140q-11.429-17.714-11.429-39.429zM73.143 548.571q95.429 147.429 244 214.286l44.571-80.571q-49.714-36-77.714-90.857t-28-116q0-69.143 34.857-128.571-130.857 66.857-217.714 201.714zM338.286 475.429q0 11.429 8 19.429t19.429 8 19.429-8 8-19.429q0-49.143 34.857-84t84-34.857q11.429 0 19.429-8t8-19.429-8-19.429-19.429-8q-71.429 0-122.571 51.143t-51.143 122.571zM512 877.714l42.286-75.429q121.143-10.286 224.286-78.286t172.286-175.429q-65.714-102.286-161.143-168l36-64q54.286 36.571 104.286 87.429t82.571 105.143q11.429 19.429 11.429 39.429t-11.429 39.429q-22.286 36.571-62.286 82.857-85.714 98.286-198.571 152.571t-239.714 54.286zM603.429 714.286l160-286.857q4.571 25.714 4.571 48 0 79.429-45.143 144.857t-119.429 94z"
"M62 512.142q0-19.085 10.045-34.655 76.842-118.025 190.849-186.328t249.108-68.303q44.698 0 90.401 8.538l27.12-48.717q5.022-8.036 14.063-8.036 2.511 0 9.040 3.014t15.569 7.784 16.573 9.291 15.82 9.291 9.794 5.775q8.036 5.022 8.036 13.561 0 3.516-0.502 4.521-52.734 94.42-158.203 284.264t-158.705 284.766l-24.609 44.698q-5.022 8.036-14.063 8.036-6.026 0-67.298-35.156-8.036-5.022-8.036-14.063 0-6.026 22.099-43.694-71.819-32.646-132.337-86.886t-104.716-123.047q-10.045-15.569-10.045-34.655zM126.286 512.142q83.873 129.577 214.453 188.337l39.173-70.814q-43.694-31.641-68.303-79.854t-24.609-101.953q0-60.771 30.636-113.002-115.011 58.761-191.35 177.288zM359.322 447.858q0 10.045 7.031 17.077t17.077 7.031 17.077-7.031 7.031-17.077q0-43.192 30.636-73.828t73.828-30.636q10.045 0 17.077-7.031t7.031-17.077-7.031-17.077-17.077-7.031q-62.78 0-107.728 44.95t-44.95 107.728zM512 801.428l37.165-66.295q106.474-9.040 197.126-68.806t151.423-154.186q-57.757-89.9-141.63-147.656l31.641-56.25q47.712 32.142 91.658 76.842t72.572 92.411q10.045 17.077 10.045 34.655t-10.045 34.655q-19.587 32.142-54.743 72.823-75.335 86.384-174.525 134.095t-210.686 47.712zM592.358 657.79l140.625-252.12q4.017 22.6 4.017 42.188 0 69.811-39.677 127.315t-104.967 82.617z"
],
"tags": [
"eye-slash"
],
"defaultCode": 61552,
"grid": 14,
"matchesSearch": false
"grid": 16,
"matchesSearch": true
},
{
"id": 106,
@ -3895,7 +3905,7 @@
],
"defaultCode": 61632,
"grid": 14,
"matchesSearch": true
"matchesSearch": false
},
{
"id": 169,
@ -4471,7 +4481,7 @@
],
"defaultCode": 61680,
"grid": 14,
"matchesSearch": true
"matchesSearch": false
},
{
"id": 214,
@ -7330,7 +7340,7 @@
"code": 56,
"name": "clock",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"order": 3,
@ -7339,7 +7349,7 @@
"code": 109,
"name": "lock",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"order": 8,
@ -7348,7 +7358,7 @@
"code": 112,
"name": "lock-open",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"order": 1,
@ -7357,7 +7367,7 @@
"code": 36,
"name": "form",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 0,
@ -7366,7 +7376,7 @@
"code": 97,
"name": "uni61",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 1,
@ -7375,7 +7385,7 @@
"code": 98,
"name": "uni62",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 2,
@ -7384,7 +7394,7 @@
"code": 99,
"name": "uni63",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 3,
@ -7393,7 +7403,7 @@
"code": 100,
"name": "uni64",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 4,
@ -7402,7 +7412,7 @@
"code": 101,
"name": "uni65",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 5,
@ -7411,7 +7421,7 @@
"code": 102,
"name": "uni66",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 6,
@ -7420,7 +7430,7 @@
"code": 103,
"name": "uni67",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 7,
@ -7429,7 +7439,7 @@
"code": 105,
"name": "uni69",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 8,
@ -7438,7 +7448,7 @@
"code": 106,
"name": "uni6A",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 9,
@ -7447,7 +7457,7 @@
"code": 107,
"name": "uni6B",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 10,
@ -7456,7 +7466,7 @@
"code": 108,
"name": "uni6C",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 12,
@ -7465,7 +7475,7 @@
"code": 110,
"name": "uni6E",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 13,
@ -7474,7 +7484,7 @@
"code": 104,
"name": "uni68",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 14,
@ -7483,7 +7493,7 @@
"code": 111,
"name": "uni6F",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 16,
@ -7492,7 +7502,7 @@
"code": 113,
"name": "uni71",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 17,
@ -7501,7 +7511,7 @@
"code": 114,
"name": "uni72",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 18,
@ -7510,7 +7520,7 @@
"code": 115,
"name": "uni73",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 19,
@ -7519,7 +7529,7 @@
"code": 116,
"name": "uni74",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 20,
@ -7528,7 +7538,7 @@
"code": 117,
"name": "uni75",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 21,
@ -7537,7 +7547,7 @@
"code": 118,
"name": "uni76",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 22,
@ -7546,7 +7556,7 @@
"code": 119,
"name": "uni77",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 23,
@ -7555,7 +7565,7 @@
"code": 120,
"name": "uni78",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 24,
@ -7564,7 +7574,7 @@
"code": 122,
"name": "uni7A",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 25,
@ -7573,7 +7583,7 @@
"code": 65,
"name": "uni41",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 26,
@ -7582,7 +7592,7 @@
"code": 66,
"name": "uni42",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 27,
@ -7591,7 +7601,7 @@
"code": 68,
"name": "uni44",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 28,
@ -7600,7 +7610,7 @@
"code": 67,
"name": "uni43",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 29,
@ -7609,7 +7619,7 @@
"code": 69,
"name": "uni45",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 30,
@ -7618,7 +7628,7 @@
"code": 70,
"name": "uni46",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 31,
@ -7627,7 +7637,7 @@
"code": 71,
"name": "uni47",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 32,
@ -7636,7 +7646,7 @@
"code": 72,
"name": "uni48",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 33,
@ -7645,7 +7655,7 @@
"code": 73,
"name": "uni49",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 34,
@ -7654,7 +7664,7 @@
"code": 74,
"name": "uni4A",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 35,
@ -7663,7 +7673,7 @@
"code": 75,
"name": "uni4B",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 36,
@ -7672,7 +7682,7 @@
"code": 76,
"name": "uni4C",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 37,
@ -7681,7 +7691,7 @@
"code": 77,
"name": "uni4D",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 38,
@ -7690,7 +7700,7 @@
"code": 78,
"name": "uni4E",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 39,
@ -7699,7 +7709,7 @@
"code": 79,
"name": "uni4F",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 40,
@ -7708,7 +7718,7 @@
"code": 80,
"name": "uni50",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 41,
@ -7717,7 +7727,7 @@
"code": 81,
"name": "uni51",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 42,
@ -7735,7 +7745,7 @@
"code": 82,
"name": "uni52",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 44,
@ -7744,7 +7754,7 @@
"code": 84,
"name": "uni54",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 45,
@ -7753,7 +7763,7 @@
"code": 87,
"name": "uni57",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 46,
@ -7762,7 +7772,7 @@
"code": 88,
"name": "uni58",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 47,
@ -7771,7 +7781,7 @@
"code": 89,
"name": "uni59",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 48,
@ -7780,7 +7790,7 @@
"code": 90,
"name": "uni5A",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 49,
@ -7789,7 +7799,7 @@
"code": 86,
"name": "uni56",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 50,
@ -7798,7 +7808,7 @@
"code": 49,
"name": "uni31",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 51,
@ -7807,7 +7817,7 @@
"code": 85,
"name": "uni55",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 52,
@ -7816,7 +7826,7 @@
"code": 51,
"name": "uni33",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 53,
@ -7825,7 +7835,7 @@
"code": 50,
"name": "uni32",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 54,
@ -7834,7 +7844,7 @@
"code": 53,
"name": "uni35",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 55,
@ -7843,7 +7853,7 @@
"code": 54,
"name": "uni36",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 56,
@ -7852,7 +7862,7 @@
"code": 48,
"name": "uni30",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 57,
@ -7861,7 +7871,7 @@
"code": 63,
"name": "uni3F",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 58,
@ -7870,7 +7880,7 @@
"code": 33,
"name": "uni21",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 59,
@ -7879,7 +7889,7 @@
"code": 57,
"name": "uni39",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 60,
@ -7888,25 +7898,25 @@
"code": 83,
"name": "uni53",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 61,
"order": 65,
"order": 0,
"prevSize": 16,
"code": 52,
"name": "uni34",
"ligatures": "",
"tempChar": ""
"tempChar": ""
},
{
"id": 62,
"order": 66,
"order": 65,
"prevSize": 16,
"code": 55,
"name": "uni37",
"ligatures": "",
"tempChar": ""
"tempChar": ""
}
],
"id": 0,

View file

@ -13,7 +13,7 @@
<glyph unicode="&#x31;" d="M106.861 74.861c-39.551 39.551-61.798 93.109-61.798 149.139 0 116.18 94.757 210.938 210.938 210.938l26.367-26.367-26.367-26.367c-87.341 0-158.203-70.862-158.203-158.203 0-42.022 16.48-82.397 46.143-112.061l-32.135-4.12zM256 13.063l-26.367 26.367 26.367 26.367c87.341 0 158.203 70.862 158.203 158.203 0 42.023-16.48 82.397-46.143 112.061l32.135 4.12 4.944 32.959c39.551-39.551 61.798-93.109 61.798-149.139 0-116.18-94.757-210.938-210.938-210.938z" />
<glyph unicode="&#x32;" d="M203.266 276.735h-158.203l122.772-89.814-44.495-147.492 126.068 88.166 138.428-88.166-56.854 147.491 135.956 89.813h-158.203l-59.327 151.612z" />
<glyph unicode="&#x33;" d="M327.25 383.375v-88.125h45.938v-91.875h-180v51.563l-142.5-95.625 142.5-94.688v50.625h268.125v268.125z" />
<glyph unicode="&#x34;" d="M256 286.053c9.366 0 17.562-1.171 25.758-4.683s15.221-7.025 21.075-12.88c5.854-5.854 10.538-12.88 12.88-19.903 3.513-8.196 5.854-16.391 5.854-24.588 0-8.195-2.341-16.391-5.854-24.587-2.341-7.025-7.025-14.050-12.88-19.904s-12.88-9.366-21.075-12.88c-8.195-3.513-16.391-4.683-25.758-4.683s-17.562 1.171-25.758 4.683c-8.196 3.513-15.221 7.025-21.075 12.88-5.854 5.854-10.538 12.88-12.88 19.904-3.513 8.195-5.854 16.391-5.854 24.587s2.341 16.391 5.854 24.588c2.341 7.025 7.025 14.050 12.88 19.903s12.88 9.367 21.075 12.88c8.196 3.513 16.391 4.683 25.758 4.683zM256 126.822c14.050 0 26.928 2.341 39.808 7.025s23.416 11.709 32.783 21.075c9.366 8.195 16.391 18.733 22.245 30.441 4.683 12.88 7.025 24.587 7.025 38.637s-2.341 25.758-7.025 38.637c-5.854 11.709-12.88 22.245-22.245 30.441-9.366 9.366-19.904 16.391-32.783 21.074s-25.758 7.025-39.808 7.025-26.928-2.341-39.808-7.025c-12.88-4.683-23.416-11.708-32.783-21.074-9.367-8.196-16.391-18.733-22.245-30.441-4.683-12.88-7.025-24.588-7.025-38.637s2.341-25.758 7.025-38.637c5.854-11.709 12.88-22.245 22.245-30.441 9.367-9.366 19.904-16.391 32.783-21.075s25.758-7.025 39.808-7.025zM256 353.961c21.075 0 40.979-2.341 59.712-7.025s36.296-11.709 52.687-19.904c16.391-7.025 30.441-16.391 43.32-25.758 12.88-10.538 24.587-19.904 33.954-29.27 8.195-9.367 15.221-18.733 19.904-26.929 5.854-9.367 8.195-16.391 8.195-21.075s-2.341-11.708-8.195-21.075c-4.683-8.195-11.709-17.562-19.904-26.929-9.366-9.366-21.075-18.733-33.954-29.27-12.88-9.366-26.928-18.733-43.32-25.758-16.391-8.195-33.954-15.221-52.687-19.904s-38.637-7.025-59.712-7.025c-21.075 0-40.979 2.341-59.712 7.025-19.904 4.683-36.296 11.709-52.686 19.904-16.391 7.025-30.441 16.391-43.321 25.758-12.88 10.538-24.588 19.904-33.954 29.27-8.195 9.366-15.221 18.733-19.904 26.929-5.854 9.366-8.196 16.391-8.196 21.075s2.341 11.709 8.195 21.075c4.683 8.196 11.709 17.562 19.904 26.929 9.367 9.367 21.075 18.733 33.954 29.27 12.88 9.367 26.929 18.733 43.321 25.758 16.391 8.196 32.783 15.221 52.686 19.904 18.733 4.683 38.637 7.025 59.712 7.025z" />
<glyph unicode="&#x34;" d="M31 223.929q0 8.538 5.023 17.327 35.157 57.505 94.546 92.411t125.433 34.906 125.433-34.906 94.546-92.411q5.022-8.789 5.022-17.327t-5.022-17.327q-35.156-57.757-94.546-92.536t-125.433-34.78-125.433 34.906-94.546 92.411q-5.023 8.789-5.023 17.327zM63.143 223.929q33.398-51.479 83.747-81.989t109.11-30.511 109.11 30.511 83.747 81.989q-38.17 59.263-95.675 88.644 15.318-26.116 15.318-56.501 0-46.457-33.022-79.478t-79.478-33.022-79.478 33.022-33.022 79.478q0 30.385 15.318 56.501-57.505-29.38-95.675-88.644zM179.661 256.071q0-5.023 3.516-8.539t8.538-3.516 8.538 3.516 3.516 8.539q0 21.596 15.318 36.914t36.914 15.318q5.022 0 8.538 3.516t3.515 8.538-3.515 8.538-8.538 3.516q-31.39 0-53.864-22.475t-22.475-53.864z" />
<glyph unicode="&#x35;" d="M135 424h241v-23h-241zM405 247l-127-124v222h-45v-220l-125 122-33-32 181-181 181 181z" />
<glyph unicode="&#x36;" d="M136 424h241v-23h-241zM108 122l126 124v-222h45v220l126-122 32 32-181 181-181-181z" />
<glyph unicode="&#x37;" d="M387.836 13.063h-263.672c-43.671 0-79.102 35.431-79.102 79.101v263.672c0 34.607 22.248 63.446 52.734 74.158v-34.607c0-22.248 18.127-39.551 39.551-39.551s39.551 17.303 39.551 39.551v39.551h158.203v-39.551c0-22.248 18.127-39.551 39.551-39.551s39.551 17.303 39.551 39.551v34.607c30.487-10.712 52.735-39.551 52.735-74.158v-263.672c0-43.671-35.431-79.101-79.101-79.101zM414.203 303.101h-316.406v-210.938c0-14.832 11.535-26.367 26.367-26.367h263.672c14.832 0 26.367 11.536 26.367 26.367zM308.735 171.265h52.735v-52.735h-52.735zM308.735 250.367h52.735v-52.734h-52.735zM229.633 171.265h52.734v-52.735h-52.734zM229.633 250.367h52.734v-52.734h-52.734zM150.531 171.265h52.734v-52.735h-52.734zM150.531 250.367h52.734v-52.734h-52.734zM374.652 382.203c-7.416 0-13.183 5.768-13.183 13.184v39.551h26.367v-39.551c0-7.416-5.768-13.184-13.183-13.184zM137.347 382.203c-7.416 0-13.183 5.768-13.183 13.184v39.551h26.367v-39.551c0-7.416-5.768-13.184-13.184-13.184z" />
@ -47,6 +47,7 @@
<glyph unicode="&#x58;" d="M351.801 122.926c0.879-3.515 0.879-6.152-1.758-8.789l-87.89-96.68c-0.879-1.758-3.515-2.637-5.274-2.637-2.637 0-4.394 0.879-6.153 2.637l-88.769 96.68c-2.637 2.637-2.637 5.274-1.758 8.789 1.758 2.637 4.394 4.394 7.031 4.394h56.25v313.769c0 2.637 0.879 4.394 2.637 5.274 1.758 1.758 3.516 2.637 6.153 2.637h47.461c2.637 0 4.394-0.879 6.152-2.637 1.758-0.879 2.637-2.637 2.637-5.274v-313.769h56.25c3.515 0 5.274-1.758 7.031-4.394z" />
<glyph unicode="&#x59;" d="M351.801 325.074c-1.758-2.637-4.394-4.394-7.031-4.394h-56.25v-313.769c0-2.637-0.879-4.394-2.637-5.274-1.758-1.758-3.515-2.637-6.152-2.637h-47.461c-2.637 0-4.394 0.879-6.153 2.637-1.758 0.879-2.637 2.637-2.637 5.274v313.769h-56.25c-3.516 0-5.274 1.758-7.031 4.394-0.879 3.516-0.879 6.152 1.758 8.789l87.891 96.68c0.879 1.758 3.516 2.636 5.274 2.636 2.636 0 4.395-0.879 6.153-2.636l88.769-96.68c2.637-2.637 2.637-5.274 1.758-8.789z" />
<glyph unicode="&#x5a;" d="M201 270v-165c0-3-1-5-2-6-2-2-4-3-7-3h-18c-3 0-5 1-7 3-2 1-2 3-2 6v165c0 2 0 5 2 6 2 2 4 3 7 3h18c3 0 5-1 7-3 1-1 2-4 2-6zM274 270v-165c0-3-1-5-2-6-2-2-4-3-7-3h-18c-3 0-5 1-7 3-1 1-2 3-2 6v165c0 2 1 5 2 6 2 2 4 3 7 3h18c3 0 5-1 7-3 1-1 2-4 2-6zM347 270v-165c0-3 0-5-2-6-2-2-4-3-7-3h-18c-3 0-5 1-7 3-1 1-2 3-2 6v165c0 2 1 5 2 6 2 2 4 3 7 3h18c3 0 5-1 7-3 2-1 2-4 2-6zM384 63v271h-256v-271c0-4 1-8 2-12 1-3 3-6 4-7 2-2 3-3 3-3h238c0 0 1 1 3 3 1 1 3 4 4 7 1 4 2 8 2 12zM192 370h128l-14 34c-1 1-3 2-5 3h-90c-2-1-4-2-5-3zM457 361v-18c0-3-1-5-2-7-2-1-4-2-7-2h-27v-271c0-16-5-30-14-41-9-12-20-17-32-17h-238c-12 0-23 5-32 16s-14 25-14 41v272h-27c-3 0-5 1-7 2-1 2-2 4-2 7v18c0 3 1 5 2 7 2 1 4 2 7 2h88l20 48c3 7 8 13 16 18 7 5 15 7 22 7h92c7 0 15-2 22-7 8-5 13-11 16-18l20-48h88c3 0 5-1 7-2 1-2 2-4 2-7z" />
<glyph unicode="&#x5e;" d="M31 223.929q0 9.542 5.023 17.327 38.421 59.012 95.424 93.164t124.554 34.151q22.349 0 45.2-4.269l13.56 24.358q2.511 4.018 7.031 4.018 1.255 0 4.52-1.507t7.784-3.892 8.286-4.646 7.91-4.646 4.897-2.887q4.018-2.511 4.018-6.781 0-1.758-0.251-2.26-26.367-47.21-79.101-142.132t-79.353-142.383l-12.304-22.349q-2.511-4.018-7.031-4.018-3.013 0-33.649 17.578-4.018 2.511-4.018 7.031 0 3.013 11.049 21.847-35.91 16.323-66.168 43.443t-52.358 61.524q-5.023 7.784-5.023 17.327zM63.143 223.929q41.936-64.788 107.227-94.168l19.587 35.407q-21.847 15.82-34.151 39.927t-12.304 50.976q0 30.386 15.318 56.501-57.505-29.381-95.675-88.644zM179.661 256.071q0-5.023 3.516-8.539t8.538-3.516 8.538 3.516 3.516 8.539q0 21.596 15.318 36.914t36.914 15.318q5.022 0 8.538 3.516t3.515 8.538-3.515 8.538-8.538 3.516q-31.39 0-53.864-22.475t-22.475-53.864zM256 79.286l18.582 33.147q53.237 4.52 98.563 34.403t75.712 77.093q-28.878 44.95-70.815 73.828l15.82 28.125q23.856-16.071 45.829-38.421t36.286-46.205q5.022-8.538 5.022-17.327t-5.022-17.327q-9.793-16.071-27.372-36.411-37.668-43.192-87.262-67.048t-105.343-23.856zM296.179 151.105l70.313 126.060q2.009-11.3 2.009-21.094 0-34.906-19.839-63.658t-52.483-41.308z" />
<glyph unicode="&#x61;" d="M239 224c0 19-7 35-20 48-13 14-29 20-48 20s-35-6-49-20c-13-13-20-29-20-48s7-35 20-48c14-14 30-20 49-20s35 6 48 20c13 13 20 29 20 48zM444 87c0 10-4 18-10 24-7 7-15 11-24 11-10 0-18-4-24-11-7-6-11-14-11-24 0-9 4-17 10-24 7-6 15-10 25-10 9 0 17 4 24 10 6 7 10 15 10 24zM444 361c0 9-4 17-10 24-7 6-15 10-24 10-10 0-18-4-24-10-7-7-11-15-11-24 0-10 4-18 10-25 7-6 15-10 25-10 9 0 17 4 24 10 6 7 10 15 10 25zM341 248v-49c0-2 0-4-2-5-1-2-2-3-4-3l-41-6c-2-7-5-13-9-21 6-8 14-18 24-30 2-2 2-4 2-6s0-4-2-5c-4-5-11-13-22-24-10-10-17-16-21-16-2 0-3 1-5 2l-31 24c-6-3-13-6-20-8-2-19-4-33-7-41-1-5-3-7-8-7h-49c-2 0-4 1-5 2-2 2-3 3-3 5l-6 41c-6 2-13 4-20 8l-32-24c-1-1-3-2-5-2s-4 1-6 3c-25 23-38 37-38 42 0 2 1 4 2 5 2 3 5 8 11 14 5 7 9 13 12 17-4 8-7 15-9 22l-41 6c-1 0-3 1-4 3-1 1-2 3-2 5v49c0 2 1 4 2 5 1 2 3 3 4 3l41 6c2 7 5 13 9 21-6 8-14 18-24 30-1 2-2 4-2 6s1 4 2 5c4 5 11 13 22 24 11 10 18 16 21 16 2 0 4-1 6-2l30-24c6 3 13 6 21 8 2 19 4 33 6 41 1 5 4 7 8 7h49c2 0 4-1 6-2 1-2 2-3 2-5l7-41c6-2 12-4 20-8l31 24c1 1 3 2 5 2s4-1 6-3c26-23 38-37 38-42 0-2 0-4-1-5-3-3-6-8-12-15-5-6-9-12-12-16 4-8 7-16 9-22l41-6c2 0 3-1 4-3 2-1 2-3 2-5zM512 106v-37c0-3-13-6-40-8-2-5-5-10-8-14 9-20 14-33 14-37 0-1 0-1-1-2-22-13-33-19-33-19-2 0-6 4-13 13-6 8-11 14-13 18-4-1-7-1-8-1-2 0-5 0-8 1-3-4-8-10-14-18-7-9-11-13-13-13 0 0-11 6-33 19 0 1-1 1-1 2 0 4 5 17 14 37-3 4-6 9-8 14-27 2-40 5-40 8v37c0 3 13 6 40 8 2 6 5 10 8 14-9 20-14 33-14 37 0 1 1 1 1 2 1 0 4 2 10 5 5 3 10 6 15 9s8 5 8 5c2 0 6-5 13-13 6-8 11-14 14-18 3 1 6 1 8 1 1 0 4 0 8-1 9 13 17 23 24 30l2 1c0 0 11-7 33-19 1-1 1-1 1-2 0-4-5-17-14-37 3-4 6-8 8-14 27-2 40-5 40-8zM512 379v-37c0-3-13-6-40-8-2-5-5-10-8-14 9-20 14-33 14-37 0-1 0-1-1-2-22-13-33-19-33-19-2 0-6 4-13 13-6 8-11 14-13 18-4-1-7-1-8-1-2 0-5 0-8 1-3-4-8-10-14-18-7-9-11-13-13-13 0 0-11 6-33 19 0 1-1 1-1 2 0 4 5 17 14 37-3 4-6 9-8 14-27 2-40 5-40 8v37c0 3 13 6 40 8 2 6 5 10 8 14-9 20-14 33-14 37 0 1 1 1 1 2 1 0 4 2 10 5 5 4 10 7 15 9 5 3 8 5 8 5 2 0 6-4 13-13 6-8 11-14 14-18 3 1 6 1 8 1 1 0 4 0 8-1 9 13 17 23 24 30l2 1c0 0 11-7 33-19 1-1 1-1 1-2 0-4-5-17-14-37 3-4 6-8 8-14 27-2 40-5 40-8z" />
<glyph unicode="&#x62;" d="M451.2 263.466v-244.267c0-8.534-3.2-14.933-8.534-20.267-5.334-6.4-12.8-8.534-21.334-8.534h-330.666c-8.534 0-16 2.134-21.334 8.534-5.334 5.334-8.534 11.733-8.534 20.267v409.6c0 8.534 3.2 14.933 8.534 20.267 5.334 6.4 12.8 8.534 21.334 8.534h165.333v-165.333c0-8.534 3.2-14.934 8.533-20.267 5.334-6.4 12.8-8.534 20.267-8.534zM450.134 301.866h-154.667v155.734c16-3.2 29.866-9.6 39.466-20.267l94.933-94.934c10.666-10.666 17.067-23.466 20.267-40.534z" />
<glyph unicode="&#x63;" d="M100.266 28.8h311.466v234.666h-126.933c-7.466 0-14.933 2.134-20.267 8.534-5.334 5.334-8.534 11.734-8.534 20.267v126.933h-155.733zM295.466 301.866h114.134c-2.134 6.4-4.267 10.667-6.4 12.8l-96 94.933c-2.134 3.2-6.4 5.333-11.733 7.466zM451.2 292.267v-273.067c0-8.534-3.2-14.933-8.534-20.267-5.334-6.4-12.8-8.534-21.334-8.534h-330.666c-8.534 0-16 2.134-21.334 8.534-5.334 5.334-8.534 11.733-8.534 20.267v409.6c0 8.534 3.2 14.933 8.534 20.267 5.334 6.4 12.8 8.534 21.334 8.534h194.133c8.534 0 17.067-1.067 27.733-5.334 9.6-4.267 17.067-9.6 22.4-14.933l94.933-94.934c6.4-5.333 10.666-13.866 14.933-23.466s6.4-18.133 6.4-26.666z" />

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

View file

@ -1,6 +1,6 @@
{% load i18n %}
{% trans "Page privacy" as title_str %}
{% include "wagtailadmin/shared/header.html" with title=title_str icon="locked" %}
{% include "wagtailadmin/shared/header.html" with title=title_str icon="no-view" %}
<div class="nice-padding">
<p>{% trans "This page has been made private by a parent page." %}</p>

View file

@ -1,6 +1,6 @@
{% load i18n %}
{% trans "Page privacy" as title_str %}
{% include "wagtailadmin/shared/header.html" with title=title_str icon="locked" %}
{% include "wagtailadmin/shared/header.html" with title=title_str icon="no-view" %}
<div class="nice-padding">
<p class="help-block help-warning">{% trans "Privacy changes apply to all children of this page too." %}</p>

View file

@ -0,0 +1,31 @@
{% load i18n wagtailadmin_tags %}
{% if not page_perms %}
{% page_permissions page as page_perms %}
{% endif %}
<div class="lock-indicator {% if page.locked %}locked{% else %}unlocked{% endif %}">
{% trans "Edit lock" %}
{% if page.locked %}
{% if page_perms.can_lock %}
<form action="{% url 'wagtailadmin_pages_unlock' page.id %}" method="POST" class="status-tag primary">
{% csrf_token %}
<input type="hidden" name="next" value="{% url 'wagtailadmin_pages_edit' page.id %}">
<input type="submit" class="unbutton" value="{% trans "Locked" %}">
</form>
{% else %}
<span class="status-tag primary">Locked</span>
{% endif %}
{% else %}
{% if page_perms.can_lock %}
<form action="{% url 'wagtailadmin_pages_lock' page.id %}" method="POST" class="status-tag secondary">
{% csrf_token %}
<input type="hidden" name="next" value="{% url 'wagtailadmin_pages_edit' page.id %}">
<input type="submit" class="unbutton" value="{% trans "Unlocked" %}">
</form>
{% else %}
<span class="status-tag secondary">Unlocked</span>
{% endif %}
{% endif %}
</div>

View file

@ -1,20 +0,0 @@
{% load i18n %}
<div class="wagtail-moderator-controls">
<div class="message">
<p>{% blocktrans with title=revision.page.title submitted_by=revision.user.get_full_name|default:revision.user.username submitted_on=revision.created_at|date:"d M Y H:i" %}
Previewing '{{ title }}', submitted by {{ submitted_by }} on {{ submitted_on }}.
{% endblocktrans %}</p>
</div>
<div class="actions">
<a href="{% url 'wagtailadmin_pages_edit' revision.page.id %}" class="button">{% trans 'Edit' %}</a>
<form action="{% url 'wagtailadmin_pages_approve_moderation' revision.id %}" method="POST">
{% csrf_token %}
<input type="submit" class="button yes" value="{% trans 'Approve' %}" />
</form>
<form action="{% url 'wagtailadmin_pages_reject_moderation' revision.id %}" method="POST">
{% csrf_token %}
<input type="submit" class="button no" value="{% trans 'Reject' %}" />
</form>
</div>
</div>

View file

@ -10,14 +10,14 @@
{% if page_perms.can_set_view_restrictions %}
<a href="{% url 'wagtailadmin_pages_set_privacy' page.id %}" class="status-tag primary action-set-privacy">
{# labels are shown/hidden in CSS according to the 'private' / 'public' class on view-permission-indicator #}
<span class="label-public icon icon-unlocked">{% trans 'Public' %}</span>
<span class="label-private icon icon-locked">{% trans 'Private' %}</span>
<span class="label-public icon icon-view">{% trans 'Public' %}</span>
<span class="label-private icon icon-no-view">{% trans 'Private' %}</span>
</a>
{% else %}
{% if is_public %}
<span class="label-public status-tag primary icon icon-unlocked ">{% trans 'Public' %}</span>
<span class="label-public status-tag primary icon icon-view ">{% trans 'Public' %}</span>
{% else %}
<span class="label-private status-tag primary icon icon-locked">{% trans 'Private' %}</span>
<span class="label-private status-tag primary icon icon-no-view">{% trans 'Private' %}</span>
{% endif %}
{% endif %}
</div>

View file

@ -23,6 +23,7 @@
{% endif %}
{% include "wagtailadmin/pages/_privacy_indicator.html" with page=page page_perms=page_perms only %}
{% include "wagtailadmin/pages/_lock_indicator.html" %}
</div>
</div>
</header>
@ -35,20 +36,23 @@
<ul>
<li class="actions">
<div class="dropdown dropup dropdown-button match-width">
<input type="submit" value="{% trans 'Save draft' %}" class="button" />
<div class="dropdown-toggle icon icon-arrow-up"></div>
<ul role="menu">
{% if page_perms.can_unpublish %}
<li><a href="{% url 'wagtailadmin_pages_unpublish' page.id %}">{% trans 'Unpublish' %}</a></li>
{% endif %}
{% if page_perms.can_delete %}
<li><a href="{% url 'wagtailadmin_pages_delete' page.id %}" class="shortcut">{% trans 'Delete' %}</a></li>
{% endif %}
{% if page_perms.can_publish %}
<li><input type="submit" name="action-publish" value="{% trans 'Publish' %}" class="button" /></li>
{% endif %}
<li><input type="submit" name="action-submit" value="{% trans 'Submit for moderation' %}" class="button" /></li>
</ul>
<input type="submit" value="{% if page.locked %}{% trans 'Page locked' %}{% else %}{% trans 'Save draft' %}{% endif %}" class="button" {% if page.locked %}disabled {% endif %} />
{% if not page.locked %}
<div class="dropdown-toggle icon icon-arrow-up"></div>
<ul role="menu">
{% if page_perms.can_unpublish %}
<li><a href="{% url 'wagtailadmin_pages_unpublish' page.id %}">{% trans 'Unpublish' %}</a></li>
{% endif %}
{% if page_perms.can_delete %}
<li><a href="{% url 'wagtailadmin_pages_delete' page.id %}" class="shortcut">{% trans 'Delete' %}</a></li>
{% endif %}
{% if page_perms.can_publish %}
<li><input type="submit" name="action-publish" value="{% trans 'Publish' %}" class="button" /></li>
{% endif %}
<li><input type="submit" name="action-submit" value="{% trans 'Submit for moderation' %}" class="button" /></li>
</ul>
{% endif %}
</div>
</li>

View file

@ -40,7 +40,7 @@
{% test_page_is_public parent_page as is_public %}
{% if not is_public %}
<span class="privacy-indicator icon icon-locked" title="This page is protected from public view"></span>
<span class="privacy-indicator icon icon-no-view" title="{% trans "This page is protected from public view" %}"></span>
{% endif %}
</h2>
{% elif choosing %}
@ -53,7 +53,7 @@
{% test_page_is_public parent_page as is_public %}
{% if not is_public %}
<span class="privacy-indicator icon icon-locked" title="This page is protected from public view"></span>
<span class="privacy-indicator icon icon-no-view" title="This page is protected from public view"></span>
{% endif %}
</h2>
{% else %}
@ -61,7 +61,11 @@
{% if parent_page_perms.can_edit and 'edit' not in hide_actions|default:'' %}
<a href="{% url 'wagtailadmin_pages_edit' parent_page.id %}">{{ parent_page.title }}</a>
{% else %}
{{ parent_page.title }}
{{ parent_page.title }}
{% endif %}
{% if parent_page.locked %}
<span class="locked-indicator icon icon-locked" title="{% trans "This page is locked to further editing" %}"></span>
{% endif %}
</h2>
@ -181,7 +185,11 @@
{% test_page_is_public page as is_public %}
{% if not is_public %}
<span class="privacy-indicator icon icon-locked" title="This page is protected from public view"></span>
<span class="privacy-indicator icon icon-no-view" title="{% trans 'This page is protected from public view' %}"></span>
{% endif %}
{% if page.locked %}
<span class="locked-indicator icon icon-locked" title="{% trans 'This page is locked to further editing' %}"></span>
{% endif %}
</h2>
{% if not moving and not choosing %}

View file

@ -443,6 +443,28 @@ class TestPageEdit(TestCase, WagtailTestUtils):
child_page_new = SimplePage.objects.get(id=self.child_page.id)
self.assertTrue(child_page_new.has_unpublished_changes)
def test_page_edit_post_when_locked(self):
# Tests that trying to edit a locked page results in an error
# Lock the page
self.child_page.locked = True
self.child_page.save()
# Post
post_data = {
'title': "I've been edited!",
'content': "Some content",
'slug': 'hello-world',
}
response = self.client.post(reverse('wagtailadmin_pages_edit', args=(self.child_page.id, )), post_data)
# Shouldn't be redirected
self.assertContains(response, "The page could not be saved as it is locked")
# The page shouldn't have "has_unpublished_changes" flag set
child_page_new = SimplePage.objects.get(id=self.child_page.id)
self.assertFalse(child_page_new.has_unpublished_changes)
def test_edit_post_scheduled(self):
# put go_live_at and expire_at several days away from the current date, to avoid
# false matches in content_json__contains tests
@ -1702,6 +1724,199 @@ class TestNotificationPreferences(TestCase, WagtailTestUtils):
self.assertEqual(len(mail.outbox), 0)
class TestLocking(TestCase, WagtailTestUtils):
def setUp(self):
# Find root page
self.root_page = Page.objects.get(id=2)
# Login
self.user = self.login()
# Create a page and submit it for moderation
self.child_page = SimplePage(
title="Hello world!",
slug='hello-world',
live=False,
)
self.root_page.add_child(instance=self.child_page)
def test_lock_post(self):
response = self.client.post(reverse('wagtailadmin_pages_lock', args=(self.child_page.id, )))
# Check response
self.assertRedirects(response, reverse('wagtailadmin_explore', args=(self.root_page.id, )))
# Check that the page is locked
self.assertTrue(Page.objects.get(id=self.child_page.id).locked)
def test_lock_get(self):
response = self.client.get(reverse('wagtailadmin_pages_lock', args=(self.child_page.id, )))
# Check response
self.assertEqual(response.status_code, 405)
# Check that the page is still unlocked
self.assertFalse(Page.objects.get(id=self.child_page.id).locked)
def test_lock_post_already_locked(self):
# Lock the page
self.child_page.locked = True
self.child_page.save()
response = self.client.post(reverse('wagtailadmin_pages_lock', args=(self.child_page.id, )))
# Check response
self.assertRedirects(response, reverse('wagtailadmin_explore', args=(self.root_page.id, )))
# Check that the page is still locked
self.assertTrue(Page.objects.get(id=self.child_page.id).locked)
def test_lock_post_with_good_redirect(self):
response = self.client.post(reverse('wagtailadmin_pages_lock', args=(self.child_page.id, )), {
'next': reverse('wagtailadmin_pages_edit', args=(self.child_page.id, ))
})
# Check response
self.assertRedirects(response, reverse('wagtailadmin_pages_edit', args=(self.child_page.id, )))
# Check that the page is locked
self.assertTrue(Page.objects.get(id=self.child_page.id).locked)
def test_unlock_post_with_bad_redirect(self):
response = self.client.post(reverse('wagtailadmin_pages_lock', args=(self.child_page.id, )), {
'next': 'http://www.google.co.uk'
})
# Check response
self.assertRedirects(response, reverse('wagtailadmin_explore', args=(self.root_page.id, )))
# Check that the page is locked
self.assertTrue(page.objects.get(id=self.child_page.id).locked)
def test_lock_post_bad_page(self):
response = self.client.post(reverse('wagtailadmin_pages_lock', args=(9999, )))
# Check response
self.assertEqual(response.status_code, 404)
# Check that the page is still unlocked
self.assertFalse(Page.objects.get(id=self.child_page.id).locked)
def test_lock_post_bad_permissions(self):
# Remove privileges from user
self.user.is_superuser = False
self.user.user_permissions.add(
Permission.objects.get(content_type__app_label='wagtailadmin', codename='access_admin')
)
self.user.save()
response = self.client.post(reverse('wagtailadmin_pages_lock', args=(self.child_page.id, )))
# Check response
self.assertEqual(response.status_code, 403)
# Check that the page is still unlocked
self.assertFalse(Page.objects.get(id=self.child_page.id).locked)
def test_unlock_post(self):
# Lock the page
self.child_page.locked = True
self.child_page.save()
response = self.client.post(reverse('wagtailadmin_pages_unlock', args=(self.child_page.id, )))
# Check response
self.assertRedirects(response, reverse('wagtailadmin_explore', args=(self.root_page.id, )))
# Check that the page is unlocked
self.assertFalse(Page.objects.get(id=self.child_page.id).locked)
def test_unlock_get(self):
# Lock the page
self.child_page.locked = True
self.child_page.save()
response = self.client.get(reverse('wagtailadmin_pages_unlock', args=(self.child_page.id, )))
# Check response
self.assertEqual(response.status_code, 405)
# Check that the page is still locked
self.assertTrue(Page.objects.get(id=self.child_page.id).locked)
def test_unlock_post_already_unlocked(self):
response = self.client.post(reverse('wagtailadmin_pages_unlock', args=(self.child_page.id, )))
# Check response
self.assertRedirects(response, reverse('wagtailadmin_explore', args=(self.root_page.id, )))
# Check that the page is still unlocked
self.assertFalse(Page.objects.get(id=self.child_page.id).locked)
def test_unlock_post_with_good_redirect(self):
# Lock the page
self.child_page.locked = True
self.child_page.save()
response = self.client.post(reverse('wagtailadmin_pages_unlock', args=(self.child_page.id, )), {
'next': reverse('wagtailadmin_pages_edit', args=(self.child_page.id, ))
})
# Check response
self.assertRedirects(response, reverse('wagtailadmin_pages_edit', args=(self.child_page.id, )))
# Check that the page is unlocked
self.assertFalse(Page.objects.get(id=self.child_page.id).locked)
def test_unlock_post_with_bad_redirect(self):
# Lock the page
self.child_page.locked = True
self.child_page.save()
response = self.client.post(reverse('wagtailadmin_pages_unlock', args=(self.child_page.id, )), {
'next': 'http://www.google.co.uk'
})
# Check response
self.assertRedirects(response, reverse('wagtailadmin_explore', args=(self.root_page.id, )))
# Check that the page is unlocked
self.assertFalse(Page.objects.get(id=self.child_page.id).locked)
def test_unlock_post_bad_page(self):
# Lock the page
self.child_page.locked = True
self.child_page.save()
response = self.client.post(reverse('wagtailadmin_pages_unlock', args=(9999, )))
# Check response
self.assertEqual(response.status_code, 404)
# Check that the page is still locked
self.assertTrue(Page.objects.get(id=self.child_page.id).locked)
def test_unlock_post_bad_permissions(self):
# Remove privileges from user
self.user.is_superuser = False
self.user.user_permissions.add(
Permission.objects.get(content_type__app_label='wagtailadmin', codename='access_admin')
)
self.user.save()
# Lock the page
self.child_page.locked = True
self.child_page.save()
response = self.client.post(reverse('wagtailadmin_pages_unlock', args=(self.child_page.id, )))
# Check response
self.assertEqual(response.status_code, 403)
# Check that the page is still locked
self.assertTrue(Page.objects.get(id=self.child_page.id).locked)
class TestIssue197(TestCase, WagtailTestUtils):
def test_issue_197(self):
# Find root page

View file

@ -204,7 +204,7 @@ class TestPrivacyIndicators(TestCase, WagtailTestUtils):
self.assertEqual(response.status_code, 200)
# Must have one privacy icon (next to the private page)
self.assertContains(response, "<span class=\"privacy-indicator icon icon-locked\"", count=1)
self.assertContains(response, "<span class=\"privacy-indicator icon icon-no-view\"", count=1)
def test_explorer_list_private(self):
"""
@ -216,7 +216,7 @@ class TestPrivacyIndicators(TestCase, WagtailTestUtils):
self.assertEqual(response.status_code, 200)
# Must have one privacy icon (next to the private child page)
self.assertContains(response, "<span class=\"privacy-indicator icon icon-locked\"", count=1)
self.assertContains(response, "<span class=\"privacy-indicator icon icon-no-view\"", count=1)
def test_edit_public(self):
"""

View file

@ -73,6 +73,9 @@ urlpatterns += [
url(r'^pages/(\d+)/privacy/$', page_privacy.set_privacy, name='wagtailadmin_pages_set_privacy'),
url(r'^pages/(\d+)/lock/$', pages.lock, name='wagtailadmin_pages_lock'),
url(r'^pages/(\d+)/unlock/$', pages.unlock, name='wagtailadmin_pages_unlock'),
url(r'^choose-page/$', chooser.browse, name='wagtailadmin_choose_page'),
url(r'^choose-page/(\d+)/$', chooser.browse, name='wagtailadmin_choose_page_child'),
url(r'^choose-external-link/$', chooser.external_link, name='wagtailadmin_choose_page_external_link'),

View file

@ -9,7 +9,8 @@ from django.contrib.auth.decorators import permission_required
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.utils import timezone
from django.utils.translation import ugettext as _
from django.views.decorators.http import require_GET
from django.utils.http import is_safe_url
from django.views.decorators.http import require_GET, require_POST
from django.views.decorators.vary import vary_on_headers
from wagtail.wagtailadmin.edit_handlers import TabbedInterface, ObjectList
@ -288,7 +289,7 @@ def edit(request, page_id):
return cleaned_data
form.clean = clean
if form.is_valid():
if form.is_valid() and not page.locked:
page = form.save(commit=False)
is_publishing = bool(request.POST.get('action-publish')) and page_perms.can_publish()
@ -329,7 +330,10 @@ def edit(request, page_id):
return redirect('wagtailadmin_explore', page.get_parent().id)
else:
messages.error(request, _("The page could not be saved due to validation errors"))
if page.locked:
messages.error(request, _("The page could not be saved as it is locked"))
else:
messages.error(request, _("The page could not be saved due to validation errors"))
edit_handler = edit_handler_class(instance=page, form=form)
errors_debug = (
@ -761,3 +765,49 @@ def preview_for_moderation(request, revision_id):
# pass in the real user request rather than page.dummy_request(), so that request.user
# and request.revision_id will be picked up by the wagtail user bar
return page.serve_preview(request, page.default_preview_mode)
@permission_required('wagtailadmin.access_admin')
@require_POST
def lock(request, page_id):
# Get the page
page = get_object_or_404(Page, id=page_id)
# Check permissions
if not page.permissions_for_user(request.user).can_lock():
raise PermissionDenied
# Lock the page
if not page.locked:
page.locked = True
page.save()
# Redirect
redirect_to = request.POST.get('next', None)
if redirect_to and is_safe_url(url=redirect_to, host=request.get_host()):
return redirect(redirect_to)
else:
return redirect('wagtailadmin_explore', page.get_parent().id)
@permission_required('wagtailadmin.access_admin')
@require_POST
def unlock(request, page_id):
# Get the page
page = get_object_or_404(Page, id=page_id)
# Check permissions
if not page.permissions_for_user(request.user).can_lock():
raise PermissionDenied
# Unlock the page
if page.locked:
page.locked = False
page.save()
# Redirect
redirect_to = request.POST.get('next', None)
if redirect_to and is_safe_url(url=redirect_to, host=request.get_host()):
return redirect(redirect_to)
else:
return redirect('wagtailadmin_explore', page.get_parent().id)

View file

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('wagtailcore', '0003_add_uniqueness_constraint_on_group_page_permission'),
]
operations = [
migrations.AddField(
model_name='page',
name='locked',
field=models.BooleanField(default=False, editable=False),
preserve_default=True,
),
]

View file

@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
def add_page_lock_permission_to_moderators(apps, schema_editor):
Group = apps.get_model('auth.Group')
Page = apps.get_model('wagtailcore.Page')
GroupPagePermission = apps.get_model('wagtailcore.GroupPagePermission')
root_pages = Page.objects.filter(depth=1)
try:
moderators_group = Group.objects.get(name='Moderators')
for page in root_pages:
GroupPagePermission.objects.create(
group=moderators_group, page=page, permission_type='lock')
except Group.DoesNotExist:
pass
class Migration(migrations.Migration):
dependencies = [
('wagtailcore', '0004_page_locked'),
]
operations = [
migrations.RunPython(add_page_lock_permission_to_moderators),
]

View file

@ -270,6 +270,8 @@ class Page(six.with_metaclass(PageBase, MP_Node, ClusterableModel, index.Indexed
expire_at = models.DateTimeField(verbose_name=_("Expiry date/time"), help_text=_("Please add a date-time in the form YYYY-MM-DD hh:mm:ss."), blank=True, null=True)
expired = models.BooleanField(default=False, editable=False)
locked = models.BooleanField(default=False, editable=False)
search_fields = (
index.SearchField('title', partial_match=True, boost=2),
index.FilterField('id'),
@ -278,6 +280,7 @@ class Page(six.with_metaclass(PageBase, MP_Node, ClusterableModel, index.Indexed
index.FilterField('content_type'),
index.FilterField('path'),
index.FilterField('depth'),
index.FilterField('locked'),
)
def __init__(self, *args, **kwargs):
@ -939,6 +942,7 @@ class PageRevision(models.Model):
obj.live = self.page.live
obj.has_unpublished_changes = self.page.has_unpublished_changes
obj.owner = self.page.owner
obj.locked = self.page.locked
return obj
@ -992,6 +996,7 @@ PAGE_PERMISSION_TYPE_CHOICES = [
('add', 'Add/edit pages you own'),
('edit', 'Add/edit any page'),
('publish', 'Publish any page'),
('lock', 'Lock/unlock any page'),
]
@ -1160,6 +1165,9 @@ class PagePermissionTester(object):
def can_set_view_restrictions(self):
return self.can_publish()
def can_lock(self):
return self.user.is_superuser or ('lock' in self.permissions)
def can_publish_subpage(self):
"""
Niggly special case for creating and publishing a page in one go.

View file

@ -0,0 +1,115 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from south.utils import datetime_utils as datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'Page.locked'
db.add_column('wagtailcore_page', 'locked',
self.gf('django.db.models.fields.BooleanField')(default=False),
keep_default=False)
def backwards(self, orm):
# Deleting field 'Page.locked'
db.delete_column('wagtailcore_page', 'locked')
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'user_set'", 'blank': 'True', 'to': "orm['auth.Group']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'user_set'", 'blank': 'True', 'to': "orm['auth.Permission']"}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'wagtailcore.grouppagepermission': {
'Meta': {'unique_together': "(('group', 'page', 'permission_type'),)", 'object_name': 'GroupPagePermission'},
'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'page_permissions'", 'to': "orm['auth.Group']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'page': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_permissions'", 'to': "orm['wagtailcore.Page']"}),
'permission_type': ('django.db.models.fields.CharField', [], {'max_length': '20'})
},
'wagtailcore.page': {
'Meta': {'object_name': 'Page'},
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'pages'", 'to': "orm['contenttypes.ContentType']"}),
'depth': ('django.db.models.fields.PositiveIntegerField', [], {}),
'expire_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'expired': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'go_live_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'has_unpublished_changes': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'live': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'numchild': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'owner': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'owned_pages'", 'null': 'True', 'to': "orm['auth.User']"}),
'path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'search_description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'seo_title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'show_in_menus': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'url_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'})
},
'wagtailcore.pagerevision': {
'Meta': {'object_name': 'PageRevision'},
'approved_go_live_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'content_json': ('django.db.models.fields.TextField', [], {}),
'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'page': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['wagtailcore.Page']"}),
'submitted_for_moderation': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'})
},
'wagtailcore.pageviewrestriction': {
'Meta': {'object_name': 'PageViewRestriction'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'page': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'view_restrictions'", 'to': "orm['wagtailcore.Page']"}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '255'})
},
'wagtailcore.site': {
'Meta': {'unique_together': "(('hostname', 'port'),)", 'object_name': 'Site'},
'hostname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_default_site': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'port': ('django.db.models.fields.IntegerField', [], {'default': '80'}),
'root_page': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'sites_rooted_here'", 'to': "orm['wagtailcore.Page']"})
}
}
complete_apps = ['wagtailcore']

View file

@ -0,0 +1,125 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from south.utils import datetime_utils as datetime
from south.db import db
from south.v2 import DataMigration
from django.db import models, connection
from django.db.transaction import set_autocommit
class Migration(DataMigration):
def forwards(self, orm):
if connection.vendor == 'sqlite':
set_autocommit(True)
root_pages = orm['wagtailcore.page'].objects.filter(depth=1)
try:
moderators_group = orm['auth.group'].objects.get(name='Moderators')
for page in root_pages:
orm['wagtailcore.grouppagepermission'].objects.create(
group=moderators_group, page=page, permission_type='lock')
except orm['auth.group'].DoesNotExist:
pass
def backwards(self, orm):
pass
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'user_set'", 'blank': 'True', 'to': "orm['auth.Group']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'user_set'", 'blank': 'True', 'to': "orm['auth.Permission']"}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'wagtailcore.grouppagepermission': {
'Meta': {'unique_together': "(('group', 'page', 'permission_type'),)", 'object_name': 'GroupPagePermission'},
'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'page_permissions'", 'to': "orm['auth.Group']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'page': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_permissions'", 'to': "orm['wagtailcore.Page']"}),
'permission_type': ('django.db.models.fields.CharField', [], {'max_length': '20'})
},
'wagtailcore.page': {
'Meta': {'object_name': 'Page'},
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'pages'", 'to': "orm['contenttypes.ContentType']"}),
'depth': ('django.db.models.fields.PositiveIntegerField', [], {}),
'expire_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'expired': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'go_live_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'has_unpublished_changes': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'live': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'numchild': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'owner': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'owned_pages'", 'null': 'True', 'to': "orm['auth.User']"}),
'path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'search_description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'seo_title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'show_in_menus': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'url_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'})
},
'wagtailcore.pagerevision': {
'Meta': {'object_name': 'PageRevision'},
'approved_go_live_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'content_json': ('django.db.models.fields.TextField', [], {}),
'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'page': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['wagtailcore.Page']"}),
'submitted_for_moderation': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'})
},
'wagtailcore.pageviewrestriction': {
'Meta': {'object_name': 'PageViewRestriction'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'page': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'view_restrictions'", 'to': "orm['wagtailcore.Page']"}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '255'})
},
'wagtailcore.site': {
'Meta': {'unique_together': "(('hostname', 'port'),)", 'object_name': 'Site'},
'hostname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_default_site': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'port': ('django.db.models.fields.IntegerField', [], {'default': '80'}),
'root_page': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'sites_rooted_here'", 'to': "orm['wagtailcore.Page']"})
}
}
complete_apps = ['wagtailcore']
symmetrical = True

View file

@ -299,3 +299,35 @@ class TestPagePermission(TestCase):
self.assertFalse(publishable_pages.filter(id=someone_elses_event_page.id).exists())
self.assertFalse(can_publish_pages)
def test_lock_page_for_superuser(self):
user = get_user_model().objects.get(username='superuser')
christmas_page = EventPage.objects.get(url_path='/home/events/christmas/')
perms = UserPagePermissionsProxy(user).for_page(christmas_page)
self.assertTrue(perms.can_lock())
def test_lock_page_for_moderator(self):
user = get_user_model().objects.get(username='eventmoderator')
christmas_page = EventPage.objects.get(url_path='/home/events/christmas/')
perms = UserPagePermissionsProxy(user).for_page(christmas_page)
self.assertTrue(perms.can_lock())
def test_lock_page_for_editor(self):
user = get_user_model().objects.get(username='eventeditor')
christmas_page = EventPage.objects.get(url_path='/home/events/christmas/')
perms = UserPagePermissionsProxy(user).for_page(christmas_page)
self.assertFalse(perms.can_lock())
def test_lock_page_for_non_editing_user(self):
user = get_user_model().objects.get(username='admin_only_user')
christmas_page = EventPage.objects.get(url_path='/home/events/christmas/')
perms = UserPagePermissionsProxy(user).for_page(christmas_page)
self.assertFalse(perms.can_lock())