mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge remote-tracking branch 'origin/3.1'
This commit is contained in:
commit
982ad569b9
@ -413,7 +413,12 @@ class Director implements TemplateGlobalProvider {
|
||||
|
||||
/**
|
||||
* Turns the given URL into an absolute URL.
|
||||
* @todo Document how relativeToSiteBase works
|
||||
* By default non-site root relative urls will be evaluated relative to the current request.
|
||||
*
|
||||
* @param string $url URL To transform to absolute
|
||||
* @param bool $relativeToSiteBase Flag indicating if non-site root relative urls should be
|
||||
* evaluated relative to the site BaseURL instead of the current url.
|
||||
* @return string The fully qualified URL
|
||||
*/
|
||||
public static function absoluteURL($url, $relativeToSiteBase = false) {
|
||||
if(!isset($_SERVER['REQUEST_URI'])) return false;
|
||||
|
@ -44,6 +44,7 @@ class SS_HTTPResponse {
|
||||
416 => 'Request Range Not Satisfiable',
|
||||
417 => 'Expectation Failed',
|
||||
422 => 'Unprocessable Entity',
|
||||
429 => 'Too Many Requests',
|
||||
500 => 'Internal Server Error',
|
||||
501 => 'Not Implemented',
|
||||
502 => 'Bad Gateway',
|
||||
@ -234,7 +235,7 @@ class SS_HTTPResponse {
|
||||
}
|
||||
|
||||
if(in_array($this->statusCode, self::$redirect_codes) && headers_sent($file, $line)) {
|
||||
$url = (string)$this->headers['Location'];
|
||||
$url = Director::absoluteURL($this->headers['Location'], true);
|
||||
$urlATT = Convert::raw2htmlatt($url);
|
||||
$urlJS = Convert::raw2js($url);
|
||||
echo
|
||||
|
@ -39,6 +39,8 @@ class FunctionalTest extends SapphireTest {
|
||||
|
||||
/**
|
||||
* CSSContentParser for the most recently requested page.
|
||||
*
|
||||
* @var CSSContentParser
|
||||
*/
|
||||
protected $cssParser = null;
|
||||
|
||||
@ -176,6 +178,8 @@ class FunctionalTest extends SapphireTest {
|
||||
|
||||
/**
|
||||
* Return a CSSContentParser for the most recent content.
|
||||
*
|
||||
* @return CSSContentParser
|
||||
*/
|
||||
public function cssParser() {
|
||||
if(!$this->cssParser) $this->cssParser = new CSSContentParser($this->mainSession->lastContent());
|
||||
|
@ -48,7 +48,7 @@ $dirsToCheck = array(
|
||||
if($dirsToCheck[0] == $dirsToCheck[1]) {
|
||||
unset($dirsToCheck[1]);
|
||||
}
|
||||
foreach($dirsToCheck as $dir) {
|
||||
foreach($dirsToCheck as $dir) {
|
||||
//check this dir and every parent dir (until we hit the base of the drive)
|
||||
// or until we hit a dir we can't read
|
||||
do {
|
||||
|
26
docs/en/changelogs/3.0.10.md
Normal file
26
docs/en/changelogs/3.0.10.md
Normal file
@ -0,0 +1,26 @@
|
||||
# 3.0.10
|
||||
|
||||
## Upgrading
|
||||
|
||||
* If relying on partial caching of content between logged in users, be aware that the cache is now automatically
|
||||
segmented based on both the current member ID, and the versioned reading mode. If this is not an appropriate
|
||||
method (such as if the same content is served to logged in users within partial caching) then it is necessary
|
||||
to adjust the config value of `SSViewer.global_key` to something more or less sensitive.
|
||||
|
||||
## Security
|
||||
|
||||
* [BUG Fix issue with versioned dataobjects being cached between stages](https://github.com/silverstripe/silverstripe-framework/commit/4415a75d9304a3930b9c28763fc092299640c685) - See [announcement SS-2014-007](http://www.silverstripe.org/ss-2014-007-confidentiality-breach-can-occur-between-draft-and-live-modes/)
|
||||
* [BUG Fix encoding of JS redirection script](https://github.com/silverstripe/silverstripe-framework/commit/f8e3bbe3ae3f29f22d85abb73cea033659511168) - See [announcement SS-2014-006](http://www.silverstripe.org/ss-2014-006-xss-in-returnurl-redirection/)
|
||||
* [Amends solution to SS-2014-006](https://github.com/silverstripe/silverstripe-framework/commit/5b0a96979484fad12e11ce69aef98feda57b321f)
|
||||
* [FIX Prevent SQLi when no URL filters are applied](https://github.com/silverstripe/silverstripe-cms/commit/114df8a3a5e4800ef7586c5d9c8d79798fd2a11d) - See [announcement SS-2014-004](http://www.silverstripe.org/ss-2014-004-sql-injection-in-sitetree-with-custom-urlsegmentfilter-rules/)
|
||||
* [FIX Do now allow arbitary class creation in CMS](https://github.com/silverstripe/silverstripe-cms/commit/bf9b22fd4331a6f78cec12a75262f570b025ec2d) - See [announcement SS-2014-005](http://www.silverstripe.org/ss-2014-005-arbitrary-class-creation-in-cms-backend/)
|
||||
|
||||
## General
|
||||
|
||||
* [Rewrote usages of error suppression operator](https://github.com/silverstripe/silverstripe-framework/commit/6d5d3d8cb7e69e0b37471b1e34077211b0f631fe)
|
||||
|
||||
## Changelog
|
||||
|
||||
* [framework](https://github.com/silverstripe/silverstripe-framework/releases/tag/3.0.10)
|
||||
* [cms](https://github.com/silverstripe/silverstripe-cms/releases/tag/3.0.10)
|
||||
* [installer](https://github.com/silverstripe/silverstripe-installer/releases/tag/3.0.10)
|
46
docs/en/changelogs/3.1.4.md
Normal file
46
docs/en/changelogs/3.1.4.md
Normal file
@ -0,0 +1,46 @@
|
||||
# 3.1.4
|
||||
|
||||
## Upgrading
|
||||
|
||||
* If relying on partial caching of content between logged in users, be aware that the cache is now automatically
|
||||
segmented based on both the current member ID, and the versioned reading mode. If this is not an appropriate
|
||||
method (such as if the same content is served to logged in users within partial caching) then it is necessary
|
||||
to adjust the config value of `SSViewer.global_key` to something more or less sensitive.
|
||||
|
||||
## Security
|
||||
|
||||
* [BUG Fix issue with versioned dataobjects being cached between stages](https://github.com/silverstripe/silverstripe-framework/commit/4415a75d9304a3930b9c28763fc092299640c685) - See [announcement SS-2014-007](http://www.silverstripe.org/ss-2014-007-confidentiality-breach-can-occur-between-draft-and-live-modes/)
|
||||
* [BUG Fix encoding of JS redirection script](https://github.com/silverstripe/silverstripe-framework/commit/f8e3bbe3ae3f29f22d85abb73cea033659511168) - See [announcement SS-2014-006](http://www.silverstripe.org/ss-2014-006-xss-in-returnurl-redirection/)
|
||||
* [Amends solution to SS-2014-006](https://github.com/silverstripe/silverstripe-framework/commit/5b0a96979484fad12e11ce69aef98feda57b321f)
|
||||
* [FIX Prevent SQLi when no URL filters are applied](https://github.com/silverstripe/silverstripe-cms/commit/114df8a3a5e4800ef7586c5d9c8d79798fd2a11d) - See [announcement SS-2014-004](http://www.silverstripe.org/ss-2014-004-sql-injection-in-sitetree-with-custom-urlsegmentfilter-rules/)
|
||||
* [FIX Do now allow arbitary class creation in CMS](https://github.com/silverstripe/silverstripe-cms/commit/bf9b22fd4331a6f78cec12a75262f570b025ec2d) - See [announcement SS-2014-005](http://www.silverstripe.org/ss-2014-005-arbitrary-class-creation-in-cms-backend/)
|
||||
|
||||
## Bugfixes
|
||||
|
||||
* [Fix Versioned::augmentSQL() when the data query was null.](https://github.com/silverstripe/silverstripe-framework/commit/deb1bfbcbaaa62acb2263ba797b5068e142a6353)
|
||||
* [FIX UploadField validation error and styles](https://github.com/silverstripe/silverstripe-framework/commit/02bceca9b478358bdd569c16818d3be2467beb64)
|
||||
* [FIX Overriding of theme templates in project folder](https://github.com/silverstripe/silverstripe-framework/commit/5f87d344f11c382dbee3fae8edfc00bb9a5a0265)
|
||||
* [BUG Ensure TreeMultiSelectField doesn't populate menus with "unchanged".](https://github.com/silverstripe/silverstripe-framework/commit/9e2c7b657221c336137e07985bd5994682216d65)
|
||||
* [BUG: #2503 Fixes performReadonlyTransformation for OptionSetField](https://github.com/silverstripe/silverstripe-framework/commit/44a8537f68872f0587cdf4cceadd433817dfdf60)
|
||||
* [FIX: Rewrite Member getCMSFields to ensure updateCMSFields is only run once](https://github.com/silverstripe/silverstripe-framework/commit/d91c7d14b84d8b3caed948b0bbab94d254ea2b96)
|
||||
* [FIX: Ensure valid CSS classes for GridField header](https://github.com/silverstripe/silverstripe-framework/commit/90952e7bd4bf7a278959ff320b3a71d30596f5d8)
|
||||
* [BUG Fix case where setFolder('/') would break UploadField::fileexists](https://github.com/silverstripe/silverstripe-framework/commit/c1e0f98f87fa58edf7967d818732c7467cf47d80)
|
||||
* [BUG Prevent unnecessary reconstruction of ClassName field after default records are generated](https://github.com/silverstripe/silverstripe-framework/commit/53b5adbcd98ff4d0e3947f4472b7b7b62a2b064a)
|
||||
* [BUG Fix DataObject::loadLazyFields discarding original query parameters](https://github.com/silverstripe/silverstripe-framework/commit/23f5f08eda4201e0d3d4c28b81805da10b55bdb1)
|
||||
* [Upload: retrieve existing File if an object without an ID is given and replaceFile=true](https://github.com/silverstripe/silverstripe-framework/commit/3c1e82b42c282ab64dfe7f5a68a50f59d8ebcc69)
|
||||
* [BUG Fix Date and SS_DateTime::FormatFromSettings](https://github.com/silverstripe/silverstripe-framework/commit/84d8022b326e3938753430678cfc3dfa50770d83)
|
||||
|
||||
## API
|
||||
|
||||
* [Add support for many_many_extraField in YAML](https://github.com/silverstripe/silverstripe-framework/commit/8b923006227b0177983c96b949edaa6df18fbbf8)
|
||||
* [Allow vetoing forgot password requests](https://github.com/silverstripe/silverstripe-framework/commit/9afcf8f01ac6b5c3c054b9a49f1731d35aa868ed)
|
||||
|
||||
## General
|
||||
|
||||
* [Rewrote usages of error suppression operator](https://github.com/silverstripe/silverstripe-framework/commit/6d5d3d8cb7e69e0b37471b1e34077211b0f631fe)
|
||||
|
||||
## Changelog
|
||||
|
||||
* [framework](https://github.com/silverstripe/silverstripe-framework/releases/tag/3.1.4)
|
||||
* [cms](https://github.com/silverstripe/silverstripe-cms/releases/tag/3.1.4)
|
||||
* [installer](https://github.com/silverstripe/silverstripe-installer/releases/tag/3.1.4)
|
9
docs/en/changelogs/3.1.5.md
Normal file
9
docs/en/changelogs/3.1.5.md
Normal file
@ -0,0 +1,9 @@
|
||||
# 3.1.5
|
||||
|
||||
## Upgrading
|
||||
|
||||
* If running an application in an environment where user security is critical, it may be necessary to
|
||||
assign the config value `Security.remember_username` to false. This will disable persistence of
|
||||
user login name between sessions, and disable browser auto-completion on the username field.
|
||||
Note that users of certain browsers who have previously autofilled and saved login credentials
|
||||
will need to clear their password autofill history before this setting is properly respected.
|
@ -25,13 +25,31 @@ Servers - this is so our changes to the php.ini take effect.
|
||||
|
||||
## Installing SilverStripe
|
||||
|
||||
###Composer
|
||||
[Composer (a dependancy manager for PHP)](http://getcomposer.org) is the prefered way to install SilverStripe and ensure you get the correct set of files for your project.
|
||||
|
||||
Composer uses your MAMP PHP executible to run and also requires [git](http://git-scm.com) (so it can automatically download the required files from GitHub).
|
||||
|
||||
Process to install is as follows:
|
||||
|
||||
1. Install [git for mac](http://git-scm.com/download/mac).
|
||||
2. Install composer using the instructions at https://gist.github.com/kkirsche/5710272
|
||||
3. Run the following command to get a fresh copy of SilverStripe via composer:
|
||||
|
||||
composer create-project silverstripe/installer /Applications/MAMP/htdocs/silverstripe/
|
||||
|
||||
4. You can now [use composer](http://doc.silverstripe.org/framework/en/installation/composer) to manage future SilverStripe updates and adding modules with a few easy commands.
|
||||
|
||||
###Package Download
|
||||
|
||||
[Download](http://silverstripe.org/download) the latest SilverStripe installer package. Copy the tar.gz file to the 'Document Root' for MAMP - By Default its `/Applications/MAMP/htdocs`.
|
||||
Don't know what your Document Root is? Open MAMP Click `Preferences -> Apache`.
|
||||
|
||||
Extract the tar.gz file to a folder, e.g. `silverstripe/` (you always move the tar.gz file first and not the other way
|
||||
around as SilverStripe uses a '.htaccess' file which is hidden from OSX so if you move SilverStripe the .htaccess file
|
||||
won't come along.
|
||||
won't come along.
|
||||
|
||||
Open your web browser and go to `http://localhost:8888/silverstripe/`. Enter your database details - by default with MAMP its user `root` and password `root` and select your account details. Click "Check Details".
|
||||
###Run the installation wizard
|
||||
Once you have a copy of the required code (by either of the above methods), open your web browser and go to `http://localhost:8888/silverstripe/`. Enter your database details - by default with MAMP its user `root` and password `root` and select your account details. Click "Check Details".
|
||||
|
||||
Once everything is sorted hit "Install!" and Voila, you have SilverStripe installed
|
||||
|
@ -247,7 +247,7 @@ Example: Check for CMS access permissions
|
||||
**Important**: These checks are not enforced on low-level ORM operations
|
||||
such as `write()` or `delete()`, but rather rely on being checked in the invoking code.
|
||||
The CMS default sections as well as custom interfaces like
|
||||
`[ModelAdmin](/reference/modeladmin)` or `[GridField](/reference/gridfield)`
|
||||
`[ModelAdmin](/reference/modeladmin)` or `[GridField](/reference/grid-field)`
|
||||
already enforce these permissions.
|
||||
|
||||
## Indexes
|
||||
|
@ -62,7 +62,7 @@ HTML5 placeholders 'day', 'month' and 'year' are enabled by default.
|
||||
|
||||
:::php
|
||||
DateField::create('MyDate')
|
||||
->setConfig('dmyfields', true);
|
||||
->setConfig('dmyfields', true)
|
||||
->setConfig('dmyseparator', '/') // set the separator
|
||||
->setConfig('dmyplaceholders', 'true'); // enable HTML 5 Placeholders
|
||||
|
||||
@ -154,4 +154,4 @@ sensitive`!
|
||||
### 4. Filename
|
||||
|
||||
Use the original jQuery UI filename 'jquery.ui.datepicker-xx.js', where xx
|
||||
stands for the locale.
|
||||
stands for the locale.
|
||||
|
@ -92,4 +92,4 @@ You can access the following controller-method with /team/signup
|
||||
|
||||
## SSViewer template rendering
|
||||
|
||||
See [templates](/topics/templates) for information on the SSViewer template system.
|
||||
See [templates](/reference/templates) for information on the SSViewer template system.
|
||||
|
@ -93,7 +93,7 @@ For output of an image tag with the image automatically resized to 80px width, y
|
||||
|
||||
:::php
|
||||
$Image.SetWidth(80) // returns a image 80px wide, ratio kept the same
|
||||
$Image.SetHeight(80) // returns a image 80px tall, ration kept the same
|
||||
$Image.SetHeight(80) // returns a image 80px tall, ratio kept the same
|
||||
$Image.SetSize(80,80) // returns a 80x80px padded image
|
||||
$Image.SetRatioSize(80,80) // Returns an image scaled proportional, with its greatest diameter scaled to 80px
|
||||
$Image.CroppedImage(80,80) // Returns an 80x80 image cropped from the center.
|
||||
|
@ -9,11 +9,11 @@ form.
|
||||
A fully implemented form in SilverStripe includes a couple of classes that
|
||||
individually have separate concerns.
|
||||
|
||||
* Controller—Takes care of assembling the form and receiving data from it.
|
||||
* Form—Holds sets of fields, actions and validators.
|
||||
* FormField —Fields that receive data or displays them, e.g input fields.
|
||||
* FormActions—Often submit buttons that executes actions.
|
||||
* Validators—Validate the whole form.
|
||||
* Controller — Takes care of assembling the form and receiving data from it.
|
||||
* Form — Holds sets of fields, actions and validators.
|
||||
* FormField — Fields that receive data or displays them, e.g input fields.
|
||||
* FormActions — Buttons that execute actions.
|
||||
* Validators — Validate the whole form.
|
||||
|
||||
Depending on your needs you can customize and override any of the above classes;
|
||||
the defaults, however, are often sufficient.
|
||||
|
@ -445,6 +445,7 @@ In addition, you can tighten password security with the following configuration
|
||||
the user is blocked from further attempts for the timespan defined in `$lock_out_delay_mins`
|
||||
* `Member.lock_out_delay_mins`: Minutes of enforced lockout after incorrect password attempts.
|
||||
Only applies if `lock_out_after_incorrect_logins` is greater than 0.
|
||||
* `Security.remember_username`: Set to false to disable autocomplete on login form
|
||||
|
||||
## Clickjacking: Prevent iframe Inclusion
|
||||
|
||||
|
@ -186,6 +186,7 @@ class Upload extends Controller {
|
||||
// This is to prevent it from trying to rename the file
|
||||
$this->file->Name = basename($relativeFilePath);
|
||||
$this->file->write();
|
||||
$this->file->onAfterUpload();
|
||||
$this->extend('onAfterLoad', $this->file); //to allow extensions to e.g. create a version after an upload
|
||||
return true;
|
||||
} else {
|
||||
|
@ -422,7 +422,7 @@ class DataQuery {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the GROUP BY clause of this query.
|
||||
* Append a GROUP BY clause to this query.
|
||||
*
|
||||
* @param String $groupby Escaped SQL statement
|
||||
*/
|
||||
@ -432,7 +432,7 @@ class DataQuery {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the HAVING clause of this query.
|
||||
* Append a HAVING clause to this query.
|
||||
*
|
||||
* @param String $having Escaped SQL statement
|
||||
*/
|
||||
@ -464,7 +464,7 @@ class DataQuery {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the WHERE clause of this query.
|
||||
* Append a WHERE clause to this query.
|
||||
* There are two different ways of doing this:
|
||||
*
|
||||
* <code>
|
||||
@ -485,7 +485,7 @@ class DataQuery {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a WHERE with OR.
|
||||
* Append a WHERE with OR.
|
||||
*
|
||||
* @example $dataQuery->whereAny(array("\"Monkey\" = 'Chimp'", "\"Color\" = 'Brown'"));
|
||||
* @see where()
|
||||
|
@ -718,6 +718,11 @@ class Image extends File {
|
||||
return self::ORIENTATION_SQUARE;
|
||||
}
|
||||
}
|
||||
|
||||
public function onAfterUpload() {
|
||||
$this->deleteFormattedImages();
|
||||
parent::onAfterUpload();
|
||||
}
|
||||
|
||||
protected function onBeforeDelete() {
|
||||
parent::onBeforeDelete();
|
||||
|
@ -57,6 +57,7 @@ class ChangePasswordForm extends Form {
|
||||
* Change the password
|
||||
*
|
||||
* @param array $data The user submitted data
|
||||
* @return SS_HTTPResponse
|
||||
*/
|
||||
public function doChangePassword(array $data) {
|
||||
if($member = Member::currentUser()) {
|
||||
@ -68,8 +69,7 @@ class ChangePasswordForm extends Form {
|
||||
"bad"
|
||||
);
|
||||
// redirect back to the form, instead of using redirectBack() which could send the user elsewhere.
|
||||
$this->controller->redirect($this->controller->Link('changepassword'));
|
||||
return;
|
||||
return $this->controller->redirect($this->controller->Link('changepassword'));
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,8 +81,7 @@ class ChangePasswordForm extends Form {
|
||||
// The user is not logged in and no valid auto login hash is available
|
||||
if(!$member) {
|
||||
Session::clear('AutoLoginHash');
|
||||
$this->controller->redirect($this->controller->Link('login'));
|
||||
return;
|
||||
return $this->controller->redirect($this->controller->Link('login'));
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,8 +93,7 @@ class ChangePasswordForm extends Form {
|
||||
"bad");
|
||||
|
||||
// redirect back to the form, instead of using redirectBack() which could send the user elsewhere.
|
||||
$this->controller->redirect($this->controller->Link('changepassword'));
|
||||
return;
|
||||
return $this->controller->redirect($this->controller->Link('changepassword'));
|
||||
}
|
||||
else if($data['NewPassword1'] == $data['NewPassword2']) {
|
||||
$isValid = $member->changePassword($data['NewPassword1']);
|
||||
@ -115,7 +113,7 @@ class ChangePasswordForm extends Form {
|
||||
// absolute redirection URLs may cause spoofing
|
||||
&& Director::is_site_url($_REQUEST['BackURL'])
|
||||
) {
|
||||
$this->controller->redirect($_REQUEST['BackURL']);
|
||||
return $this->controller->redirect($_REQUEST['BackURL']);
|
||||
}
|
||||
else {
|
||||
// Redirect to default location - the login form saying "You are logged in as..."
|
||||
@ -123,7 +121,7 @@ class ChangePasswordForm extends Form {
|
||||
'BackURL',
|
||||
Director::absoluteBaseURL(), $this->controller->Link('login')
|
||||
);
|
||||
$this->controller->redirect($redirectURL);
|
||||
return $this->controller->redirect($redirectURL);
|
||||
}
|
||||
} else {
|
||||
$this->clearMessage();
|
||||
@ -137,7 +135,7 @@ class ChangePasswordForm extends Form {
|
||||
);
|
||||
|
||||
// redirect back to the form, instead of using redirectBack() which could send the user elsewhere.
|
||||
$this->controller->redirect($this->controller->Link('changepassword'));
|
||||
return $this->controller->redirect($this->controller->Link('changepassword'));
|
||||
}
|
||||
|
||||
} else {
|
||||
@ -147,7 +145,7 @@ class ChangePasswordForm extends Form {
|
||||
"bad");
|
||||
|
||||
// redirect back to the form, instead of using redirectBack() which could send the user elsewhere.
|
||||
$this->controller->redirect($this->controller->Link('changepassword'));
|
||||
return $this->controller->redirect($this->controller->Link('changepassword'));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,9 +80,16 @@ class MemberLoginForm extends LoginForm {
|
||||
new HiddenField("AuthenticationMethod", null, $this->authenticator_class, $this),
|
||||
// Regardless of what the unique identifer field is (usually 'Email'), it will be held in the
|
||||
// 'Email' value, below:
|
||||
new TextField("Email", $label, Session::get('SessionForms.MemberLoginForm.Email'), null, $this),
|
||||
$emailField = new TextField("Email", $label, null, null, $this),
|
||||
new PasswordField("Password", _t('Member.PASSWORD', 'Password'))
|
||||
);
|
||||
if(Security::config()->remember_username) {
|
||||
$emailField->setValue(Session::get('SessionForms.MemberLoginForm.Email'));
|
||||
} else {
|
||||
// Some browsers won't respect this attribute unless it's added to the form
|
||||
$this->setAttribute('autocomplete', 'off');
|
||||
$emailField->setAttribute('autocomplete', 'off');
|
||||
}
|
||||
if(Security::config()->autologin_enabled) {
|
||||
$fields->push(new CheckboxField(
|
||||
"Remember",
|
||||
@ -114,13 +121,13 @@ class MemberLoginForm extends LoginForm {
|
||||
$this->setValidator(new RequiredFields('Email', 'Password'));
|
||||
|
||||
// Focus on the email input when the page is loaded
|
||||
Requirements::customScript(<<<JS
|
||||
$js = <<<JS
|
||||
(function() {
|
||||
var el = document.getElementById("MemberLoginForm_LoginForm_Email");
|
||||
if(el && el.focus) el.focus();
|
||||
if(el && el.focus && (!jQuery || jQuery(el).is(':visible'))) el.focus();
|
||||
})();
|
||||
JS
|
||||
);
|
||||
JS;
|
||||
Requirements::customScript($js, 'MemberLoginFormFieldFocus');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -63,6 +63,15 @@ class Security extends Controller implements TemplateGlobalProvider {
|
||||
*/
|
||||
private static $autologin_enabled = true;
|
||||
|
||||
/**
|
||||
* Determine if login username may be remembered between login sessions
|
||||
* If set to false this will disable autocomplete and prevent username persisting in the session
|
||||
*
|
||||
* @config
|
||||
* @var bool
|
||||
*/
|
||||
private static $remember_username = true;
|
||||
|
||||
/**
|
||||
* Location of word list to use for generating passwords
|
||||
*
|
||||
|
@ -41,6 +41,9 @@ class DirectorTest extends SapphireTest {
|
||||
public function tearDown() {
|
||||
// TODO Remove director rule, currently API doesnt allow this
|
||||
|
||||
// Remove base URL override (setting to false reverts to default behaviour)
|
||||
Director::setBaseURL(false);
|
||||
|
||||
// Reinstate the original REQUEST_URI after it was modified by some tests
|
||||
$_SERVER['REQUEST_URI'] = self::$originalRequestURI;
|
||||
|
||||
@ -72,6 +75,40 @@ class DirectorTest extends SapphireTest {
|
||||
|
||||
unlink($tempFilePath);
|
||||
}
|
||||
|
||||
public function testAbsoluteURL() {
|
||||
|
||||
$rootURL = Director::protocolAndHost();
|
||||
$_SERVER['REQUEST_URI'] = "$rootURL/mysite/sub-page/";
|
||||
Director::setBaseURL('/mysite/');
|
||||
|
||||
// Test already absolute url
|
||||
$this->assertEquals($rootURL, Director::absoluteURL($rootURL));
|
||||
$this->assertEquals($rootURL, Director::absoluteURL($rootURL, true));
|
||||
$this->assertEquals('http://www.mytest.com', Director::absoluteURL('http://www.mytest.com'));
|
||||
$this->assertEquals('http://www.mytest.com', Director::absoluteURL('http://www.mytest.com', true));
|
||||
$this->assertEquals("$rootURL/test", Director::absoluteURL("$rootURL/test"));
|
||||
$this->assertEquals("$rootURL/test", Director::absoluteURL("$rootURL/test", true));
|
||||
|
||||
// Test relative to base
|
||||
$this->assertEquals("$rootURL/mysite/test", Director::absoluteURL("test", true));
|
||||
$this->assertEquals("$rootURL/mysite/test/url", Director::absoluteURL("test/url", true));
|
||||
$this->assertEquals("$rootURL/root", Director::absoluteURL("/root", true));
|
||||
$this->assertEquals("$rootURL/root/url", Director::absoluteURL("/root/url", true));
|
||||
|
||||
// Test relative to requested page
|
||||
$this->assertEquals("$rootURL/mysite/sub-page/test", Director::absoluteURL("test"));
|
||||
// Legacy behaviour resolves this to $rootURL/mysite/test/url
|
||||
//$this->assertEquals("$rootURL/mysite/sub-page/test/url", Director::absoluteURL("test/url"));
|
||||
$this->assertEquals("$rootURL/root", Director::absoluteURL("/root"));
|
||||
$this->assertEquals("$rootURL/root/url", Director::absoluteURL("/root/url"));
|
||||
|
||||
// Test that javascript links are not left intact
|
||||
$this->assertStringStartsNotWith('javascript', Director::absoluteURL('javascript:alert("attack")'));
|
||||
$this->assertStringStartsNotWith('alert', Director::absoluteURL('javascript:alert("attack")'));
|
||||
$this->assertStringStartsNotWith('javascript', Director::absoluteURL('alert("attack")'));
|
||||
$this->assertStringStartsNotWith('alert', Director::absoluteURL('alert("attack")'));
|
||||
}
|
||||
|
||||
public function testAlternativeBaseURL() {
|
||||
// relative base URLs - you should end them in a /
|
||||
|
@ -465,6 +465,48 @@ class UploadTest extends SapphireTest {
|
||||
$file3->delete();
|
||||
}
|
||||
|
||||
public function testDeleteResampledImagesOnUpload() {
|
||||
$tmpFileName = 'UploadTest-testUpload.jpg';
|
||||
$tmpFilePath = TEMP_FOLDER . '/' . $tmpFileName;
|
||||
|
||||
$uploadImage = function() use ($tmpFileName, $tmpFilePath) {
|
||||
copy(__DIR__ . '/gdtest/test_jpg.jpg', $tmpFilePath);
|
||||
|
||||
// emulates the $_FILES array
|
||||
$tmpFile = array(
|
||||
'name' => $tmpFileName,
|
||||
'type' => 'text/plaintext',
|
||||
'size' => filesize($tmpFilePath),
|
||||
'tmp_name' => $tmpFilePath,
|
||||
'extension' => 'jpg',
|
||||
'error' => UPLOAD_ERR_OK,
|
||||
);
|
||||
|
||||
$v = new UploadTest_Validator();
|
||||
|
||||
// test upload into default folder
|
||||
$u = new Upload();
|
||||
$u->setReplaceFile(true);
|
||||
$u->setValidator($v);
|
||||
$u->load($tmpFile);
|
||||
return $u->getFile();
|
||||
};
|
||||
|
||||
// Image upload and generate a resampled image
|
||||
$image = $uploadImage();
|
||||
$resampled = $image->ResizedImage(123, 456);
|
||||
$resampledPath = $resampled->getFullPath();
|
||||
$this->assertTrue(file_exists($resampledPath));
|
||||
|
||||
// Re-upload the image, overwriting the original
|
||||
// Resampled images should removed when their parent file is overwritten
|
||||
$image = $uploadImage();
|
||||
$this->assertFalse(file_exists($resampledPath));
|
||||
|
||||
unlink($tmpFilePath);
|
||||
$image->delete();
|
||||
}
|
||||
|
||||
}
|
||||
class UploadTest_Validator extends Upload_Validator implements TestOnly {
|
||||
|
||||
|
@ -15,6 +15,8 @@ class SecurityTest extends FunctionalTest {
|
||||
protected $priorDefaultAuthenticator = null;
|
||||
|
||||
protected $priorUniqueIdentifierField = null;
|
||||
|
||||
protected $priorRememberUsername = null;
|
||||
|
||||
public function setUp() {
|
||||
// This test assumes that MemberAuthenticator is present and the default
|
||||
@ -29,6 +31,7 @@ class SecurityTest extends FunctionalTest {
|
||||
|
||||
// And that the unique identified field is 'Email'
|
||||
$this->priorUniqueIdentifierField = Member::config()->unique_identifier_field;
|
||||
$this->priorRememberUsername = Security::config()->remember_username;
|
||||
Member::config()->unique_identifier_field = 'Email';
|
||||
|
||||
parent::setUp();
|
||||
@ -48,6 +51,7 @@ class SecurityTest extends FunctionalTest {
|
||||
|
||||
// Restore unique identifier field
|
||||
Member::config()->unique_identifier_field = $this->priorUniqueIdentifierField;
|
||||
Security::config()->remember_username = $this->priorRememberUsername;
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
@ -124,6 +128,32 @@ class SecurityTest extends FunctionalTest {
|
||||
$this->session()->inst_set('loggedInAs', null);
|
||||
}
|
||||
|
||||
public function testLoginUsernamePersists() {
|
||||
// Test that username does not persist
|
||||
$this->session()->inst_set('SessionForms.MemberLoginForm.Email', 'myuser@silverstripe.com');
|
||||
Security::config()->remember_username = false;
|
||||
$this->get(Config::inst()->get('Security', 'login_url'));
|
||||
$items = $this->cssParser()->getBySelector('#MemberLoginForm_LoginForm #Email input.text');
|
||||
$this->assertEquals(1, count($items));
|
||||
$this->assertEmpty((string)$items[0]->attributes()->value);
|
||||
$this->assertEquals('off', (string)$items[0]->attributes()->autocomplete);
|
||||
$form = $this->cssParser()->getBySelector('#MemberLoginForm_LoginForm');
|
||||
$this->assertEquals(1, count($form));
|
||||
$this->assertEquals('off', (string)$form[0]->attributes()->autocomplete);
|
||||
|
||||
// Test that username does persist when necessary
|
||||
$this->session()->inst_set('SessionForms.MemberLoginForm.Email', 'myuser@silverstripe.com');
|
||||
Security::config()->remember_username = true;
|
||||
$this->get(Config::inst()->get('Security', 'login_url'));
|
||||
$items = $this->cssParser()->getBySelector('#MemberLoginForm_LoginForm #Email input.text');
|
||||
$this->assertEquals(1, count($items));
|
||||
$this->assertEquals('myuser@silverstripe.com', (string)$items[0]->attributes()->value);
|
||||
$this->assertNotEquals('off', (string)$items[0]->attributes()->autocomplete);
|
||||
$form = $this->cssParser()->getBySelector('#MemberLoginForm_LoginForm');
|
||||
$this->assertEquals(1, count($form));
|
||||
$this->assertNotEquals('off', (string)$form[0]->attributes()->autocomplete);
|
||||
}
|
||||
|
||||
public function testExternalBackUrlRedirectionDisallowed() {
|
||||
// Test internal relative redirect
|
||||
$response = $this->doTestLoginForm('noexpiry@silverstripe.com', '1nitialPassword', 'testpage');
|
||||
|
8
thirdparty/tinymce/tiny_mce_gzip.php
vendored
8
thirdparty/tinymce/tiny_mce_gzip.php
vendored
@ -94,17 +94,17 @@ class TinyMCE_Compressor {
|
||||
$plugins = self::getParam("plugins");
|
||||
if ($plugins)
|
||||
$this->settings["plugins"] = $plugins;
|
||||
$plugins = explode(',', $this->settings["plugins"]);
|
||||
$plugins = array_unique(explode(',', $this->settings["plugins"]));
|
||||
|
||||
$themes = self::getParam("themes");
|
||||
if ($themes)
|
||||
$this->settings["themes"] = $themes;
|
||||
$themes = explode(',', $this->settings["themes"]);
|
||||
$themes = array_unique(explode(',', $this->settings["themes"]));
|
||||
|
||||
$languages = self::getParam("languages");
|
||||
if ($languages)
|
||||
$this->settings["languages"] = $languages;
|
||||
$languages = explode(',', $this->settings["languages"]);
|
||||
$languages = array_unique(explode(',', $this->settings["languages"]));
|
||||
|
||||
$tagFiles = self::getParam("files");
|
||||
if ($tagFiles)
|
||||
@ -140,7 +140,7 @@ class TinyMCE_Compressor {
|
||||
}
|
||||
|
||||
// Add any specified files.
|
||||
$allFiles = array_merge($files, explode(',', $this->settings['files']));
|
||||
$allFiles = array_merge($files, array_unique(explode(',', $this->settings['files'])));
|
||||
|
||||
// Process source files
|
||||
for ($i = 0; $i < count($allFiles); $i++) {
|
||||
|
Loading…
Reference in New Issue
Block a user