diff --git a/docs/en/03_Upgrading/index.md b/docs/en/03_Upgrading/index.md
index dbdeb6ba3..dcd5fd0cb 100644
--- a/docs/en/03_Upgrading/index.md
+++ b/docs/en/03_Upgrading/index.md
@@ -3,4 +3,1174 @@ introduction: The following guides will help you upgrade your project or module
The following guides will help you upgrade your project or module to SilverStripe 4. Upgrading a module is very similar to upgrading a Project. The module upgrade guide assumes familiarity with the project upgrade guide.
-[CHILDREN]
\ No newline at end of file
+[CHILDREN]
+
+SilverStripe applications should be kept up to date with the latest security releases. Usually an update or upgrade to
+your SilverStripe installation means overwriting files, flushing the cache and updating your database schema.
+
+## Understanding and planning your upgrade {#planning}
+
+How easy will it be to update my project? It's a fair question, and sometimes a difficult one to answer.
+
+* SilverStripe follows _semantic versioning_ (see our [release process](/contributing/release_process) for details).
+ * "Major" releases introduces API change that may break your application.
+ * "Minor" releases (x.y) introduces API changes in a backward compatible way and can mark some API as deprecated.
+ * "Patch" releases (x.y.z) fix bugs without introducing any API changes.
+* If you've made custom branches of SilverStripe core, or any thirdparty module, upgrades are going to be more complex.
+* More custom features mean more work to re-test all of those features, and adapt to API changes in core.
+* Customisations of a well defined type - such as custom page types or custom blog widgets -
+ are going to be easier to upgrade than customisations that modify deep system internals like rewriting SQL queries.
+
+### Overview of changes
+
+There are some fundamental changes in SilverStripe 4:
+
+* PHP 5.6 is now the minimum required version and up to PHP 7.2 is supported.
+* SilverStripe is now even more modular which allows you to remove functionality your project might not need.
+* Common functionality sets can now be installed via SilverStripe _recipes_.
+* SilverStripe modules can now be installed in the `vendor/` folder along with your regular PHP packages.
+* All classes are namespaced: You have to use these, but can decide if you namespace your project code.
+* PHP _traits_ replace a few core classes (e.g. `Object`) and make it easy to apply common patterns
+* Public files can now be served from a `public/` webroot for added security.
+* Versioning is more powerful through an "ownership" concept, and available for all DataObject classes.
+* Changes across objects can be collected in a "campaign" for batch publication.
+* GraphQL is now the favourite way of creating web services with SilverStripe.
+* Asset management has been completely redone with a brand new React-based UI, protected draft files and versioning.
+* Parts of the CMS UI are now build in React and Bootstrap instead of Entwine and custom CSS.
+* PSR-4 auto-loading is supported for modules and for your project code.
+
+[Learn more about major API changes introduced by SilverStripe 4](#list-of-major-api-changes),
+and dig into the changelogs for [4.0.0](/changelogs/4.0.0), [4.1.0](/changelogs/4.1.0) and [4.2.0](/changelogs/4.2.0).
+
+### Using recipes instead of requiring individual modules
+The SilverStripe CMS and SilverStripe Framework are becoming more modular. Many of the secondary features contained in SilverStripe CMS 3 and SilverStripe Framework 3 have been moved to separate modules.
+
+SilverStripe 4 introduces the concept of _recipes_. Recipes are a combination of modules to achieve a common pattern.
+
+Read the [Switching to recipes](#switching-to-recipes) section of this guide for more information about how recipes work.
+
+### Automating your upgrades using the SilverStripe Upgrader tool
+We've developed [an upgrader tool](https://github.com/silverstripe/silverstripe-upgrader) which you can use to help
+with the upgrade process. The upgrader is unlikely to completely upgrade your project, however it can take care of the most tedious part of the upgrade.
+It can also be use to upgrade your existing SilverStripe 4 project to a newer minor release.
+
+## Step 0 - Pre-requisites and background work {#step0}
+
+Before you begin the upgrade process, make sure you meet these pre-requisites.
+
+### Back up your files and database
+
+* Set up your codebase in your development environment.
+* Backup your database content.
+* Backup your codebase (use version control if possible).
+
+
+Never update a website on the live server. Get it working on a development copy first!
+
+
+### Install composer
+
+[Composer](http://getcomposer.org) is a tool for managing PHP dependencies. SilverStripe 4 requires composer version _1.1_ or greater. Read the [SilverStripe _Getting started_ guide](/getting_started/composer) for more details.
+
+We recommend using `recipe-cms` in your `composer.json` file to help you keep up to date and run `composer update`.
+
+```json
+{
+ "require": {
+ "silverstripe/recipe-cms": "^4"
+ }
+}
+```
+
+This will also add extra dependencies, such as the `admin`, `asset-admin`, `reports`, `errorpage` and `siteconfig`
+modules.
+
+If you want more granular control over what gets installed,
+check out the [recipe plugin repository](https://github.com/silverstripe/recipe-plugin)
+as well as the `composer.json` files in [recipe-core](https://github.com/silverstripe/recipe-core) and
+[recipe-cms](https://github.com/silverstripe/recipe-cms).
+
+For a description on how to handle issues with pre-existing composer installs or upgrading other modules, read
+through the [Step 1 - Upgrade your dependencies](#step1) section.
+
+### Install the upgrader tool (optional)
+Using the upgrader is not mandatory, but it can speed up the process. Although SilverStripe 4 can run in both PHP 5.6 and PHP 7, the upgrader itself requires PHP 7.1.
+
+The upgrader is available as a phar executable.
+
+To install the PHAR executable:
+
+1. [Download the upgrader as a PHAR executable](https://silverstripe.github.io/silverstripe-upgrader/upgrade-code.phar) or `wget https://silverstripe.github.io/silverstripe-upgrader/upgrade-code.phar`
+2. Make the file executable `chmod +x upgrade-code.phar`
+3. Move the file to a folder in your path, for example `sudo mv upgrade-code.phar /usr/local/bin/upgrade-code`
+
+
+Each command in the upgrader has somewhat different arguments. However, most of them accept these two options:
+* `--write` which tells the upgrader to apply changes to your code base
+* `--root-dir` which can be use to explicitly specify the root of your project — if not specified the current working directory is assume to be the root of the project.
+
+You can run `upgrade-code help` to get more information about the upgrader or `upgrade-code help command-name` to information about a specific command.
+
+
+Sample upgrader commands in this guide assume your working directory is the root of your SilverStripe project. You'll need to use the `--root-dir` flag if that's not the case.
+
+
+#### Install the upgrader globally with composer
+
+You can install the upgrader globally with composer. This can make it easier to update to newer releases, however you can get dependency conflicts if you have other packages installed globally.
+
+To install the upgrader globally run this command.
+
+```bash
+composer global require silverstripe/upgrader
+```
+
+Add your global composer bin directory to your path. On *nix system, this directory is normally located at `$HOME/.composer/vendor/bin`. On Windows system, this directory is normally located at `C:\Users\\AppData\Roaming\Composer\vendor\bin`. You can find the exact location by running this command:
+```bash
+composer global config bin-dir
+```
+
+On *nix system, the following command will add your global composer bin directory to your path if `bash` is your default shell environment:
+```bash
+echo 'export PATH=$PATH:~/.composer/vendor/bin/' >> ~/.bash_profile
+source ~/.bash_profile
+```
+
+### Running all the upgrader commands in this guide in on line
+
+The upgrader comes with an `all` command. This command will attempt to run all the upgrader commands in the same order as this guide. This is unlikely to work on your first try, but can be a good way to get started without going through this entire guide.
+
+```bash
+upgrade-code all --namespace="App\\Web" --psr4
+```
+
+* `--recipe-core-constraint` defines your SilverStripe release version (optional, will default to the most recent stable release).
+* `--namespace` allows you to specify how your project will be namespaced (optional).
+* `--psr4` allows you to specify that your project structure respect the PSR-4 standard and to use sub-namespaces.
+* `--skip-add-namespace` allows you to skip the `add-namespace` command.
+* `--skip-reorganise` allows you to skip the `reorganise` command.
+* `--skip-webroot` allows you to skip the `webroot` command.
+
+### Branching your project
+
+Setting a dedicated branch in your source control system to track your upgrade work can help you manage your upgrade. If you're upgrading a big project, you should consider creating individual branches or commits for each step.
+
+## Step 1 - Upgrade your dependencies {#step1}
+
+The first step is to update your dependencies' constraints in your `composer.json` file to require the latest version of modules.
+
+### Automatically upgrade dependencies with the `recompose` upgrader command
+
+If you've installed the upgrader, you can use the `recompose` command to help you upgrade your dependencies. This command will try to:
+* upgrade your PHP constraint
+* upgrade core SilverStripe modules to their version 4 equivalent
+* switch to recipes where possible
+* find SilverStripe 4 compatible versions of third party modules.
+
+Take for example the following SilverStripe 3 `composer.json` file.
+```json
+{
+ "name": "app/cms-website",
+ "description": "The Example website project.",
+ "license": "BSD-3",
+ "require": {
+ "php": ">=5.3.3",
+ "silverstripe/cms": "3.6.5@stable",
+ "silverstripe/framework": "3.6.5@stable",
+ "silverstripe/reports": "3.6.5@stable",
+ "silverstripe/siteconfig": "3.6.5@stable",
+ "dnadesign/silverstripe-elemental": "^1.8.0"
+ }
+}
+```
+
+You can upgrade the `composer.json` file with this command:
+```bash
+upgrade-code recompose --write
+```
+
+You can add a `--recipe-core-constraint` flag to target a specific version of `silverstripe/recipe-core`. By default, the project will be upgraded to the latest stable version. You can use the `--strict` option if you want to use more conservative version constraints. Omit the `--write` flag to preview your changes.
+
+Your upgraded `composer.json` file will look like this.
+```json
+{
+ "name": "app/cms-website",
+ "description": "The Example website project.",
+ "license": "BSD-3",
+ "require": {
+ "dnadesign/silverstripe-elemental": "^2.1",
+ "php": ">=5.6",
+ "silverstripe/recipe-cms": "^4.1"
+ }
+}
+```
+
+If the `recompose` command can't find a compatible version for one of your module, it will keep this dependency in your `composer.json` file with its existing constraint.
+
+[Continue to Step 2](#step2)
+
+### Manually upgrading your dependencies
+
+The instruction in this section assumed you'll be editing your `composer.json` file in a text editor.
+
+#### Switching to recipes
+
+Where possible, we recommend you use recipes.
+
+If your SilverStripe 3 project requires the `silverstripe/cms` module, replace that dependency with `silverstripe/recipe-cms`. The version constraint for `silverstripe/recipe-cms` must match your targeted version of SilverStripe:
+* `~4.0.0` to upgrade to SilverStripe 4.0
+* `~4.1.0` to upgrade to SilverStripe 4.1
+* `~4.2.0` to upgrade to SilverStripe 4.2
+* and so on.
+
+If your SilverStripe 3 project requires the `silverstripe/framework` module without `silverstripe/cms`, replace `silverstripe/framework` with `silverstripe/recipe-core`. The version constraint for `silverstripe/recipe-core` must match your targeted version of SilverStripe:
+* `~4.0.0` to upgrade to SilverStripe 4.0
+* `~4.1.0` to upgrade to SilverStripe 4.1
+* `~4.2.0` to upgrade to SilverStripe 4.2
+* and so on.
+
+The following modules are implicitly required by `silverstripe/recipe-core`. They can be removed from your `composer.json` dependencies if you are using `silverstripe/recipe-core` or `silverstripe/recipe-cms`.
+* `silverstripe/framework`
+* `silverstripe/config`
+* `silverstripe/assets`
+
+The following modules are implicitly required by `silverstripe/recipe-cms`. They can be removed from your `composer.json` dependencies if you are using `silverstripe/recipe-cms`.
+* `silverstripe/admin`
+* `silverstripe/asset-admin`
+* `silverstripe/campaign-admin`
+* `silverstripe/cms`
+* `silverstripe/errorpage`
+* `silverstripe/reports`
+* `silverstripe/graphql`
+* `silverstripe/siteconfig`
+* `silverstripe/versioned`
+* `silverstripe/recipe-core`
+
+Take for example the following SilverStripe 3 `composer.json`.
+```json
+{
+ "name": "app/cms-website",
+ "require": {
+ "silverstripe/cms": "3.6.5@stable",
+ "silverstripe/framework": "3.6.5@stable",
+ "silverstripe/reports": "3.6.5@stable",
+ "silverstripe/siteconfig": "3.6.5@stable"
+ }
+}
+```
+
+After switching to SilverStripe 4 recipes, the `composer.json` file should look like this.
+```json
+{
+ "name": "app/cms-website",
+ "require": {
+ "silverstripe/recipe-cms": "~4.1.0"
+ }
+}
+```
+
+#### Explicitly defining your dependencies
+If you would rather explicitly define your dependencies, you can do so. Update the `silverstripe/framework` constraint and `silverstripe/cms` constraint to match your targeted minor version of SilverStripe 4. If you use `silverstripe/reports` and `silverstripe/siteconfig`, update their constraints as well.
+
+In most cases, you'll also want to require the same modules as the equivalent recipes. If you don't, your users will likely lose some features after the upgrade is completed.
+
+Take for example the following SilverStripe 3 `composer.json`.
+```json
+{
+ "name": "app/cms-website",
+ "require": {
+ "silverstripe/cms": "3.6.5@stable",
+ "silverstripe/framework": "3.6.5@stable",
+ "silverstripe/reports": "3.6.5@stable",
+ "silverstripe/siteconfig": "3.6.5@stable"
+ }
+}
+```
+
+After switching to SilverStripe 4 and explicitly defining your dependencies, the `composer.json` file should look like this.
+```json
+{
+ "name": "app/cms-website",
+ "require": {
+ "silverstripe/cms": "~4.1.0",
+ "silverstripe/framework": "~4.1.0",
+ "silverstripe/reports": "~4.1.0",
+ "silverstripe/siteconfig": "~4.1.0",
+ "silverstripe/admin": "~1.1.0",
+ "silverstripe/asset-admin": "~1.1.0",
+ "silverstripe/campaign-admin": "~1.1.0",
+ "silverstripe/errorpage": "~1.1.0",
+ "silverstripe/graphql": "~1.1.0",
+ "silverstripe/versioned": "~1.1.0"
+ }
+}
+```
+
+#### Updating third party dependencies
+If you project requires third party modules, you'll need to adjust their associated constraint. This will allow you to retrieve a SilverStripe 4 compatible version of the module.
+
+[Look up the module on Packagist](https://packagist.org/) to see if a SilverStripe 4 version is provided.
+
+Take for example the following SilverStripe 3 `composer.json`.
+```json
+{
+ "name": "app/cms-website",
+ "require": {
+ "silverstripe/framework": "3.6.5@stable",
+ "silverstripe/cms": "3.6.5@stable",
+ "dnadesign/silverstripe-elemental": "^1.8.0"
+ }
+}
+```
+
+Looking at the [Packagist entry for `dnadesign/silverstripe-elemental`](https://packagist.org/packages/dnadesign/silverstripe-elemental#2.0.0), you can see that versions 2.0.0 and above of this module are compatible with SilverStripe 4. So you can update that constraint to `^2.0.0`.
+
+Alternatively, you can set a very permissive constraint and let composer find a SilverStripe 4 compatible version. After you're done updating your dependencies, make sure you adjust your constraints to be more specific.
+
+Once you've updated your third-party modules constraints, try updating your dependencies by running `composer update`. If composer can't resolve all your dependencies it will throw an error.
+
+### Resolving conflicts
+
+You'll likely have some conflicts to resolve, whether you've updated your dependencies with the upgrader or manually.
+
+Running a `composer update` will tell you which modules are conflicted and suggested alternative combinations of modules that might work.
+
+The most typical reason for a conflict is that the maintainer of a module hasn't released a version compatible with SilverStripe 4.
+
+If the maintainer of the module is in the process of upgrading to SilverStripe 4, a development version of the module might be available. In some cases, it can be worthwhile to look up the repository of the module or to reach out to the maintainer.
+
+
+If you're going to install development version of third party modules, you should consider adding the following entries to your `composer.json` file.
+
+```json
+{
+ // ...
+ "minimum-stability": "dev",
+ "prefer-stable": true,
+ // ...
+}
+```
+
+
+To resolve a conflict you can either:
+* fork the affected module and upgrade it yourself. Don't forget to send a pull request to the original module!
+* Integrate the affected module into your project's codebase
+* Remove the module from your project, if it is not essential
+
+To integrate a third party module in your project, remove it from your `composer.json` file and from your `.gitignore` file. Then track the module's codebase in your project source control. You'll need to upgrade the module's code to be compatible with SilverStripe 4.
+
+
+If you're taking the time to upgrade a third party module, consider doing a pull request against the original project so other developers can benefit from your work or releasing your fork as a seperate module.
+
+[Learn about how to publish a SilverStripe module](/developer_guides/extending/how_tos/publish_a_module)
+
+
+### Finalising your dependency upgrade
+
+Once you've resolved all conflicts in your `composer.json` file, `composer update` will be able to run without errors.
+
+This will install your new dependencies. You'll notice many of the folders in the root of your project will disappear. That's because SilverStripe 4 modules can be installed in the vendor folder like generic PHP packages.
+
+If you've decided to use recipes, some generic files will be copied from the recipe into your project. The `extra` attribute in your `composer.json` file will be updated to keep track of those new files.
+
+This is a good point to commit your changes to your source control system before moving on to the next step.
+
+## Step 2 - Update your environment configuration {#env}{#step2}
+
+The php configuration `_ss_environment.php` file has been replaced with a non-executable
+`.env` file. It follows a syntax similar to a `.ini` file for key/value pair assignment. Your `.env` file may be placed in your project root, or one level above your project root ([details](/getting_started/environment_management/))
+
+### Automatically convert `_ss_environment.php` to `.env`
+
+If you have installed the upgrader tool, you can use the `environment` command to generate a valid `.env` file from your existing `_ss_environment.php` file.
+
+```bash
+upgrade-code environment --write
+```
+
+If your `_ss_environment.php` file contains unusual logic (conditional statements or loops), you will get a warning. `upgrade-code` will still try to convert the file, but you should double-check the output. Omit the `--write` flag to do a dry-run.
+
+[Continue to "Cleaning up `mysite/_config.php`"](#env-config-cleanup)
+
+### Manually convert `_ss_environment.php` to `.env`
+
+Create a `.env` file in the root of your project. Replace `define` statements from `_ss_environment.php` with `KEY=VALUE` pairs in `.env`.
+
+Most SilverStripe 3 environment variables have been carried over to SilverStripe 4. See [Environment Management docs](/getting_started/environment_management/) for the full list of available variables. Your `.env` file can contain environment variables specific to your project as well.
+
+The global array `$_FILE_TO_URL_MAPPING` has been removed and replaced with the `SS_BASE_URL` environment variable. `SS_BASE_URL` expects an absolute url with an optional protocol. The following are values would be valid entries for `SS_BASE_URL`:
+* `http://localhost/`
+* `https://localhost/`
+* `//localhost/`
+
+For example, take the following `_ss_environment.php` file.
+```php
+get('ProductService');
+```
+
+Execute the upgrade command with this command.
+
+```bash
+upgrade-code upgrade ./mysite/ --write
+```
+
+If you omit the `--write` flag you will get a preview of what change the upgrader will apply to your codebase. This can be helpful if you if you are tweaking your `.upgrade.yml` or if you are trying to identify areas where you should add a `@skipUpgrade` statement,
+
+You can also tweak which rules to apply with the `--rule` flag: `code`, `config`, and `lang`. For example, the following command will only upgrade `lang` and `config` files:
+```bash
+upgrade-code upgrade ./mysite/ --rule=config --rule=lang
+```
+
+The `upgrade` command can alter big chunks of your codebase. While it works reasonably well in most use case, you should not trust it blindly. You should take time to review all changes applied by the `upgrade` command and confirm you are happy with them.
+
+[Continue to "Finalising namespace updates"](#namespace-finalise)
+
+### Manually update namespaced references
+
+If you decide to update your namespace references by hand, you'll need to go through the entire code base and update them all from the old non-namespaced SilverStripe classes to the new namespaced equivalent. If you are referencing classes from third party modules that have been namespaced, you'll need to update those as well.
+
+#### Update explicit references to classes in your code
+
+Wherever your code explicitly references a SilverStripe class, it will need to be updated to the new namespaced equivalent. You can either update the reference to use the fully qualified name of the class or you can add a `use` statement to your file.
+
+For example take the following SilverStripe 3 class. `DataObject` and `FieldList` need to point to their namespace equivalents.
+
+```php
+ 'Image'
+ ];
+
+ private static $has_many = [
+ 'Tags' => 'BlogPost'
+ ];
+
+
+ public function getShippingCost()
+ {
+ return Injector::inst('ProductService')->calculateCost($this);
+ }
+}
+```
+
+`Image`, `BlogPost`, and `ProductService` represent classes. Those strings need to be updated to specify the full namespace.
+
+The best way of achieving this is to use the [`::class` PHP magic class constant](http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.class.class) which will return the fully qualified name of a class.
+
+Our example could be update to:
+```php
+ Image::class
+ ];
+
+ private static $has_many = [
+ 'Tags' => BlogPost::class
+ ];
+
+
+ public function getShippingCost()
+ {
+ return Injector::inst(ProductService::class)->calculateCost($this);
+ }
+}
+```
+
+Alternatively, you can spell out the full qualified name of each class in a string. For example, `'Image'` would become `'SilverStripe\\Assets\\Image'`. Note the use of the _double backslash_ — this is necessary because the backslash is an escape character.
+
+#### Update references to classes in your YML config
+
+YAML configuration files can reference SilverStripe classes. Those references also need to use the fully qualified name of each class.
+
+Take for example the following SilverStripe 3 YAML configuration file.
+
+```yaml
+Injector:
+ ProductService:
+ properties:
+ RoadRunnerSpeed: 99999999
+ CoyoteSpeed: 1
+
+BlogPost:
+ extensions:
+ - HasOneExplosiveTennisBallExtension
+
+Email:
+ admin_email: no-reply@example.com
+```
+
+In SilverStripe 4, this will become:
+```yaml
+SilverStripe\Core\Injector\Injector:
+ App\Web\ProductService:
+ properties:
+ RoadRunnerSpeed: 99999999
+ CoyoteSpeed: 1
+
+SilverStripe\Blog\Model\BlogPost:
+ extensions:
+ - App\Web\Extensions\HasOneExplosiveTennisBallExtension
+
+SilverStripe\Control\Email\Email:
+ admin_email: no-reply@example.com
+```
+
+#### Update references to classes in your language files
+
+Translation keys are normally tied to classes. If you override SilverStripe's default translation or if you are localising your own project, you'll need to update those references to use the fully qualified name of each class.
+
+For example, let's say you had the following translation file in `mysite/lang/eng.yml`.
+```yaml
+en:
+ Member:
+ SINGULARNAME: Coyote
+ RoadRunner:
+ SALUTATION: Beep Beep
+```
+
+In SilverStripe 4, it would become:
+```yaml
+en:
+ SilverStripe\Security\Member:
+ SINGULARNAME: Coyote
+ App\Web\RoadRunner:
+ SALUTATION: Beep Beep
+```
+
+### Finalising namespace updates {#namespace-finalise}
+You'll need to perform the following steps manually, even if you've used the automated rewrite of namespaces.
+
+DataObject database tables will default to use a namespaced name. For example, if you have a class under `App\Web\Products\ExplosiveTennisBall` that extends `DataObject`, the matching table in your database will be called `App_Web_Products_ExplosiveTennisBall`.
+You can define a `private static $table_name` property on your DataObjects to use more convenient table names.
+For example, `private static $table_name = 'ExplosiveTennisBall';`.
+
+In your PHP code, calls to the `_t()` method should be updated to use the full namespace of the target class.
+
+```php
+ 'Products']);
+
+# New SilverStripe 4
+use SilverStripe\CMS\Controllers\CMSMain;
+// ...
+$translation = _t(CMSMain::class .'.ACCESS', "Access to ''{title}'' section", ['title' => 'Products']);
+```
+
+If you're calling `_t()` to retrieve a translation for the current class, you can also use `__CLASS__` or `self::class`. For example:
+```php
+
+Avoid using `static::class` or `parent::class` to retrieve translated string. It will retrieve unpredictable values bases on the class inheritance.
+
+
+If your template files contain translatable strings, they also need to be updated to referenced the namespaced classes.
+For example, `<%t Member.SINGULARNAME 'Member' %>` would become `<%t SilverStripe\Security\Member.SINGULARNAME 'Member' %>`.
+
+Your codebase should now be referencing valid SilverStripe 4 classes. This means that your classes can be loaded at runtime. However, your codebase will still be using an outdated API.
+This is a good point to commit your changes to your source control system before moving on to the next step.
+
+## Step 5 - Updating your codebase to use SilverStripe 4 API {#step5}
+
+This is the most intricate and potentially time-consuming part of the upgrade. It involves going through your entire codebase to remove references to deprecated APIs and update your project logic.
+
+### Automatically update deprecated API references with the `inspect` command
+
+The upgrader has an `inspect` command that can flag deprecated API usage, and in some cases, update your codebase to the SilverStripe 4 equivalent. This does require you to carefully review each change and warning to make sure the updated logic still work as intended. Even so, it is a huge time-saver compared to reviewing your code base manually.
+
+Note that the `inspect` command loads your files with PHP interpreter. So basic syntax errors — for example, extending a class that does not exists — will cause an immediate failure. For this reason, you need to complete [Step 4 - Update codebase with references to newly namespaced classes](#step4) before running the `inspect` command.
+
+```bash
+upgrade-code inspect ./mysite/ --write
+```
+
+You can omit the `--write` flag if you just want to view the proposed changes without applying them. You can run the command on a specific subdirectory or file. This can be more manageable if you have a big project to go through.
+
+Like the `upgrade` command, `inspect` gets its list of API changes from `.upgrade.yml` files. So you may get upgrade suggestions and substitution from third party modules. You can even include your own project specific changes in your `.upgrade.yml` if you want.
+
+#### Sample output of the `inspect` command
+Here's some sample output of what you might get back the `inspect` command.
+
+```bash
+upgrade-code inspect ./mysite/Models/Coyote.php
+
+Running post-upgrade on "/var/www/SS_example/mysite/code/Models/Coyote.php"
+[2018-06-06 13:35:38] Applying ApiChangeWarningsRule to Coyote.php...
+modified: Coyote.php
+@@ -68,7 +68,7 @@
+ {
+ // Getting a reference to Coyote's list of crazy ideas
+- $manyManyRelation = $this->manyManyComponent('CrazyIdeas');
++ $manyManyRelation = $this->getSchema()->manyManyComponent('CrazyIdeas');
+ return $manyManyRelation;
+ }
+
+Warnings for Coyote.php:
+ - Coyote.php:20 SS_Cache: Using symfony/cache now (https://docs.silverstripe.org/en/4/changelogs/4.0.0#cache)
+ - Coyote.php:42 SilverStripe\Control\Director::setUrlParams(): Method removed
+ - Coyote.php:71 SilverStripe\ORM\DataObject->manyManyComponent(): DataObject->manyManyComponent() moved to DataObjectSchema. Access through getSchema(). You must manually add static::class as the first argument to manyManyComponent()
+Changes not saved; Run with --write to commit to disk
+```
+
+### Manually update deprecated API references
+
+SilverStripe 4 introduces many API changes. To update deprecated API references manually, you have to go through each one of your project files.
+Read the changelogs for [4.0.0](/changelogs/4.0.0/), [4.1.0](/changelogs/4.1.0/) and [4.2.0](/changelogs/4.2.0/)
+for a comprehensive overview.
+
+### Finalising the deprecated API update
+At this stage, your site should be using only SilverStripe 4 API logic.
+
+You still have some minor clean up tasks and configuration tweaks to apply, but you're almost done.
+
+This is a good point to commit your changes to your source control system before moving on to the next step.
+
+## Step 6 - Update your entry point {#step6}
+The location of SilverStripe's _entry file_ has changed. Your project and server environment will need
+to adjust the path to this file from `framework/main.php` to `index.php`.
+
+### Update your `index.php` file
+You can get a copy of the SilverStripe 4 `index.php` file at
+`vendor/silverstripe/recipe-core/public/index.php`.
+
+If you've created your own `index.php` or modified version of `main.php`,
+you'll need to reconcile those changes with the `index.php` file you got from `recipe-core`.
+Otherwise, just use the generic `index.php` file `recipe-core` provides.
+
+Copy your new `index.php` to your project's web root. Unlike SilverStripe 3, `index.php` must be present in your web root.
+
+### Update your server configuration
+If you're using a `.htaccess` file or `web.config` file to handle your server configuration, you can get the generic SilverStripe 4 version of those file from
+`vendor/silverstripe/recipe-core/public`.
+
+Just like `index.php`, if you've modified your server configuration file from the one that shipped with SilverStripe 3, you'll need to reconcile your changes into the version retrieve from `recipe-core`.
+
+[Refer to the installation instruction for your platform](/getting_started/installation/) if your server configuration is not managed via a `.htaccess` or `web.config` file.
+
+### Finalising the entry point upgrade
+
+At this stage, you could in theory run your project in SilverStripe 4.
+
+This is a good point to commit your changes to your source control system before moving on to the next step.
+
+## Step 7 - Update project structure (optional) {#step7}
+SilverStripe 4 introduces a new recommended project structure ([details](/changelogs/4.2.0#app-folder-name)).
+Adopting the recommended project structure is optional, but will become mandatory in SilverStripe 5.
+
+[Skip to Step 8](#step8)
+
+### Automatically switch to the new structure with the `reorganise` command
+The reorganise command can automatically update your project to use the new recommended structure.
+
+It will search your code and find any occurrence of `mysite`. It won't replace those occurrence with `app` however.
+
+```bash
+upgrade-code reorganise --write
+```
+
+Omit the `--write` flag if you just want to preview your changes
+
+### Manually switch to the new structure
+
+Simply rename your `mysite` fold to `app`. Then rename `app/code` to `app/src`.
+
+### Finalising the reorganise structure
+
+If you've implemented the new PSR-4 auto-loading logic in your `composer.json` file you'll need to update your namespace mapping.
+
+For example, let's say you had the following autoload attribute in your `composer.json`.
+```json
+{
+ // ...
+ "autoload": {
+ "classmap": [
+ "mysite/code/Page.php",
+ "mysite/code/PageController.php"
+ ],
+ "psr-4": {
+ "App\\Web\\": "mysite/code/"
+ }
+ },
+ // ...
+}
+```
+
+It will become this:
+```json
+{
+ // ...
+ "autoload": {
+ "classmap": [
+ "app/src/Page.php",
+ "app/src/PageController.php"
+ ],
+ "psr-4": {
+ "App\\Web\\": "app/src/"
+ }
+ },
+ // ...
+}
+```
+
+You'll need to update the `project` attribute for your `ModuleManifest` in your `app/src/mysite.yml` file. It should now look something like this:
+```yaml
+SilverStripe\Core\Manifest\ModuleManifest:
+ project: app
+```
+
+At this stage, your project should be functional with the recommended project structure.
+Note, that if you've explicitly reference any static assets (images, css, js) under `mysite`, you'll need to rewrite those references.
+
+This is a good point to commit your changes to your source control system before moving on to the next step.
+
+## Step 8 - Switch to public web-root (optional){#step8}
+
+SilverStripe 4.1 introduces the concept of _public web-root_ this allows you to move
+all publicly accessible assets under a `public` folder ([details](/changelogs/4.1.0#public-folder)).
+This has security benefits as it minimises the possibility that files that are not meant to be access directly get accidentally exposed.
+
+This step is optional and requires SilverStripe 4.1 or greater. It will become mandatory in SilverStripe 5.
+
+[Skip to Step 9](#step9)
+
+### Automatically switch to the public web root
+
+The `webroot` upgrader command will automatically move your files for you.
+
+```bash
+upgrade-code webroot --write
+```
+
+Omit the `--write` flag if you want to preview the change.
+
+If you are using a modified `index.php`, `.htaccess`, or `web.config`, you will get a warning.
+
+### Manually switch to using the public web root
+* Create a `public` folder in the root of your project
+* Move the following files and folder to your new public folder
+ * `index.php`
+ * `.htaccess`
+ * `webconfig.php`
+ * `assets`
+ * Any `favicon` files
+ * Other common files that should be accssible in your project webroot (example: `robots.txt`)
+* Delete the root `resources` directory if present.
+* Run the following command `composer vendor-expose` to make static assets files accessible via the `public` directory.
+
+If you are upgrading from SilverStripe 4.0 to SilverStripe 4.1 (or above), you'll need to update `index.php` before moving it to the public folder. You can get a copy of the generic `index.php` file from `vendor/silverstripe/recipe-core/public`. If you've made modifications to your `index.php` file, you'll need to replicate those into the new `public/index.php` file.
+
+### Finalising the web root migration
+You'll need to update your server configuration to point to the public directory rather than the root of your project.
+Update your `.gitignore` file so `assets` and `resources` are still ignored when located under the `public` folder.
+Your project should still be functional, although you may now be missing some static assets.
+
+This is a good point to commit your changes to your source control system before moving on to the next step.
+
+## Step 9 - Move away from hardcoded paths for referencing static assets {#step9}
+
+SilverStripe 4 introduces a new way to reference static assets like images and css.
+This enable innovations like moving SilverStripe module [vendor folder](/changelogs/4.0.0#vendor-folder) or the [public web root](/changelogs/4.1.0#public-folder).
+
+This change is mandatory if you've completed either
+[step 7](#step7) (update project structure) or [step 8](#step8) (switch to public web-root).
+If you have skipped these steps, it is strongly recommended, but not mandatory.
+
+### Exposing your project static assets
+If you have folders under `app` or `mysite` that need to be accessible for your project's web root, you need to say so in your `composer.json` file by adding an entry under `extra.expose`.
+
+For example, let's say you have `scripts`, `images` and `css` folders under `app`. You can expose them by adding this content to your `composer.json` file:
+```json
+{
+ // ...
+ "extra": {
+ "branch-alias": {
+ "4.x-dev": "4.2.x-dev"
+ },
+ "expose": [
+ "app/scripts",
+ "app/images",
+ "app/css"
+ ]
+ },
+ // ...
+}
+```
+
+For the change to take affect, run the following command: `composer vendor-expose`.
+
+### Referencing static assets in your PHP code
+Wherever you would have use an hardcoded path, you can now use the `projectname: path/to/file.css` syntax.
+
+`projectname` is controlled by the `project` property of `SilverStripe\Core\Manifest\ModuleManifest` in your YML configuration. This configuration file should look like this:
+ ```yaml
+ SilverStripe\Core\Manifest\ModuleManifest:
+ project: app
+ ```
+
+To add some javascript and css files to your requirements from your PHP code, you could use this syntax:
+```php
+use SilverStripe\View\Requirements;
+
+# Load your own style and scripts
+Requirements::css('app: css/styles.css');
+Requirements::script('app: scripts/client.css');
+
+# Load some assets from a module.
+Requirements::script('silverstripe/blog: js/main.bundle.js');
+```
+
+You can `SilverStripe\Core\Manifest\ModuleLoader` to get the web path of file.
+```php
+ModuleLoader::getModule('app')->getResource('images/road-runner.jpg')->getRelativePath();
+```
+
+You can use `SilverStripe\View\ThemeResourceLoader` to access files from your theme:
+```php
+$themeFolderPath = ThemeResourceLoader::inst()->getPath('simple');
+$themesFilePath = ThemeResourceLoader::inst()->findThemedResource('css/styles.css');
+```
+
+For classes that expect icons, you can specify theme with:
+```php
+class ListingPage extends \Page
+{
+ private static $icon = 'app: images/sitetree_icon.png';
+}
+
+class MyCustomModelAdmin extends \SilverStripe\Admin\ModelAdmin
+{
+ private static $menu_icon = 'app: images/modeladmin_icon.png';
+}
+```
+
+### Referencing static assets in template files
+SS template files accept a similar format for referencing static assets. Go through your assets files and remove hardcoded references.
+
+```html
+
+<% require css("app: css/styles.css") %>
+```
+
+### Finalising removal of hardcoded paths for referencing static assets
+
+All your assets should be loading properly now.
+
+This is a good point to commit your changes to your source control system before moving on to the next step.
+
+
+## Step 10 - Running your upgraded site for the first time {#step10}
+
+You're almost across the finish line.
+
+### Run a dev build
+Run a `dev/build` either on the command line or in your browser.
+
+```bash
+./vendor/bin/sake dev/build
+```
+
+This should migrate your existing data (non-destructively) to the new SilverStripe 4 structure.
+
+#### Migrating files
+
+Since the structure of the `File` DataObject has changed, a new task `MigrateFileTask`
+has been added to assist in migration of legacy files (see [file migration documentation](/developer_guides/files/file_migration)).
+
+```bash
+./vendor/bin/sake dev/tasks/MigrateFileTask
+```
+
+##### If you were using the versionedfiles on your 3.x site
+
+SilverStripe 4 supersedes the `versionedfiles` module with its new support for
+properly versioned files. However, your file migration will leave all your old
+`_versions` folders as artefacts in the public filesystem, which means all the
+unpublished versions of your old files are publicly accessible under a guessable URL.
+
+To work around this, you can use the `VersionedFilesMigrationTask`:
+
+`$ vendor/bin/sake dev/tasks/migrate-versionedfiles strategy=[delete|protect]`
+
+If you choose the `delete` strategy (default), the task will delete all `_versions`
+files for you. Be sure to take a snapshot of your `public/assets` folder before
+doing so. If you choose the `protect` strategy, the task will drop an `.htaccess` file
+in your old `_versions` directories. **This method only works if you are using Apache
+to serve your static files**. If you are using another server such as Nginx, these files
+will remain publicly exposed. It is recommended you use the `delete` strategy if you are
+not using Apache.
+
+
+### Any other script that needs running.
+
+Some third party modules may include their own migration tasks. Take a minute to consult the release notes of your third party dependencies to make sure you haven't missed anything.
+>>>>>>> DOCS: Add docs for versioned files migration
diff --git a/docs/en/04_Changelogs/4.3.5.md b/docs/en/04_Changelogs/4.3.5.md
new file mode 100644
index 000000000..e5ad33966
--- /dev/null
+++ b/docs/en/04_Changelogs/4.3.5.md
@@ -0,0 +1,42 @@
+# 4.3.5
+
+Embedding files with shortcodes (`FileShortcodeProvider`) no longer provides a session grant
+by default. This is because it has the potential to escalate file access
+to users who otherwise should not have viewing permissions for the file.
+
+There is a minor performance trade-off for disabling these grants. If you have a page with a lot of
+images that are in a draft state or have custom viewing permissions, it adds an extra database
+query for each embedded image. With session grants enabled, the first permission check persists
+the grant into the session, meaning there is no need to query the database on every single file.
+
+Unless you have a lot of shortcode images embedded with protected or draft status on a single page,
+this setting is best left to its default value of `false`.
+
+To revert to the old behaviour:
+
+```
+SilverStripe\Assets\Shortcodes\FileShortcodeProvider:
+ allow_session_grant: true
+```
+
+## If you were using the versionedfiles on your 3.x site
+
+This release includes a security fix for users who migrated from a 3.x site that used
+the [versionedfiles](https://github.com/symbiote/silverstripe-versionedfiles) module.
+The file migration would have left the `_versions` folders in your public filesystem
+as artefacts, leaving all the unpublished versions of your old files publicly accessible
+under a guessable URL.
+
+To work around this, you can use the `VersionedFilesMigrationTask`:
+
+`$ vendor/bin/sake dev/tasks/migrate-versionedfiles strategy=[delete|protect]`
+
+If you choose the `delete` strategy (default), the task will delete all `_versions`
+files for you. Be sure to take a snapshot of your `public/assets` folder before
+doing so. If you choose the `protect` strategy, the task will drop an `.htaccess` file
+in your old `_versions` directories. **This method only works if you are using Apache
+to serve your static files**. If you are using another server such as Nginx, these files
+will remain publicly exposed. It is recommended you use the `delete` strategy if you are
+not using Apache.
+
+
diff --git a/docs/en/04_Changelogs/4.4.3.md b/docs/en/04_Changelogs/4.4.3.md
index 630350f55..01d50e129 100644
--- a/docs/en/04_Changelogs/4.4.3.md
+++ b/docs/en/04_Changelogs/4.4.3.md
@@ -1,8 +1,23 @@
# 4.4.3
-
+Embedding files with shortcodes (`FileShortcodeProvider`) no longer provides a session grant
+by default. This is because it has the potential to escalate file access
+to users who otherwise should not have viewing permissions for the file.
+There is a minor performance trade-off for disabling these grants. If you have a page with a lot of
+images that are in a draft state or have custom viewing permissions, it adds an extra database
+query for each embedded image. With session grants enabled, the first permission check persists
+the grant into the session, meaning there is no need to query the database on every single file.
+Unless you have a lot of shortcode images embedded with protected or draft status on a single page,
+this setting is best left to its default value of `false`.
+
+To revert to the old behaviour:
+
+```
+SilverStripe\Assets\Shortcodes\FileShortcodeProvider:
+ allow_session_grant: true
+```
## Change Log
@@ -30,5 +45,4 @@
* 2019-08-15 [11a7d6ccb](https://github.com/silverstripe/silverstripe-framework/commit/11a7d6ccb4c2bb416dd58261d46b6e70fa8ad0d9) Rename test to be clearer about its intent (Robbie Averill)
* 2019-07-29 [c1ffc4edf](https://github.com/silverstripe/silverstripe-framework/commit/c1ffc4edfb4c2c06da5a6a04ba5b9ea3fcc60f1a) Added unit tests for multiple relationship sorting (UndefinedOffset)
-
-
\ No newline at end of file
+
diff --git a/docs/en/04_Changelogs/4.4.4.md b/docs/en/04_Changelogs/4.4.4.md
new file mode 100644
index 000000000..0178ba6d3
--- /dev/null
+++ b/docs/en/04_Changelogs/4.4.4.md
@@ -0,0 +1,48 @@
+# 4.4.4
+
+
+
+
+
+## Change Log
+
+### Security
+
+ * 2019-09-23 [8b7063a8e](https://github.com/silverstripe/silverstripe-framework/commit/8b7063a8e2773e2bbec3cabf94ed86e11f607071) Fix access escalation for CMS users with limited access through permission cache pollution (Serge Latyntcev) - See [cve-2019-12617](https://www.silverstripe.org/download/security-releases/cve-2019-12617)
+ * 2019-09-16 [eccfa9b10](https://github.com/silverstripe/silverstripe-framework/commit/eccfa9b10d246d741de2fa83d502339d45068983) Session fixation in "change password" form (Serge Latyntcev) - See [cve-2019-12203](https://www.silverstripe.org/download/security-releases/cve-2019-12203)
+ * 2019-08-20 [f98a59de](https://github.com/silverstripe/silverstripe-cms/commit/f98a59deb58d3c9c739f5b32de16472f6ef4a69c) install.php warning does not account for public dir (Aaron Carlino) - See [cve-2019-12204](https://www.silverstripe.org/download/security-releases/cve-2019-12204)
+ * 2019-08-17 [8c7a719](https://github.com/silverstripe/silverstripe-assets/commit/8c7a71992b038f65543a37097b88e6929c23ba8b) Broken access control on files due to session grant (Aaron Carlino) - See [cve-2019-14273](https://www.silverstripe.org/download/security-releases/cve-2019-14273)
+ * 2019-05-21 [73e0cc6](https://github.com/silverstripe/silverstripe-assets/commit/73e0cc69dc499c24aa706af9eddd8a2db2ac93e0) Fix incorrect access control vulnerability with unwritten files in protected folders (Robbie Averill) - See [cve-2019-12245](https://www.silverstripe.org/download/security-releases/cve-2019-12245)
+
+### Features and Enhancements
+
+ * 2019-09-18 [1308911](https://github.com/silverstripe/silverstripe-assets/commit/13089110e7b3feea2196198fd3beda21244ceb20) Add task to remove/protect _versions folders (Aaron Carlino)
+
+### Bugfixes
+
+ * 2019-09-24 [3659f2888](https://github.com/silverstripe/silverstripe-framework/commit/3659f2888d9359f106f91afe46a2f605ed563233) Add 'legal empty attributes' to allow empty alt values on i… (#9257) (Guy Marriott)
+ * 2019-09-23 [0d27f32cc](https://github.com/silverstripe/silverstripe-framework/commit/0d27f32cc9df8776879ff4142a14945c2cba2ad1) Add 'legal empty attributes' to allow empty alt values on imgs (Garion Herman)
+ * 2019-09-23 [fc536fa](https://github.com/silverstripe/silverstripe-assets/commit/fc536faf2413683549d6b8e77400dc85e37b3a30) Update Apache .htaccess for new access directives (Dylan Wagstaff)
+ * 2019-09-20 [ea363fc](https://github.com/silverstripe/silverstripe-asset-admin/commit/ea363fcabd9af8d7607bac9b431171b6b94583f1) Correctly process all non-insert form actions normally in the media dialog (#1005) (Damian Mooyman)
+ * 2019-09-16 [6a1c6ecec](https://github.com/silverstripe/silverstripe-framework/commit/6a1c6ecec6e39ae1f66c9750d5136cf83faa6417) Fix administrators not being able to see files that are restricted to groups (bergice)
+ * 2019-09-10 [591b88a9b](https://github.com/silverstripe/silverstripe-framework/commit/591b88a9bc05b40a7ce3604283b9b7cb684f88cc) Allow infinite loop when calling DataObject::writeComponent() recursively (Maxime Rainville)
+ * 2019-09-03 [b0a6973](https://github.com/silverstripe/silverstripe-asset-admin/commit/b0a6973052e73652a9092e7ed9d5dd5d89e5dd42) Remove Default DropzoneJS Timeout of 30s (#985) (Joe Harvey)
+ * 2019-09-02 [9f19a9b](https://github.com/silverstripe/silverstripe-versioned/commit/9f19a9b3c9999571d4c4db106dc8b8d95dc81cf8) make the actions consistent on the grid field items to what they look like on pages (#242) (Andre Kiste)
+ * 2019-08-29 [194ec84](https://github.com/silverstripe/silverstripe-admin/commit/194ec84496bf5b31212461347170c489231c102f) content block editing breaking when editing using IE11 by adding Event constructor polyfill (bergice)
+ * 2019-08-29 [77ba8391c](https://github.com/silverstripe/silverstripe-framework/commit/77ba8391c40278930873301d50ee3c1168da4cef) Byte Order Marks (BOM) are now stripped when importing CSV files (Robbie Averill)
+ * 2019-08-28 [73f43c6f4](https://github.com/silverstripe/silverstripe-framework/commit/73f43c6f428dc92ee2c9a5f932c63ed8a04c8230) Remove placeholder text on new group form (Maxime Rainville)
+ * 2019-08-27 [2f8d847a1](https://github.com/silverstripe/silverstripe-framework/commit/2f8d847a10fcef45a49e1d96d407b84b99221637) make the grid field actions consistent to what they look like on pages (bergice)
+ * 2019-08-26 [d2a07b104](https://github.com/silverstripe/silverstripe-framework/commit/d2a07b10478ddc57d798e9c96f057973e6e4de68) Remove error when exporting a column that is not displayed in a GridField (Will Rossiter)
+ * 2019-08-26 [314a906](https://github.com/silverstripe/silverstripe-admin/commit/314a9068e5a3a1a71dfc99021d6acec9b0ab5b77) Fix the jstree styles so that the selected states are more visible (bergice)
+ * 2019-08-26 [8b22e3b](https://github.com/silverstripe/silverstripe-assets/commit/8b22e3b7802164a8a59f8bfa2e0417e3ff6bc7a2) Update LegacyThumbnailMigrationHelper to carry on if it hits a fileID it can't parse (Maxime Rainville)
+ * 2019-08-23 [5845ac6](https://github.com/silverstripe/silverstripe-admin/commit/5845ac685851f8841af8d96ef6313a2cff153ba4) Prevent breadcrumb item styles from bleeding into non-react (Maxime Rainville)
+ * 2019-08-23 [94d6c80](https://github.com/silverstripe/silverstripe-admin/commit/94d6c80780430acb4e9d8786a5080a800f777792) enter to submit form not working on `Add new page` (bergice)
+ * 2019-08-22 [841c855](https://github.com/silverstripe/silverstripe-versioned/commit/841c8552b1c7cd7437d607aa51783a62f69a8c34) Ensure dataobjects are unpublished during the delete mutation (Guy Marriott)
+ * 2019-08-22 [4cb4d46](https://github.com/silverstripe/silverstripe-admin/commit/4cb4d467c500f0098f54002599b96ad8e2d112bb) react-select clears input on search. Monkey patch, needs upgrade (Aaron Carlino)
+ * 2019-08-18 [ab4ccb8](https://github.com/silverstripe/silverstripe-assets/commit/ab4ccb8d5311c6ef20640fa5d4bcbdc76c8eeede) Update LegacyFileIDHelper to understand pre-SS33 variant FileID (Maxime Rainville)
+ * 2019-08-13 [1c548cb](https://github.com/silverstripe/silverstripe-admin/commit/1c548cb599563997687cd1062ff2a0985c43197e) jstree state when saving a page by retaining the open/closed state and selected node state. (bergice)
+ * 2019-07-29 [0abfed3e0](https://github.com/silverstripe/silverstripe-framework/commit/0abfed3e06c62b1156073bdf068a1b0ac23d2505) Skip md5-ing the whole contents of a stream for etags (Guy Marriott)
+ * 2019-04-12 [7592db91](https://github.com/silverstripe/silverstripe-cms/commit/7592db918f269db2fd5c33d9c1259df86f15e12b) VirtualPage missing methods from target page (fixes #2408) (Loz Calver)
+
+
+
\ No newline at end of file
diff --git a/lang/fi.yml b/lang/fi.yml
index cf4999859..da2e52a8e 100644
--- a/lang/fi.yml
+++ b/lang/fi.yml
@@ -34,8 +34,6 @@ fi:
LOGGED_IN_ERROR: 'Sinun täytyy olla kirjautuneena vaihtaaksesi salasanasi.'
MAXIMUM: 'Salasana voi olla enintään {max} merkkiä pitkä.'
SHOWONCLICKTITLE: 'Vaihda salasana'
- SilverStripe\Forms\CurrencyField:
- CURRENCYSYMBOL: $
SilverStripe\Forms\DateField:
NOTSET: 'ei asetettu'
TODAY: tänään
@@ -48,7 +46,6 @@ fi:
VALIDDATETIMEMINDATE: 'Päivämäärän on oltava uudempi tai sovittava asetettuun päivämäärän ja ajan minimiarvoon ({date})'
SilverStripe\Forms\DropdownField:
CHOOSE: (Valitse)
- CHOOSE_MODEL: '(Valitse {name})'
SOURCE_VALIDATION: 'Valitse arvo pudotusvalikosta. {value} ei kelpaa'
SilverStripe\Forms\EmailField:
VALIDATION: 'Anna sähköpostiosoite, ole hyvä.'
diff --git a/lang/fi_FI.yml b/lang/fi_FI.yml
index 8afd3cbb3..64efd693e 100644
--- a/lang/fi_FI.yml
+++ b/lang/fi_FI.yml
@@ -34,8 +34,6 @@ fi_FI:
LOGGED_IN_ERROR: 'Sinun täytyy olla kirjautuneena vaihtaaksesi salasanasi.'
MAXIMUM: 'Salasana voi olla enintään {max} merkkiä pitkä.'
SHOWONCLICKTITLE: 'Vaihda salasana'
- SilverStripe\Forms\CurrencyField:
- CURRENCYSYMBOL: $
SilverStripe\Forms\DateField:
NOTSET: 'ei asetettu'
TODAY: tänään
@@ -48,7 +46,6 @@ fi_FI:
VALIDDATETIMEMINDATE: 'Päivämäärän on oltava uudempi tai sovittava asetettuun päivämäärän ja ajan minimiarvoon ({date})'
SilverStripe\Forms\DropdownField:
CHOOSE: (Valitse)
- CHOOSE_MODEL: '(Valitse {name})'
SOURCE_VALIDATION: 'Valitse arvo pudotusvalikosta. {value} ei kelpaa'
SilverStripe\Forms\EmailField:
VALIDATION: 'Anna sähköpostiosoite, ole hyvä.'
diff --git a/src/Control/Session.php b/src/Control/Session.php
index 24858d4bf..0fa9730e9 100644
--- a/src/Control/Session.php
+++ b/src/Control/Session.php
@@ -225,7 +225,6 @@ class Session
*/
public function init(HTTPRequest $request)
{
-
if (!$this->isStarted() && $this->requestContainsSessionId($request)) {
$this->start($request);
}
@@ -642,4 +641,16 @@ class Session
}
}
}
+
+ /**
+ * Regenerate session id
+ *
+ * @internal This is for internal use only. Isn't a part of public API.
+ */
+ public function regenerateSessionId()
+ {
+ if (!headers_sent()) {
+ session_regenerate_id(true);
+ }
+ }
}
diff --git a/src/Security/InheritedPermissions.php b/src/Security/InheritedPermissions.php
index d320793f6..0c1cd66c5 100644
--- a/src/Security/InheritedPermissions.php
+++ b/src/Security/InheritedPermissions.php
@@ -357,21 +357,25 @@ class InheritedPermissions implements PermissionChecker, MemberCacheFlusher
$baseTable = DataObject::getSchema()->baseDataTable($this->getBaseClass());
if ($member && $member->ID) {
- // Determine if this member matches any of the group or other rules
- $groupJoinTable = $this->getJoinTable($type);
- $uninheritedPermissions = $stageRecords
- ->where([
- "(\"$typeField\" IN (?, ?) OR " . "(\"$typeField\" = ? AND \"$groupJoinTable\".\"{$baseTable}ID\" IS NOT NULL))"
- => [
- self::ANYONE,
- self::LOGGED_IN_USERS,
- self::ONLY_THESE_USERS
- ]
- ])
- ->leftJoin(
- $groupJoinTable,
- "\"$groupJoinTable\".\"{$baseTable}ID\" = \"{$baseTable}\".\"ID\" AND " . "\"$groupJoinTable\".\"GroupID\" IN ($groupIDsSQLList)"
- )->column('ID');
+ if (!Permission::checkMember($member, 'ADMIN')) {
+ // Determine if this member matches any of the group or other rules
+ $groupJoinTable = $this->getJoinTable($type);
+ $uninheritedPermissions = $stageRecords
+ ->where([
+ "(\"$typeField\" IN (?, ?) OR " . "(\"$typeField\" = ? AND \"$groupJoinTable\".\"{$baseTable}ID\" IS NOT NULL))"
+ => [
+ self::ANYONE,
+ self::LOGGED_IN_USERS,
+ self::ONLY_THESE_USERS
+ ]
+ ])
+ ->leftJoin(
+ $groupJoinTable,
+ "\"$groupJoinTable\".\"{$baseTable}ID\" = \"{$baseTable}\".\"ID\" AND " . "\"$groupJoinTable\".\"GroupID\" IN ($groupIDsSQLList)"
+ )->column('ID');
+ } else {
+ $uninheritedPermissions = $stageRecords->column('ID');
+ }
} else {
// Only view pages with ViewType = Anyone if not logged in
$uninheritedPermissions = $stageRecords
@@ -748,6 +752,7 @@ class InheritedPermissions implements PermissionChecker, MemberCacheFlusher
*/
protected function generateCacheKey($type, $memberID)
{
- return "{$type}-{$memberID}";
+ $classKey = str_replace('\\', '-', $this->baseClass);
+ return "{$type}-{$classKey}-{$memberID}";
}
}
diff --git a/src/Security/MemberAuthenticator/ChangePasswordHandler.php b/src/Security/MemberAuthenticator/ChangePasswordHandler.php
index 483286162..fdd704e0a 100644
--- a/src/Security/MemberAuthenticator/ChangePasswordHandler.php
+++ b/src/Security/MemberAuthenticator/ChangePasswordHandler.php
@@ -158,6 +158,7 @@ class ChangePasswordHandler extends RequestHandler
Injector::inst()->get(IdentityStore::class)->logOut();
}
+ $this->getRequest()->getSession()->regenerateSessionId();
// Store the hash for the change password form. Will be unset after reload within the ChangePasswordForm.
$this->getRequest()->getSession()->set('AutoLoginHash', $member->encryptWithUserSettings($token));
}
diff --git a/src/Security/MemberAuthenticator/SessionAuthenticationHandler.php b/src/Security/MemberAuthenticator/SessionAuthenticationHandler.php
index 1aafc020c..25f5b47f4 100644
--- a/src/Security/MemberAuthenticator/SessionAuthenticationHandler.php
+++ b/src/Security/MemberAuthenticator/SessionAuthenticationHandler.php
@@ -98,6 +98,7 @@ class SessionAuthenticationHandler implements AuthenticationHandler
$file = '';
$line = '';
+ // TODO: deprecate and use Session::regenerateSessionId
// @ is to supress win32 warnings/notices when session wasn't cleaned up properly
// There's nothing we can do about this, because it's an operating system function!
if (!headers_sent($file, $line)) {
diff --git a/src/View/HTML.php b/src/View/HTML.php
index 220d0e955..7a5d2a72e 100644
--- a/src/View/HTML.php
+++ b/src/View/HTML.php
@@ -39,6 +39,16 @@ class HTML
'wbr'
];
+ /**
+ * List of attributes that should be rendered even if they contain no value
+ *
+ * @config
+ * @var array
+ */
+ private static $legal_empty_attributes = [
+ 'alt',
+ ];
+
/**
* Construct and return HTML tag.
*
@@ -52,10 +62,13 @@ class HTML
$tag = strtolower($tag);
// Build list of arguments
+ $legalEmptyAttributes = static::config()->get('legal_empty_attributes');
$preparedAttributes = '';
foreach ($attributes as $attributeKey => $attributeValue) {
+ $whitelisted = in_array($attributeKey, $legalEmptyAttributes);
+
// Only set non-empty strings (ensures strlen(0) > 0)
- if (strlen($attributeValue) > 0) {
+ if (strlen($attributeValue) > 0 || $whitelisted) {
$preparedAttributes .= sprintf(
' %s="%s"',
$attributeKey,
diff --git a/tests/php/Security/InheritedPermissionsTest.php b/tests/php/Security/InheritedPermissionsTest.php
index f5a0804d2..5aa32de65 100644
--- a/tests/php/Security/InheritedPermissionsTest.php
+++ b/tests/php/Security/InheritedPermissionsTest.php
@@ -151,6 +151,8 @@ class InheritedPermissionsTest extends SapphireTest
$protected = $this->objFromFixture(TestPermissionNode::class, 'protected');
$protectedChild = $this->objFromFixture(TestPermissionNode::class, 'protected-child');
$editor = $this->objFromFixture(Member::class, 'editor');
+ $restricted = $this->objFromFixture(TestPermissionNode::class, 'restricted-page');
+ $admin = $this->objFromFixture(Member::class, 'admin');
// Not logged in user can only access Inherit or Anyone pages
Member::actAs(
@@ -182,6 +184,9 @@ class InheritedPermissionsTest extends SapphireTest
$this->rootPermissions->setCanView(false);
$this->assertFalse($history->canView($editor));
+
+ // Ensure admins can view everything, even if only a certain group is allowed to view it
+ $this->assertTrue($restricted->canView($admin));
}
public function testUnstagedViewPermissions()
diff --git a/tests/php/Security/InheritedPermissionsTest.yml b/tests/php/Security/InheritedPermissionsTest.yml
index 19fa1cd3a..92141c361 100644
--- a/tests/php/Security/InheritedPermissionsTest.yml
+++ b/tests/php/Security/InheritedPermissionsTest.yml
@@ -100,6 +100,10 @@ SilverStripe\Security\Tests\InheritedPermissionsTest\TestPermissionNode:
Title: Child
CanViewType: Inherit
Parent: =>SilverStripe\Security\Tests\InheritedPermissionsTest\TestPermissionNode.protected
+ restricted-page:
+ Title: Restricted Page
+ CanViewType: OnlyTheseUsers
+ ViewerGroups: =>SilverStripe\Security\Group.allsections
SilverStripe\Security\Tests\InheritedPermissionsTest\UnstagedNode:
about:
@@ -167,3 +171,7 @@ SilverStripe\Security\Tests\InheritedPermissionsTest\UnstagedNode:
Title: Child
CanViewType: Inherit
Parent: =>SilverStripe\Security\Tests\InheritedPermissionsTest\UnstagedNode.protected
+ restricted-page:
+ Title: Restricted Page
+ CanViewType: OnlyTheseUsers
+ ViewerGroups: =>SilverStripe\Security\Group.allsections
diff --git a/tests/php/View/HTMLTest.php b/tests/php/View/HTMLTest.php
index e363e3e1a..3c96e2d55 100644
--- a/tests/php/View/HTMLTest.php
+++ b/tests/php/View/HTMLTest.php
@@ -45,6 +45,16 @@ class HTMLTest extends SapphireTest
$this->assertEquals('Some content!', $tag);
}
+ public function testImgTag()
+ {
+ $tag = HTML::createTag('img', [
+ 'src' => 'example.png',
+ 'alt' => '',
+ ]);
+
+ $this->assertEquals('', $tag);
+ }
+
public function testVoidContentError()
{
$this->expectException(InvalidArgumentException::class);