Merge branch '4.2' into 4

This commit is contained in:
Daniel Hensby 2018-07-13 17:06:51 +01:00
commit ac5c3416a4
No known key found for this signature in database
GPG Key ID: B00D1E9767F0B06E
11 changed files with 124 additions and 85 deletions

View File

@ -168,12 +168,12 @@ the result will be the higher priority false-ish value.
The locations that configuration values are taken from in highest -> lowest priority order are: The locations that configuration values are taken from in highest -> lowest priority order are:
- Any values set via a call to Config#merge / Config#set - Runtime modifications, ie: any values set via a call to `Config::inst()->update()`
- The configuration values taken from the YAML files in `_config/` directories (internally sorted in before / after - The configuration values taken from the YAML files in `_config/` directories (internally sorted in before / after
order, where the item that is latest is highest priority) order, where the item that is latest is highest priority)
- Any static set on an "additional static source" class (such as an extension) named the same as the name of the property
- Any static set on the class named the same as the name of the property - Any static set on the class named the same as the name of the property
- The composite configuration value of the parent class of this class - The composite configuration value of the parent class of this class
- Any static set on an "additional static source" class (such as an extension) named the same as the name of the property
<div class="notice"> <div class="notice">
It is an error to have mixed types of the same named property in different locations. An error will not necessarily It is an error to have mixed types of the same named property in different locations. An error will not necessarily

View File

@ -0,0 +1,12 @@
# 4.0.5
## Notable changes
Fix [#7971](https://github.com/silverstripe/silverstripe-framework/pull/7971) introduces a subtle change of behaviour
to how `Config` settings are prioritised. In SilverStripe 4 there was a change where `Extension` objects took the
highest importance when determining Config values; this was deemed to be unexpected and unintuitive as well as making it
cumbersome and difficult for developers to override module defaults defined in `Extension`s. This change reverts
behaviour to that of SilverStripe 3 where `Extension` instances are of lowest importance and are used only to set a
default value. If you rely on your `Extension` or module providing an overriding config value, please move this to yaml.
<!--- Changes below this line will be automatically regenerated -->

View File

@ -0,0 +1,12 @@
# 4.1.3
## Notable changes
Fix [#7971](https://github.com/silverstripe/silverstripe-framework/pull/7971) introduces a subtle change of behaviour
to how `Config` settings are prioritised. In SilverStripe 4 there was a change where `Extension` objects took the
highest importance when determining Config values; this was deemed to be unexpected and unintuitive as well as making it
cumbersome and difficult for developers to override module defaults defined in `Extension`s. This change reverts
behaviour to that of SilverStripe 3 where `Extension` instances are of lowest importance and are used only to set a
default value. If you rely on your `Extension` or module providing an overriding config value, please move this to yaml.
<!--- Changes below this line will be automatically regenerated -->

View File

@ -0,0 +1,12 @@
# 4.2.1
## Notable changes
Fix [#7971](https://github.com/silverstripe/silverstripe-framework/pull/7971) introduces a subtle change of behaviour
to how `Config` settings are prioritised. In SilverStripe 4 there was a change where `Extension` objects took the
highest importance when determining Config values; this was deemed to be unexpected and unintuitive as well as making it
cumbersome and difficult for developers to override module defaults defined in `Extension`s. This change reverts
behaviour to that of SilverStripe 3 where `Extension` instances are of lowest importance and are used only to set a
default value. If you rely on your `Extension` or module providing an overriding config value, please move this to yaml.
<!--- Changes below this line will be automatically regenerated -->

View File

@ -327,5 +327,5 @@ en:
NOTEPAGESECURED: 'That page is secured. Enter your credentials below and we will send you right along.' NOTEPAGESECURED: 'That page is secured. Enter your credentials below and we will send you right along.'
NOTERESETLINKINVALID: '<p>The password reset link is invalid or expired.</p><p>You can request a new one <a href="{link1}">here</a> or change your password after you <a href="{link2}">logged in</a>.</p>' NOTERESETLINKINVALID: '<p>The password reset link is invalid or expired.</p><p>You can request a new one <a href="{link1}">here</a> or change your password after you <a href="{link2}">logged in</a>.</p>'
NOTERESETPASSWORD: 'Enter your e-mail address and we will send you a link with which you can reset your password' NOTERESETPASSWORD: 'Enter your e-mail address and we will send you a link with which you can reset your password'
PASSWORDSENTHEADER: 'Password reset link sent to ''{email}''' PASSWORDRESETSENTHEADER: 'Password reset link sent'
PASSWORDSENTTEXT: 'Thank you! A reset link has been sent to ''{email}'', provided an account exists for this email address.' PASSWORDRESETSENTTEXT: 'Thank you. A reset link has been sent, provided an account exists for this email address.'

View File

@ -103,7 +103,7 @@ class HTTPCacheControlMiddleware implements HTTPMiddleware, Resettable
* @config * @config
* @var string * @var string
*/ */
protected static $defaultState = self::STATE_DEFAULT; private static $defaultState = self::STATE_DEFAULT;
/** /**
* Current state * Current state
@ -771,14 +771,9 @@ class HTTPCacheControlMiddleware implements HTTPMiddleware, Resettable
} }
// Errors disable cache (unless some errors are cached intentionally by usercode) // Errors disable cache (unless some errors are cached intentionally by usercode)
if ($response->isError()) { if ($response->isError() || $response->isRedirect()) {
// Even if publicCache(true) is specified, errors will be uncacheable // Even if publicCache(true) is specified, errors will be uncacheable
$this->disableCache(true); $this->disableCache(true);
} }
// Don't cache redirects
if ($response->isRedirect()) {
$this->disableCache(true);
}
} }
} }

View File

@ -39,7 +39,7 @@ class ExtensionMiddleware implements Middleware
} }
foreach ($this->getExtraConfig($class, $config, $excludeMiddleware) as $extra) { foreach ($this->getExtraConfig($class, $config, $excludeMiddleware) as $extra) {
$config = Priority::mergeArray($extra, $config); $config = Priority::mergeArray($config, $extra);
} }
return $config; return $config;
} }

View File

@ -27,8 +27,8 @@ class LostPasswordHandler extends RequestHandler
* @var array * @var array
*/ */
private static $url_handlers = [ private static $url_handlers = [
'passwordsent/$EmailAddress' => 'passwordsent', 'passwordsent' => 'passwordsent',
'' => 'lostpassword', '' => 'lostpassword',
]; ];
/** /**
@ -101,27 +101,17 @@ class LostPasswordHandler extends RequestHandler
*/ */
public function passwordsent() public function passwordsent()
{ {
$request = $this->getRequest();
$email = Convert::raw2xml(rawurldecode($request->param('EmailAddress')));
if ($request->getExtension()) {
$email = $email . '.' . Convert::raw2xml($request->getExtension());
}
$message = _t( $message = _t(
'SilverStripe\\Security\\Security.PASSWORDSENTTEXT', 'SilverStripe\\Security\\Security.PASSWORDRESETSENTTEXT',
"Thank you! A reset link has been sent to '{email}', provided an account exists for this email" "Thank you. A reset link has been sent, provided an account exists for this email address."
. " address.",
['email' => Convert::raw2xml($email)]
); );
return [ return [
'Title' => _t( 'Title' => _t(
'SilverStripe\\Security\\Security.PASSWORDSENTHEADER', 'SilverStripe\\Security\\Security.PASSWORDRESETSENTHEADER',
"Password reset link sent to '{email}'", "Password reset link sent"
array('email' => $email)
), ),
'Content' => DBField::create_field('HTMLFragment', "<p>$message</p>"), 'Content' => DBField::create_field('HTMLFragment', "<p>$message</p>"),
'Email' => $email
]; ];
} }
@ -263,11 +253,7 @@ class LostPasswordHandler extends RequestHandler
*/ */
protected function redirectToSuccess(array $data) protected function redirectToSuccess(array $data)
{ {
$link = Controller::join_links( $link = $this->link('passwordsent');
$this->Link('passwordsent'),
rawurlencode($data['Email']),
'/'
);
return $this->redirect($this->addBackURLParam($link)); return $this->redirect($this->addBackURLParam($link));
} }

View File

@ -2,6 +2,7 @@
namespace SilverStripe\View\Shortcodes; namespace SilverStripe\View\Shortcodes;
use Embed\Http\DispatcherInterface;
use SilverStripe\Core\Convert; use SilverStripe\Core\Convert;
use SilverStripe\Core\Injector\Injector; use SilverStripe\Core\Injector\Injector;
use SilverStripe\View\Embed\Embeddable; use SilverStripe\View\Embed\Embeddable;
@ -76,6 +77,11 @@ class EmbedShortcodeProvider implements ShortcodeHandler
$serviceURL, $serviceURL,
$extra['resolver']['config'] $extra['resolver']['config']
); );
} elseif (Injector::inst()->has(DispatcherInterface::class)) {
$dispatcher = Injector::inst()->get(DispatcherInterface::class);
}
if ($dispatcher) {
$embed->setDispatcher($dispatcher); $embed->setDispatcher($dispatcher);
} }

View File

@ -1102,72 +1102,88 @@ class DataObjectTest extends SapphireTest
// Test logical fields (including composite) // Test logical fields (including composite)
$teamSpecifications = $schema->fieldSpecs(DataObjectTest\Team::class); $teamSpecifications = $schema->fieldSpecs(DataObjectTest\Team::class);
$expected = array(
'ID',
'ClassName',
'LastEdited',
'Created',
'Title',
'DatabaseField',
'ExtendedDatabaseField',
'CaptainID',
'FounderID',
'HasOneRelationshipID',
'ExtendedHasOneRelationshipID'
);
$actual = array_keys($teamSpecifications);
sort($expected);
sort($actual);
$this->assertEquals( $this->assertEquals(
array( $expected,
'ID', $actual,
'ClassName',
'LastEdited',
'Created',
'Title',
'DatabaseField',
'ExtendedDatabaseField',
'CaptainID',
'FounderID',
'HasOneRelationshipID',
'ExtendedHasOneRelationshipID'
),
array_keys($teamSpecifications),
'fieldSpecifications() contains all fields defined on instance: base, extended and foreign keys' 'fieldSpecifications() contains all fields defined on instance: base, extended and foreign keys'
); );
$teamFields = $schema->databaseFields(DataObjectTest\Team::class, false); $teamFields = $schema->databaseFields(DataObjectTest\Team::class, false);
$expected = array(
'ID',
'ClassName',
'LastEdited',
'Created',
'Title',
'DatabaseField',
'ExtendedDatabaseField',
'CaptainID',
'FounderID',
'HasOneRelationshipID',
'ExtendedHasOneRelationshipID'
);
$actual = array_keys($teamFields);
sort($expected);
sort($actual);
$this->assertEquals( $this->assertEquals(
array( $expected,
'ID', $actual,
'ClassName',
'LastEdited',
'Created',
'Title',
'DatabaseField',
'ExtendedDatabaseField',
'CaptainID',
'FounderID',
'HasOneRelationshipID',
'ExtendedHasOneRelationshipID'
),
array_keys($teamFields),
'databaseFields() contains only fields defined on instance, including base, extended and foreign keys' 'databaseFields() contains only fields defined on instance, including base, extended and foreign keys'
); );
$subteamSpecifications = $schema->fieldSpecs(DataObjectTest\SubTeam::class); $subteamSpecifications = $schema->fieldSpecs(DataObjectTest\SubTeam::class);
$expected = array(
'ID',
'ClassName',
'LastEdited',
'Created',
'Title',
'DatabaseField',
'ExtendedDatabaseField',
'CaptainID',
'FounderID',
'HasOneRelationshipID',
'ExtendedHasOneRelationshipID',
'SubclassDatabaseField',
'ParentTeamID',
);
$actual = array_keys($subteamSpecifications);
sort($expected);
sort($actual);
$this->assertEquals( $this->assertEquals(
array( $expected,
'ID', $actual,
'ClassName',
'LastEdited',
'Created',
'Title',
'DatabaseField',
'ExtendedDatabaseField',
'CaptainID',
'FounderID',
'HasOneRelationshipID',
'ExtendedHasOneRelationshipID',
'SubclassDatabaseField',
'ParentTeamID',
),
array_keys($subteamSpecifications),
'fieldSpecifications() on subclass contains all fields, including base, extended and foreign keys' 'fieldSpecifications() on subclass contains all fields, including base, extended and foreign keys'
); );
$subteamFields = $schema->databaseFields(DataObjectTest\SubTeam::class, false); $subteamFields = $schema->databaseFields(DataObjectTest\SubTeam::class, false);
$expected = array(
'ID',
'SubclassDatabaseField',
'ParentTeamID',
);
$actual = array_keys($subteamFields);
sort($expected);
sort($actual);
$this->assertEquals( $this->assertEquals(
array( $expected,
'ID', $actual,
'SubclassDatabaseField',
'ParentTeamID',
),
array_keys($subteamFields),
'databaseFields() on subclass contains only fields defined on instance' 'databaseFields() on subclass contains only fields defined on instance'
); );
} }

View File

@ -239,7 +239,7 @@ class MemberTest extends FunctionalTest
// We should get redirected to Security/passwordsent // We should get redirected to Security/passwordsent
$this->assertContains( $this->assertContains(
'Security/lostpassword/passwordsent/testuser@example.com', 'Security/lostpassword/passwordsent',
urldecode($response->getHeader('Location')) urldecode($response->getHeader('Location'))
); );