From 65b44073379de4c9657f8047da8064fd437247aa Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Fri, 1 Nov 2013 11:50:49 +0100 Subject: [PATCH] FIX "Draft" stage to fix dev/build, Versioned docs (fixes #2619) --- dev/DevelopmentAdmin.php | 4 ++++ docs/en/changelogs/3.0.9.md | 35 +++++++++++++++++++++++++++++++++++ docs/en/topics/versioning.md | 27 +++++++++++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 docs/en/changelogs/3.0.9.md diff --git a/dev/DevelopmentAdmin.php b/dev/DevelopmentAdmin.php index 9d707fc9e..fc2e7d614 100644 --- a/dev/DevelopmentAdmin.php +++ b/dev/DevelopmentAdmin.php @@ -72,6 +72,10 @@ class DevelopmentAdmin extends Controller { } } + // Backwards compat: Default to "draft" stage, which is important + // for tasks like dev/build which call DataObject->requireDefaultRecords(), + // but also for other administrative tasks which have assumptions about the default stage. + Versioned::reading_stage('Stage'); } public function index() { diff --git a/docs/en/changelogs/3.0.9.md b/docs/en/changelogs/3.0.9.md new file mode 100644 index 000000000..089cde8f8 --- /dev/null +++ b/docs/en/changelogs/3.0.9.md @@ -0,0 +1,35 @@ +# 3.0.9 + +## Overview + +### Default current Versioned "stage" to "Live" rather than "Stage" + +Previously only the controllers responsible for page and CMS display +(`LeftAndMain` and `ContentController`) explicitly set a stage through +`Versioned::choose_site_stage()`. Unless this method is called, +the default stage will be "Stage", showing draft content. +Any direct subclasses of `Controller` interacting with "versioned" objects +are vulnerable to exposing unpublished content, unless `choose_site_stage()` +is called explicitly in their own logic. + +In order to provide more secure default behaviour, we have changed +`choose_site_stage()` to be called on all requests, defaulting to the "Live" stage. +If your logic relies on querying draft content, use `Versioned::reading_stage('Stage')`. + +Important: The `choose_site_stage()` call only deals with setting the default stage, +and doesn't check if the user is authenticated to view it. As with any other controller logic, +please use `DataObject->canView()` to determine permissions. + + :::php + class MyController extends Controller { + private static $allowed_actions = array('showpage'); + public function showpage($request) { + $page = Page::get()->byID($request->param('ID')); + if(!$page->canView()) return $this->httpError(401); + // continue with authenticated logic... + } + } + +### API Changes + + * 2013-08-03 [0e7231f](https://github.com/silverstripe/sapphire/commit/0e7231f) Disable discontinued Google Spellcheck in TinyMCE (Ingo Schommer) \ No newline at end of file diff --git a/docs/en/topics/versioning.md b/docs/en/topics/versioning.md index ebd98825c..61f20b6da 100644 --- a/docs/en/topics/versioning.md +++ b/docs/en/topics/versioning.md @@ -156,6 +156,33 @@ The `$Content` variable contain the published content by default, and only preview draft content if explicitly requested (e.g. by the "preview" feature in the CMS). If you want to force a specific stage, we recommend the `Controller->init()` method for this purpose. +### Controllers + +The current stage for each request is determined by `VersionedRequestFilter` before +any controllers initialize, through `Versioned::choose_site_stage()`. +It checks for a `Stage` GET parameter, so you can force +a draft stage by appending `?stage=Stage` to your request. The setting is "sticky" +in the PHP session, so any subsequent requests will also be in draft stage. + +Important: The `choose_site_stage()` call only deals with setting the default stage, +and doesn't check if the user is authenticated to view it. As with any other controller logic, +please use `DataObject->canView()` to determine permissions, and avoid exposing unpublished +content to your users. + + :::php + class MyController extends Controller { + private static $allowed_actions = array('showpage'); + public function showpage($request) { + $page = Page::get()->byID($request->param('ID')); + if(!$page->canView()) return $this->httpError(401); + // continue with authenticated logic... + } + } + +The `ContentController` class responsible for page display already has this built in, +so your own `canView()` checks are only necessary in controllers extending directly +from the `Controller` class. + ## Recipes ### Trapping the publication event