Merge branch '3.1'

This commit is contained in:
Sean Harvey 2014-02-12 11:06:54 +13:00
commit 9048eab4a2
13 changed files with 106 additions and 35 deletions

View File

@ -418,7 +418,7 @@ class Injector {
// and reload the object; existing bindings don't get // and reload the object; existing bindings don't get
// updated though! (for now...) // updated though! (for now...)
if (isset($this->serviceCache[$id])) { if (isset($this->serviceCache[$id])) {
$this->instantiate($spec, $id); $this->instantiate(array('class'=>$id), $id);
} }
} }
} }

View File

@ -9,7 +9,7 @@
* @todo Add support for deep chaining of relation properties (e.g. Player.Team.Stats.GoalCount) * @todo Add support for deep chaining of relation properties (e.g. Player.Team.Stats.GoalCount)
* @todo Character conversion * @todo Character conversion
* *
* @see http://rfc.net/rfc4180.html * @see http://tools.ietf.org/html/rfc4180
* @package framework * @package framework
* @subpackage bulkloading * @subpackage bulkloading
* @author Ingo Schommer, Silverstripe Ltd. (<firstname>@silverstripe.com) * @author Ingo Schommer, Silverstripe Ltd. (<firstname>@silverstripe.com)

View File

@ -6,7 +6,7 @@
* Uses the fgetcsv() function to process CSV input. Accepts a file-handler as * Uses the fgetcsv() function to process CSV input. Accepts a file-handler as
* input. * input.
* *
* @see http://rfc.net/rfc4180.html * @see http://tools.ietf.org/html/rfc4180
* *
* @package framework * @package framework
* @subpackage bulkloading * @subpackage bulkloading

View File

@ -34,7 +34,7 @@ instead make it easier for developers to build other applications.
## Finding Modules ## Finding Modules
* [Official module list on silverstripe.org](http://silverstripe.org/modules) * [Official module list on silverstripe.org](http://addons.silverstripe.org/)
* [Packagist.org "silverstripe" tag](https://packagist.org/search/?tags=silverstripe) * [Packagist.org "silverstripe" tag](https://packagist.org/search/?tags=silverstripe)
* [Github.com "silverstripe" search](https://github.com/search?q=silverstripe&ref=commandbar) * [Github.com "silverstripe" search](https://github.com/search?q=silverstripe&ref=commandbar)

View File

@ -129,17 +129,12 @@ class Upload extends Controller {
$base = Director::baseFolder(); $base = Director::baseFolder();
$parentFolder = Folder::find_or_make($folderPath); $parentFolder = Folder::find_or_make($folderPath);
// Create a folder for uploading.
if(!file_exists(ASSETS_PATH . "/" . $folderPath)){
Filesystem::makeFolder(ASSETS_PATH . "/" . $folderPath);
}
// Generate default filename // Generate default filename
$nameFilter = FileNameFilter::create(); $nameFilter = FileNameFilter::create();
$file = $nameFilter->filter($tmpFile['name']); $file = $nameFilter->filter($tmpFile['name']);
$fileName = basename($file); $fileName = basename($file);
$relativeFilePath = ASSETS_DIR . "/" . $folderPath . "/$fileName"; $relativeFilePath = $parentFolder->getRelativePath() . "/$fileName";
// Create a new file record (or try to retrieve an existing one) // Create a new file record (or try to retrieve an existing one)
if(!$this->file) { if(!$this->file) {

View File

@ -292,10 +292,20 @@ class Form extends RequestHandler {
// Protection against CSRF attacks // Protection against CSRF attacks
$token = $this->getSecurityToken(); $token = $this->getSecurityToken();
if(!$token->checkRequest($request)) { if( ! $token->checkRequest($request)) {
$this->httpError(400, _t("Form.CSRF_FAILED_MESSAGE", if (empty($vars['SecurityID'])) {
"There seems to have been a technical problem. Please click the back button," $this->httpError(400, _t("Form.CSRF_FAILED_MESSAGE",
. " refresh your browser, and try again.")); "There seems to have been a technical problem. Please click the back button,
refresh your browser, and try again."));
} else {
Session::set("FormInfo.{$this->FormName()}.data", $this->getData());
Session::set("FormInfo.{$this->FormName()}.errors", array());
$this->sessionMessage(
_t("Form.CSRF_EXPIRED_MESSAGE", "Your session has expired. Please re-submit the form."),
"warning"
);
return $this->controller->redirectBack();
}
} }
// Determine the action button clicked // Determine the action button clicked

View File

@ -957,8 +957,8 @@ class UploadField extends FileField {
Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.js'); Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.js');
Requirements::javascript(THIRDPARTY_DIR . '/jquery-ui/jquery-ui.js'); Requirements::javascript(THIRDPARTY_DIR . '/jquery-ui/jquery-ui.js');
Requirements::javascript(THIRDPARTY_DIR . '/jquery-entwine/dist/jquery.entwine-dist.js'); Requirements::javascript(THIRDPARTY_DIR . '/jquery-entwine/dist/jquery.entwine-dist.js');
Requirements::javascript(FRAMEWORK_DIR . '/javascript/i18n.js');
Requirements::javascript(FRAMEWORK_ADMIN_DIR . '/javascript/ssui.core.js'); Requirements::javascript(FRAMEWORK_ADMIN_DIR . '/javascript/ssui.core.js');
Requirements::add_i18n_javascript(FRAMEWORK_DIR . '/javascript/lang');
Requirements::combine_files('uploadfield.js', array( Requirements::combine_files('uploadfield.js', array(
// @todo jquery templates is a project no longer maintained and should be retired at some point. // @todo jquery templates is a project no longer maintained and should be retired at some point.

View File

@ -249,4 +249,4 @@ abstract class SS_Query implements Iterator {
* @return array * @return array
*/ */
abstract public function seek($rowNum); abstract public function seek($rowNum);
} }

View File

@ -44,7 +44,8 @@ class SS_Transliterator extends Object {
'þ'=>'b', 'ÿ'=>'y', 'Ŕ'=>'R', 'ŕ'=>'r', 'þ'=>'b', 'ÿ'=>'y', 'Ŕ'=>'R', 'ŕ'=>'r',
'Ā'=>'A', 'ā'=>'a', 'Ē'=>'E', 'ē'=>'e', 'Ī'=>'I', 'ī'=>'i', 'Ō'=>'O', 'ō'=>'o', 'Ū'=>'U', 'ū'=>'u', 'Ā'=>'A', 'ā'=>'a', 'Ē'=>'E', 'ē'=>'e', 'Ī'=>'I', 'ī'=>'i', 'Ō'=>'O', 'ō'=>'o', 'Ū'=>'U', 'ū'=>'u',
'œ'=>'oe', 'ß'=>'ss', 'ij'=>'ij', 'ą'=>'a','ę'=>'e', 'ė'=>'e', 'į'=>'i','ų'=>'u','ū'=>'u', 'Ą'=>'A', 'œ'=>'oe', 'ß'=>'ss', 'ij'=>'ij', 'ą'=>'a','ę'=>'e', 'ė'=>'e', 'į'=>'i','ų'=>'u','ū'=>'u', 'Ą'=>'A',
'Ę'=>'E', 'Ė'=>'E', 'Į'=>'I','Ų'=>'U','Ū'=>'u' 'Ę'=>'E', 'Ė'=>'E', 'Į'=>'I','Ų'=>'U','Ū'=>'u',
"ľ"=>"l", "Ľ"=>"L", "ť"=>"t", "Ť"=>"T", "ů"=>"u", "Ů"=>"U",
); );
return strtr($source, $table); return strtr($source, $table);

View File

@ -54,24 +54,41 @@ class SS_Datetime extends Date implements TemplateGlobalProvider {
} }
/** /**
* Returns the date in the raw SQL-format, e.g. “2006-01-18 16:32:04 * Returns the date and time (in 12-hour format) using the format string 'd/m/Y g:ia' e.g. '31/01/2014 2:23pm'.
* @return string Formatted date and time.
*/ */
public function Nice() { public function Nice() {
if($this->value) return $this->Format('d/m/Y g:ia'); if($this->value) return $this->Format('d/m/Y g:ia');
} }
/**
* Returns the date and time (in 24-hour format) using the format string 'd/m/Y H:i' e.g. '28/02/2014 13:32'.
* @return string Formatted date and time.
*/
public function Nice24() { public function Nice24() {
if($this->value) return $this->Format('d/m/Y H:i'); if($this->value) return $this->Format('d/m/Y H:i');
} }
/**
* Returns the date using the format string 'd/m/Y' e.g. '28/02/2014'.
* @return string Formatted date.
*/
public function Date() { public function Date() {
if($this->value) return $this->Format('d/m/Y'); if($this->value) return $this->Format('d/m/Y');
} }
/**
* Returns the time in 12-hour format using the format string 'g:ia' e.g. '1:32pm'.
* @return string Formatted time.
*/
public function Time() { public function Time() {
if($this->value) return $this->Format('g:ia'); if($this->value) return $this->Format('g:ia');
} }
/**
* Returns the time in 24-hour format using the format string 'H:i' e.g. '13:32'.
* @return string Formatted time.
*/
public function Time24() { public function Time24() {
if($this->value) return $this->Format('H:i'); if($this->value) return $this->Format('H:i');
} }
@ -81,7 +98,13 @@ class SS_Datetime extends Date implements TemplateGlobalProvider {
$values=Array('type'=>'SS_Datetime', 'parts'=>$parts); $values=Array('type'=>'SS_Datetime', 'parts'=>$parts);
DB::requireField($this->tableName, $this->name, $values); DB::requireField($this->tableName, $this->name, $values);
} }
/**
* Returns the url encoded date and time in ISO 6801 format using format
* string 'Y-m-d%20H:i:s' e.g. '2014-02-28%2013:32:22'.
*
* @return string Formatted date and time.
*/
public function URLDatetime() { public function URLDatetime() {
if($this->value) return $this->Format('Y-m-d%20H:i:s'); if($this->value) return $this->Format('Y-m-d%20H:i:s');
} }

View File

@ -10,4 +10,5 @@
</div> </div>
<% if $RightTitle %><label class="right">$RightTitle</label><% end_if %> <% if $RightTitle %><label class="right">$RightTitle</label><% end_if %>
<% if $Message %><span class="message $MessageType">$Message</span><% end_if %> <% if $Message %><span class="message $MessageType">$Message</span><% end_if %>
<% if $Description %><span class="description">$Description</span><% end_if %>
</div> </div>

View File

@ -320,7 +320,22 @@ class FormTest extends FunctionalTest {
) )
); );
$this->assertEquals(400, $response->getStatusCode(), 'Submission fails without security token'); $this->assertEquals(400, $response->getStatusCode(), 'Submission fails without security token');
$response = $this->get('FormTest_ControllerWithSecurityToken');
$response = $this->post(
'FormTest_ControllerWithSecurityToken/Form',
array(
'Email' => 'test@test.com',
'action_doSubmit' => 1,
'SecurityID' => -1
)
);
$this->assertEquals(200, $response->getStatusCode(), 'Submission reloads form if security token invalid');
$matched = $this->cssParser()->getBySelector('#Form_Form_Email');
$attrs = $matched[0]->attributes();
$this->assertEquals('test@test.com', (string)$attrs['value'], 'Submitted data is preserved');
$response = $this->get('FormTest_ControllerWithSecurityToken'); $response = $this->get('FormTest_ControllerWithSecurityToken');
$tokenEls = $this->cssParser()->getBySelector('#Form_Form_SecurityID'); $tokenEls = $this->cssParser()->getBySelector('#Form_Form_SecurityID');
$this->assertEquals( $this->assertEquals(

View File

@ -358,19 +358,28 @@ class SQLQueryTest extends SapphireTest {
$query->setFrom('"SQLQueryTest_DO"'); $query->setFrom('"SQLQueryTest_DO"');
$query->setOrderBy('"Name"'); $query->setOrderBy('"Name"');
$result = $query->firstRow()->execute(); $result = $query->firstRow()->execute();
$this->assertCount(1, $result); $records = array();
foreach($result as $row) { foreach($result as $row) {
$this->assertEquals('Object 1', $row['Name']); $records[] = $row;
} }
$this->assertCount(1, $records);
$this->assertEquals('Object 1', $records[0]['Name']);
// Test first from empty sequence // Test first from empty sequence
$query = new SQLQuery(); $query = new SQLQuery();
$query->setFrom('"SQLQueryTest_DO"'); $query->setFrom('"SQLQueryTest_DO"');
$query->setOrderBy('"Name"'); $query->setOrderBy('"Name"');
$query->setWhere(array("\"Name\" = 'Nonexistent Object'")); $query->setWhere(array("\"Name\" = 'Nonexistent Object'"));
$result = $query->firstRow()->execute(); $result = $query->firstRow()->execute();
$this->assertCount(0, $result);
$records = array();
foreach($result as $row) {
$records[] = $row;
}
$this->assertCount(0, $records);
// Test that given the last item, the 'first' in this list matches the last // Test that given the last item, the 'first' in this list matches the last
$query = new SQLQuery(); $query = new SQLQuery();
@ -378,10 +387,14 @@ class SQLQueryTest extends SapphireTest {
$query->setOrderBy('"Name"'); $query->setOrderBy('"Name"');
$query->setLimit(1, 1); $query->setLimit(1, 1);
$result = $query->firstRow()->execute(); $result = $query->firstRow()->execute();
$this->assertCount(1, $result);
$records = array();
foreach($result as $row) { foreach($result as $row) {
$this->assertEquals('Object 2', $row['Name']); $records[] = $row;
} }
$this->assertCount(1, $records);
$this->assertEquals('Object 2', $records[0]['Name']);
} }
public function testSelectLast() { public function testSelectLast() {
@ -391,11 +404,14 @@ class SQLQueryTest extends SapphireTest {
$query->setFrom('"SQLQueryTest_DO"'); $query->setFrom('"SQLQueryTest_DO"');
$query->setOrderBy('"Name"'); $query->setOrderBy('"Name"');
$result = $query->lastRow()->execute(); $result = $query->lastRow()->execute();
$this->assertCount(1, $result); $records = array();
foreach($result as $row) { foreach($result as $row) {
$this->assertEquals('Object 2', $row['Name']); $records[] = $row;
} }
$this->assertCount(1, $records);
$this->assertEquals('Object 2', $records[0]['Name']);
// Test last from empty sequence // Test last from empty sequence
$query = new SQLQuery(); $query = new SQLQuery();
@ -403,20 +419,30 @@ class SQLQueryTest extends SapphireTest {
$query->setOrderBy('"Name"'); $query->setOrderBy('"Name"');
$query->setWhere(array("\"Name\" = 'Nonexistent Object'")); $query->setWhere(array("\"Name\" = 'Nonexistent Object'"));
$result = $query->lastRow()->execute(); $result = $query->lastRow()->execute();
$this->assertCount(0, $result);
$records = array();
foreach($result as $row) {
$records[] = $row;
}
$this->assertCount(0, $records);
// Test that given the first item, the 'last' in this list matches the first // Test that given the first item, the 'last' in this list matches the first
$query = new SQLQuery(); $query = new SQLQuery();
$query->setFrom('"SQLQueryTest_DO"'); $query->setFrom('"SQLQueryTest_DO"');
$query->setOrderBy('"Name"'); $query->setOrderBy('"Name"');
$query->setLimit(1); $query->setLimit(1);
$result = $query->lastRow()->execute(); $result = $query->lastRow()->execute();
$this->assertCount(1, $result);
$records = array();
foreach($result as $row) { foreach($result as $row) {
$this->assertEquals('Object 1', $row['Name']); $records[] = $row;
} }
$this->assertCount(1, $records);
$this->assertEquals('Object 1', $records[0]['Name']);
} }
/** /**
* Tests aggregate() function * Tests aggregate() function
*/ */