From 7026a488e617f7a1b7e31ee598a5c340d12397b3 Mon Sep 17 00:00:00 2001 From: Mateusz Uzdowski Date: Mon, 23 May 2011 18:12:31 +1200 Subject: [PATCH 01/17] BUGFIX: for date manipulation use the SS_Datetime::now, otherwise it does not respect the mock date. --- model/fieldtypes/Date.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/model/fieldtypes/Date.php b/model/fieldtypes/Date.php index f789dd82c..effeda1b6 100644 --- a/model/fieldtypes/Date.php +++ b/model/fieldtypes/Date.php @@ -302,7 +302,7 @@ class Date extends DBField { * @return boolean */ public function InPast() { - return strtotime($this->value) < time(); + return strtotime($this->value) < SS_Datetime::now()->Format('U'); } /** @@ -310,7 +310,7 @@ class Date extends DBField { * @return boolean */ public function InFuture() { - return strtotime($this->value) > time(); + return strtotime($this->value) > SS_Datetime::now()->Format('U'); } /** @@ -318,7 +318,7 @@ class Date extends DBField { * @return boolean */ public function IsToday() { - return (date('Y-m-d', strtotime($this->value)) == date('Y-m-d', time())); + return (date('Y-m-d', strtotime($this->value)) == SS_Datetime::now()->Format('Y-m-d')); } /** From 5e6f5f9f7e3e15df4056873df60b8be64189e01e Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Thu, 10 Jan 2013 12:33:20 +1300 Subject: [PATCH 02/17] NEW: Allow configuration of send_all_emails_to, ccs_all_emails_to, and bcc_all_emails_to via the config system. --- conf/ConfigureFromEnv.php | 2 +- dev/SapphireTest.php | 3 +- email/Email.php | 66 +++++++++++++++++++++++++++++---------- 3 files changed, 52 insertions(+), 19 deletions(-) diff --git a/conf/ConfigureFromEnv.php b/conf/ConfigureFromEnv.php index a994f2880..5fc8a6461 100644 --- a/conf/ConfigureFromEnv.php +++ b/conf/ConfigureFromEnv.php @@ -105,7 +105,7 @@ if(defined('SS_DATABASE_USERNAME') && defined('SS_DATABASE_PASSWORD')) { } if(defined('SS_SEND_ALL_EMAILS_TO')) { - Email::send_all_emails_to(SS_SEND_ALL_EMAILS_TO); + Config::inst()->update("Email","send_all_emails_to", SS_SEND_ALL_EMAILS_TO); } if(defined('SS_DEFAULT_ADMIN_USERNAME')) { diff --git a/dev/SapphireTest.php b/dev/SapphireTest.php index efeb8f842..ab555b952 100644 --- a/dev/SapphireTest.php +++ b/dev/SapphireTest.php @@ -206,7 +206,7 @@ class SapphireTest extends PHPUnit_Framework_TestCase { $className = get_class($this); $fixtureFile = eval("return {$className}::\$fixture_file;"); $prefix = defined('SS_DATABASE_PREFIX') ? SS_DATABASE_PREFIX : 'ss_'; - + // Todo: this could be a special test model $this->model = DataModel::inst(); @@ -263,6 +263,7 @@ class SapphireTest extends PHPUnit_Framework_TestCase { $this->originalMailer = Email::mailer(); $this->mailer = new TestMailer(); Email::set_mailer($this->mailer); + Config::inst()->remove('Email', 'send_all_emails_to'); Email::send_all_emails_to(null); // Preserve memory settings diff --git a/email/Email.php b/email/Email.php index 0a95099be..9c82f014a 100644 --- a/email/Email.php +++ b/email/Email.php @@ -125,16 +125,43 @@ class Email extends ViewableData { static $admin_email_address = ''; /** + * Send every email generated by the Email class to the given address. + * + * It will also add " [addressed to (email), cc to (email), bcc to (email)]" to the end of the subject line + * + * To set this, set Email.send_all_emails_to in your yml config file. + * It can also be set in _ss_environment.php with SS_SEND_ALL_EMAILS_TO. + * * @param string $send_all_emails_to Email-Address */ protected static $send_all_emails_to = null; /** + * BCC every email generated by the Email class to the given address. + * It won't affect the original delivery in the same way that send_all_emails_to does. It just adds a BCC header + * with the given email address. Note that you can only call this once - subsequent calls will overwrite the + * configuration variable. + * + * This can be used when you have a system that relies heavily on email and you want someone to be checking all + * correspondence. + * + * To set this, set Email.bcc_all_emails_to in your yml config file. + * * @param string $bcc_all_emails_to Email-Address */ protected static $bcc_all_emails_to = null; /** + * CC every email generated by the Email class to the given address. + * It won't affect the original delivery in the same way that send_all_emails_to does. It just adds a CC header + * with the given email address. Note that you can only call this once - subsequent calls will overwrite the + * configuration variable. + * + * This can be used when you have a system that relies heavily on email and you want someone to be checking all + * correspondence. + * + * To set this, set Email.cc_all_emails_to in your yml config file. + * * @param string $cc_all_emails_to Email-Address */ protected static $cc_all_emails_to = null; @@ -400,30 +427,32 @@ class Email extends ViewableData { $to = $this->to; $subject = $this->subject; - if(self::$send_all_emails_to) { + if($sendAllTo = $this->config()->send_all_emails_to) { $subject .= " [addressed to $to"; - $to = self::$send_all_emails_to; + $to = $sendAllTo; if($this->cc) $subject .= ", cc to $this->cc"; if($this->bcc) $subject .= ", bcc to $this->bcc"; $subject .= ']'; + unset($headers['Cc']); + unset($headers['Bcc']); } else { if($this->cc) $headers['Cc'] = $this->cc; if($this->bcc) $headers['Bcc'] = $this->bcc; } - if(self::$cc_all_emails_to) { + if($ccAllTo = $this->config()->cc_all_emails_to) { if(!empty($headers['Cc']) && trim($headers['Cc'])) { - $headers['Cc'] .= ', ' . self::$cc_all_emails_to; + $headers['Cc'] .= ', ' . $ccAllTo; } else { - $headers['Cc'] = self::$cc_all_emails_to; + $headers['Cc'] = $ccAllTo; } } - if(self::$bcc_all_emails_to) { + if($bccAllTo = $this->config()->bcc_all_emails_to) { if(!empty($headers['Bcc']) && trim($headers['Bcc'])) { - $headers['Bcc'] .= ', ' . self::$bcc_all_emails_to; + $headers['Bcc'] .= ', ' . $bccAllTo; } else { - $headers['Bcc'] = self::$bcc_all_emails_to; + $headers['Bcc'] = $bccAllTo; } } @@ -459,34 +488,37 @@ class Email extends ViewableData { if(project()) $headers['X-SilverStripeSite'] = project(); + $to = $this->to; $subject = $this->subject; - if(self::$send_all_emails_to) { + if($sendAllTo = $this->config()->send_all_emails_to) { $subject .= " [addressed to $to"; - $to = self::$send_all_emails_to; + $to = $sendAllTo; if($this->cc) $subject .= ", cc to $this->cc"; if($this->bcc) $subject .= ", bcc to $this->bcc"; $subject .= ']'; unset($headers['Cc']); unset($headers['Bcc']); + } else { if($this->cc) $headers['Cc'] = $this->cc; if($this->bcc) $headers['Bcc'] = $this->bcc; } - if(self::$cc_all_emails_to) { + + if($ccAllTo = $this->config()->cc_all_emails_to) { if(!empty($headers['Cc']) && trim($headers['Cc'])) { - $headers['Cc'] .= ', ' . self::$cc_all_emails_to; + $headers['Cc'] .= ', ' . $ccAllTo; } else { - $headers['Cc'] = self::$cc_all_emails_to; + $headers['Cc'] = $ccAllTo; } } - - if(self::$bcc_all_emails_to) { + + if($bccAllTo = $this->config()->bcc_all_emails_to) { if(!empty($headers['Bcc']) && trim($headers['Bcc'])) { - $headers['Bcc'] .= ', ' . self::$bcc_all_emails_to; + $headers['Bcc'] .= ', ' . $bccAllTo; } else { - $headers['Bcc'] = self::$bcc_all_emails_to; + $headers['Bcc'] = $bccAllTo; } } From c3a3ff4438f91d23ddc8ef1617e866c3a1f0692d Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Wed, 2 Mar 2011 18:23:07 +1300 Subject: [PATCH 03/17] NEW: Added Email::send_all_emails_from() setting. --- conf/ConfigureFromEnv.php | 4 ++++ email/Email.php | 31 +++++++++++++++++++++++++++---- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/conf/ConfigureFromEnv.php b/conf/ConfigureFromEnv.php index 5fc8a6461..ffa0beb99 100644 --- a/conf/ConfigureFromEnv.php +++ b/conf/ConfigureFromEnv.php @@ -41,6 +41,7 @@ * * Email: * - SS_SEND_ALL_EMAILS_TO: If you set this define, all emails will be redirected to this address. + * - SS_SEND_ALL_EMAILS_FROM: If you set this define, all emails will be send from this address. * * @package framework * @subpackage core @@ -107,6 +108,9 @@ if(defined('SS_DATABASE_USERNAME') && defined('SS_DATABASE_PASSWORD')) { if(defined('SS_SEND_ALL_EMAILS_TO')) { Config::inst()->update("Email","send_all_emails_to", SS_SEND_ALL_EMAILS_TO); } +if(defined('SS_SEND_ALL_EMAILS_FROM')) { + Config::inst()->update("Email","send_all_emails_from", SS_SEND_ALL_EMAILS_FROM); +} if(defined('SS_DEFAULT_ADMIN_USERNAME')) { if(!defined('SS_DEFAULT_ADMIN_PASSWORD')) { diff --git a/email/Email.php b/email/Email.php index 9c82f014a..e677e7969 100644 --- a/email/Email.php +++ b/email/Email.php @@ -135,6 +135,17 @@ class Email extends ViewableData { * @param string $send_all_emails_to Email-Address */ protected static $send_all_emails_to = null; + + /** + * Send every email generated by the Email class *from* the given address. + * It will also add " [, from to (email)]" to the end of the subject line + * + * To set this, set Email.send_all_emails_from in your yml config file. + * It can also be set in _ss_environment.php with SS_SEND_ALL_EMAILS_FROM. + * + * @param string $send_all_emails_from Email-Address + */ + protected static $send_all_emails_from = null; /** * BCC every email generated by the Email class to the given address. @@ -426,6 +437,7 @@ class Email extends ViewableData { if(project()) $headers['X-SilverStripeSite'] = project(); $to = $this->to; + $from = $this->from; $subject = $this->subject; if($sendAllTo = $this->config()->send_all_emails_to) { $subject .= " [addressed to $to"; @@ -456,9 +468,14 @@ class Email extends ViewableData { } } + if($sendAllfrom = $this->config()->send_all_emails_from) { + if($from) $subject .= " [from $from]"; + $from = $sendAllfrom; + } + Requirements::restore(); - return self::mailer()->sendPlain($to, $this->from, $subject, $this->body, $this->attachments, $headers); + return self::mailer()->sendPlain($to, $from, $subject, $this->body, $this->attachments, $headers); } /** @@ -490,6 +507,7 @@ class Email extends ViewableData { $to = $this->to; + $from = $this->from; $subject = $this->subject; if($sendAllTo = $this->config()->send_all_emails_to) { $subject .= " [addressed to $to"; @@ -521,10 +539,15 @@ class Email extends ViewableData { $headers['Bcc'] = $bccAllTo; } } - + + if($sendAllfrom = $this->config()->send_all_emails_from) { + if($from) $subject .= " [from $from]"; + $from = $sendAllfrom; + } + Requirements::restore(); - return self::mailer()->sendHTML($to, $this->from, $subject, $this->body, $this->attachments, $headers, + return self::mailer()->sendHTML($to, $from, $subject, $this->body, $this->attachments, $headers, $this->plaintext_body); } @@ -558,7 +581,7 @@ class Email extends ViewableData { public static function send_all_emails_to($emailAddress) { self::$send_all_emails_to = $emailAddress; } - + /** * CC every email generated by the Email class to the given address. * It won't affect the original delivery in the same way that send_all_emails_to does. It just adds a CC header From b7a1db7ce31f4712a6578d9db88f6f0601a0a11a Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Sat, 21 May 2011 14:42:26 +1200 Subject: [PATCH 04/17] FIX: Set up the test mailer before loading the fixture, in case fixture-creation causes emails to be generated. --- dev/SapphireTest.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/dev/SapphireTest.php b/dev/SapphireTest.php index ab555b952..20faa60e4 100644 --- a/dev/SapphireTest.php +++ b/dev/SapphireTest.php @@ -205,8 +205,16 @@ class SapphireTest extends PHPUnit_Framework_TestCase { $className = get_class($this); $fixtureFile = eval("return {$className}::\$fixture_file;"); + $prefix = defined('SS_DATABASE_PREFIX') ? SS_DATABASE_PREFIX : 'ss_'; + // Set up email + $this->originalMailer = Email::mailer(); + $this->mailer = new TestMailer(); + Email::set_mailer($this->mailer); + Config::inst()->remove('Email', 'send_all_emails_to'); + Email::send_all_emails_to(null); + // Todo: this could be a special test model $this->model = DataModel::inst(); @@ -259,13 +267,6 @@ class SapphireTest extends PHPUnit_Framework_TestCase { $this->logInWithPermission("ADMIN"); } - // Set up email - $this->originalMailer = Email::mailer(); - $this->mailer = new TestMailer(); - Email::set_mailer($this->mailer); - Config::inst()->remove('Email', 'send_all_emails_to'); - Email::send_all_emails_to(null); - // Preserve memory settings $this->originalMemoryLimit = ini_get('memory_limit'); From 33a1fc7b3adeedb92f138321243deb3bffd66cc4 Mon Sep 17 00:00:00 2001 From: Carlos Barberis Date: Wed, 20 Apr 2011 17:37:17 +1200 Subject: [PATCH 05/17] FIX: Fixed operation of inlined images in Mailer, when no inlined images actually attached. --- email/Mailer.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/email/Mailer.php b/email/Mailer.php index 6a0c23a81..1202b1530 100644 --- a/email/Mailer.php +++ b/email/Mailer.php @@ -291,7 +291,7 @@ function encodeMultipart($parts, $contentType, $headers = false) { */ function wrapImagesInline($htmlContent) { global $_INLINED_IMAGES; - $_INLINED_IMAGES = null; + $_INLINED_IMAGES = array(); $replacedContent = imageRewriter($htmlContent, 'wrapImagesInline_rewriter($URL)'); @@ -303,8 +303,8 @@ function wrapImagesInline($htmlContent) { // Make all the image parts global $_INLINED_IMAGES; - foreach($_INLINED_IMAGES as $url => $cid) { - $multiparts[] = encodeFileForEmail($url, false, "inline", "Content-ID: <$cid>\n"); + if($_INLINED_IMAGES) foreach($_INLINED_IMAGES as $url => $cid) { + $multiparts[] = encodeFileForEmail(BASE_PATH . '/' . $url, false, "inline", "Content-ID: <$cid>\n"); } // Merge together in a multipart @@ -312,10 +312,10 @@ function wrapImagesInline($htmlContent) { return processHeaders($headers, $body); } function wrapImagesInline_rewriter($url) { - $url = relativiseURL($url); + $url = Director::makeRelative($url); global $_INLINED_IMAGES; - if(!$_INLINED_IMAGES[$url]) { + if(!isset($_INLINED_IMAGES[$url])) { $identifier = "automatedmessage." . rand(1000,1000000000) . "@silverstripe.com"; $_INLINED_IMAGES[$url] = $identifier; } @@ -384,6 +384,7 @@ function encodeFileForEmail($file, $destFileName = false, $disposition = NULL, $ $file = array('filename' => $file); $fh = fopen($file['filename'], "rb"); if ($fh) { + $file['contents'] = ""; while(!feof($fh)) $file['contents'] .= fread($fh, 10000); fclose($fh); } @@ -393,12 +394,12 @@ function encodeFileForEmail($file, $destFileName = false, $disposition = NULL, $ if(!$destFileName) $base = basename($file['filename']); else $base = $destFileName; - $mimeType = $file['mimetype'] ? $file['mimetype'] : HTTP::get_mime_type($file['filename']); + $mimeType = !empty($file['mimetype']) ? $file['mimetype'] : HTTP::get_mime_type($file['filename']); if(!$mimeType) $mimeType = "application/unknown"; if (empty($disposition)) $disposition = isset($file['contentLocation']) ? 'inline' : 'attachment'; // Encode for emailing - if (substr($file['mimetype'], 0, 4) != 'text') { + if (substr($mimeType, 0, 4) != 'text') { $encoding = "base64"; $file['contents'] = chunk_split(base64_encode($file['contents'])); } else { From d8bfc0bb48c16aaa3235d36b43782f485b182d04 Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Wed, 16 Mar 2011 16:13:14 +1300 Subject: [PATCH 06/17] API CHANGE: Added Security::set_login_url() so that you can define an alternative log-in page if you have made one yourself. --- dev/Debug.php | 2 +- security/Security.php | 22 +++++++++++++++++++++- tests/control/DirectorTest.php | 2 +- tests/security/SecurityTest.php | 11 +++++++---- 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/dev/Debug.php b/dev/Debug.php index 9d42ddcc2..fef951a70 100644 --- a/dev/Debug.php +++ b/dev/Debug.php @@ -652,7 +652,7 @@ class Debug { $_SESSION['Security']['Message']['type'] = 'warning'; $_SESSION['BackURL'] = $_SERVER['REQUEST_URI']; header($_SERVER['SERVER_PROTOCOL'] . " 302 Found"); - header("Location: " . Director::baseURL() . "Security/login"); + header("Location: " . Director::baseURL() . Security::login_url()); die(); } } diff --git a/security/Security.php b/security/Security.php index f8da0e029..112fda9e2 100644 --- a/security/Security.php +++ b/security/Security.php @@ -242,7 +242,10 @@ class Security extends Controller { // Audit logging hook $controller->extend('permissionDenied', $member); - $controller->redirect("Security/login?BackURL=" . urlencode($_SERVER['REQUEST_URI'])); + $controller->redirect( + Config::inst()->get('Security', 'login_url') + . "?BackURL=" . urlencode($_SERVER['REQUEST_URI']) + ); } return; } @@ -927,8 +930,25 @@ class Security extends Controller { public static function set_ignore_disallowed_actions($flag) { self::$ignore_disallowed_actions = $flag; } + public static function ignore_disallowed_actions() { return self::$ignore_disallowed_actions; } + protected static $login_url = "Security/login"; + + /** + * Set a custom log-in URL if you have built your own log-in page. + */ + public static function set_login_url($loginUrl) { + self::$login_url = $loginUrl; + } + /** + * Get the URL of the log-in page. + * Defaults to Security/login but can be re-set with {@link set_login_url()} + */ + public static function login_url() { + return self::$login_url; + } + } diff --git a/tests/control/DirectorTest.php b/tests/control/DirectorTest.php index a157c59a6..48359bed3 100644 --- a/tests/control/DirectorTest.php +++ b/tests/control/DirectorTest.php @@ -252,7 +252,7 @@ class DirectorTest extends SapphireTest { } public function testForceSSLOnSubPagesPattern() { - $_SERVER['REQUEST_URI'] = Director::baseURL() . 'Security/login'; + $_SERVER['REQUEST_URI'] = Director::baseURL() . Config::inst()->get('Security', 'login_url'); $output = Director::forceSSL(array('/^Security/')); $this->assertEquals($output, 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']); } diff --git a/tests/security/SecurityTest.php b/tests/security/SecurityTest.php index 6337e1b71..3325d09f9 100644 --- a/tests/security/SecurityTest.php +++ b/tests/security/SecurityTest.php @@ -57,7 +57,10 @@ class SecurityTest extends FunctionalTest { $response = $this->get('SecurityTest_SecuredController'); $this->assertEquals(302, $response->getStatusCode()); - $this->assertContains('Security/login', $response->getHeader('Location')); + $this->assertContains( + Config::inst()->get('Security', 'login_url'), + $response->getHeader('Location') + ); $this->logInWithPermission('ADMIN'); $response = $this->get('SecurityTest_SecuredController'); @@ -74,7 +77,7 @@ class SecurityTest extends FunctionalTest { $this->session()->inst_set('loggedInAs', $member->ID); /* View the Security/login page */ - $response = $this->get('Security/login'); + $response = $this->get(Config::inst()->get('Security', 'login_url')); $items = $this->cssParser()->getBySelector('#MemberLoginForm_LoginForm input.action'); @@ -108,7 +111,7 @@ class SecurityTest extends FunctionalTest { $this->autoFollowRedirection = true; /* Attempt to get into the admin section */ - $response = $this->get('Security/login/'); + $response = $this->get(Config::inst()->get('Security', 'login_url')); $items = $this->cssParser()->getBySelector('#MemberLoginForm_LoginForm input.text'); @@ -396,7 +399,7 @@ class SecurityTest extends FunctionalTest { public function doTestLoginForm($email, $password, $backURL = 'test/link') { $this->get('Security/logout'); $this->session()->inst_set('BackURL', $backURL); - $this->get('Security/login'); + $this->get(Config::inst()->get('Security', 'login_url')); return $this->submitForm( "MemberLoginForm_LoginForm", From 1e1df8c43eb9ecb055c4abc57cc64a38096ff65c Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Mon, 12 Dec 2011 18:44:47 +1300 Subject: [PATCH 07/17] BUGFIX: Improved detection of empty HTMLText fields. --- model/fieldtypes/HTMLText.php | 15 ++++++++++++++- tests/model/HTMLTextTest.php | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/model/fieldtypes/HTMLText.php b/model/fieldtypes/HTMLText.php index bfb20e5a3..54e0ac9d6 100644 --- a/model/fieldtypes/HTMLText.php +++ b/model/fieldtypes/HTMLText.php @@ -136,8 +136,21 @@ class HTMLText extends Text { return ShortcodeParser::get_active()->parse($this->value); } + /** + * Returns true if the field has meaningful content. + * Excludes null content like

,

,etc + * + * @return boolean + */ public function exists() { - return parent::exists() && $this->value != '

'; + // If it's blank, it's blank + if(!parent::exists()) return false; + // If it's got a content tag + if(preg_match('/<(img|embed|object|iframe)[^>]*>/i', $this->value)) return true; + // If it's just one or two tags on its own (and not the above) it's empty. This might be

or

or whatever. + if(preg_match('/^[\\s]*(<[^>]+>[\\s]*){1,2}$/', $this->value)) return false; + // Otherwise its content is genuine content + return true; } public function scaffoldFormField($title = null, $params = null) { diff --git a/tests/model/HTMLTextTest.php b/tests/model/HTMLTextTest.php index f1fda34bc..a5ed4856c 100644 --- a/tests/model/HTMLTextTest.php +++ b/tests/model/HTMLTextTest.php @@ -139,4 +139,38 @@ class HTMLTextTest extends SapphireTest { $data = DBField::create_field('HTMLText', '"this is a test"'); $this->assertEquals($data->ATT(), '"this is a test"'); } + + function testExists() { + $h = new HTMLText; + $h->setValue(""); + $this->assertFalse($h->exists()); + $h->setValue("

"); + $this->assertFalse($h->exists()); + $h->setValue("

"); + $this->assertFalse($h->exists()); + $h->setValue("

"); + $this->assertFalse($h->exists()); + $h->setValue("

"); + $this->assertFalse($h->exists()); + + $h->setValue("something"); + $this->assertTrue($h->exists()); + $h->setValue(""); + $this->assertTrue($h->exists()); + $h->setValue(""); + $this->assertTrue($h->exists()); + $h->setValue("

"); + $this->assertTrue($h->exists()); + + $h->setValue(""); + $this->assertTrue($h->exists()); + $h->setValue(""); + $this->assertTrue($h->exists()); + $h->setValue(""); + $this->assertTrue($h->exists()); + + + $h->setValue("

test

"); + $this->assertTrue($h->exists()); + } } From 47e037e74ccbc70069f4339936f0984235bd1138 Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Fri, 29 Apr 2011 15:12:21 +1200 Subject: [PATCH 08/17] FIX: Removed notice-level error after forms w/ required fields are made readonly. --- forms/RequiredFields.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forms/RequiredFields.php b/forms/RequiredFields.php index a0e46278b..d58211413 100644 --- a/forms/RequiredFields.php +++ b/forms/RequiredFields.php @@ -35,7 +35,7 @@ class RequiredFields extends Validator { * Clears all the validation from this object. */ public function removeValidation(){ - $this->required = null; + $this->required = array(); } /** From 55f3ec1371ce80c3905c9dcdf2ece615c4ca34b8 Mon Sep 17 00:00:00 2001 From: Jean-Fabien Date: Thu, 26 May 2011 18:42:59 +1200 Subject: [PATCH 09/17] FIX: Added error message fields to default search form --- templates/SearchForm.ss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/templates/SearchForm.ss b/templates/SearchForm.ss index f3d195d0a..c6a525d1e 100644 --- a/templates/SearchForm.ss +++ b/templates/SearchForm.ss @@ -1,4 +1,9 @@
+ <% if Message %> +

$Message

+ <% else %> + + <% end_if %>
<% loop Fields %> $FieldHolder From f72c77e984d1f71e1ae6016533d0a09146da72a8 Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Fri, 1 Apr 2011 10:36:04 +1300 Subject: [PATCH 10/17] MINOR: Fixed a glitch that causes warnings in cli-script execution. --- control/Director.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/control/Director.php b/control/Director.php index 86684bc67..cab2d598c 100644 --- a/control/Director.php +++ b/control/Director.php @@ -725,6 +725,9 @@ class Director implements TemplateGlobalProvider { $matched = false; if($patterns) { + // Calling from the command-line? + if(!isset($_SERVER['REQUEST_URI'])) return; + // protect portions of the site based on the pattern $relativeURL = self::makeRelative(Director::absoluteURL($_SERVER['REQUEST_URI'])); foreach($patterns as $pattern) { From f8206d15c81b161af13494e9e978794b947fb3c1 Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Mon, 18 Apr 2011 16:44:11 +1200 Subject: [PATCH 11/17] BUGFIX: Prevent notice-level error in Session code when non-array is turned into an array. --- control/Session.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/control/Session.php b/control/Session.php index e86616da7..d0326c5f4 100644 --- a/control/Session.php +++ b/control/Session.php @@ -415,7 +415,7 @@ class Session { protected function recursivelyApply($data, &$dest) { foreach($data as $k => $v) { if(is_array($v)) { - if(!isset($dest[$k])) $dest[$k] = array(); + if(!isset($dest[$k]) || !is_array($dest[$k])) $dest[$k] = array(); $this->recursivelyApply($v, $dest[$k]); } else { $dest[$k] = $v; From 82988d421bb28ef0e04f0fea8c6c6fd60c54c58a Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Fri, 11 Mar 2011 15:09:52 +1300 Subject: [PATCH 12/17] BUGFIX: Better error message when 401 response is corrupted. --- control/HTTPResponse.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/control/HTTPResponse.php b/control/HTTPResponse.php index 16a801838..1a0a38c06 100644 --- a/control/HTTPResponse.php +++ b/control/HTTPResponse.php @@ -220,11 +220,17 @@ class SS_HTTPResponse { "; } else { - if(!headers_sent()) { + $line = $file = null; + if(!headers_sent($file, $line)) { header($_SERVER['SERVER_PROTOCOL'] . " $this->statusCode " . $this->getStatusDescription()); foreach($this->headers as $header => $value) { header("$header: $value", true, $this->statusCode); } + } else { + // It's critical that these status codes are sent; we need to report a failure if not. + if($this->statusCode >= 300) { + user_error("Couldn't set response type to $this->statusCode because of output on line $line of $file", E_USER_WARNING); + } } // Only show error pages or generic "friendly" errors if the status code signifies From 6fcbad1a31519cdfeb0f2587100166097bba3833 Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Tue, 15 Mar 2011 18:30:16 +1300 Subject: [PATCH 13/17] BUGFIX: Updated SilverStripe error handler so that log_errors still works. --- dev/Debug.php | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/dev/Debug.php b/dev/Debug.php index fef951a70..e29ee24ff 100644 --- a/dev/Debug.php +++ b/dev/Debug.php @@ -213,6 +213,7 @@ class Debug { public static function noticeHandler($errno, $errstr, $errfile, $errline, $errcontext) { if(error_reporting() == 0) return; + ini_set('display_errors', 0); // Send out the error details to the logger for writing SS_Log::log( @@ -227,7 +228,9 @@ class Debug { ); if(Director::isDev()) { - self::showError($errno, $errstr, $errfile, $errline, $errcontext, "Notice"); + return self::showError($errno, $errstr, $errfile, $errline, $errcontext, "Notice"); + } else { + return false; } } @@ -242,8 +245,10 @@ class Debug { */ public static function warningHandler($errno, $errstr, $errfile, $errline, $errcontext) { if(error_reporting() == 0) return; + ini_set('display_errors', 0); + if(self::$send_warnings_to) { - self::emailError(self::$send_warnings_to, $errno, $errstr, $errfile, $errline, $errcontext, "Warning"); + return self::emailError(self::$send_warnings_to, $errno, $errstr, $errfile, $errline, $errcontext, "Warning"); } // Send out the error details to the logger for writing @@ -263,8 +268,10 @@ class Debug { } if(Director::isDev()) { - self::showError($errno, $errstr, $errfile, $errline, $errcontext, "Warning"); - } + return self::showError($errno, $errstr, $errfile, $errline, $errcontext, "Warning"); + } else { + return false; + } } /** @@ -279,6 +286,8 @@ class Debug { * @param unknown_type $errcontext */ public static function fatalHandler($errno, $errstr, $errfile, $errline, $errcontext) { + ini_set('display_errors', 0); + if(self::$send_errors_to) { self::emailError(self::$send_errors_to, $errno, $errstr, $errfile, $errline, $errcontext, "Error"); } @@ -300,11 +309,10 @@ class Debug { } if(Director::isDev() || Director::is_cli()) { - self::showError($errno, $errstr, $errfile, $errline, $errcontext, "Error"); + return self::showError($errno, $errstr, $errfile, $errline, $errcontext, "Error"); } else { - self::friendlyError(); + return self::friendlyError(); } - exit(1); } /** @@ -363,6 +371,7 @@ class Debug { $renderer->writeFooter(); } } + return false; } /** @@ -679,7 +688,7 @@ function exceptionHandler($exception) { $file = $exception->getFile(); $line = $exception->getLine(); $context = $exception->getTrace(); - Debug::fatalHandler($errno, $message, $file, $line, $context); + return Debug::fatalHandler($errno, $message, $file, $line, $context); } /** @@ -698,21 +707,18 @@ function errorHandler($errno, $errstr, $errfile, $errline) { case E_ERROR: case E_CORE_ERROR: case E_USER_ERROR: - Debug::fatalHandler($errno, $errstr, $errfile, $errline, debug_backtrace()); - break; + return Debug::fatalHandler($errno, $errstr, $errfile, $errline, debug_backtrace()); case E_WARNING: case E_CORE_WARNING: case E_USER_WARNING: - Debug::warningHandler($errno, $errstr, $errfile, $errline, debug_backtrace()); - break; + return Debug::warningHandler($errno, $errstr, $errfile, $errline, debug_backtrace()); case E_NOTICE: case E_USER_NOTICE: case E_DEPRECATED: case E_USER_DEPRECATED: case E_STRICT: - Debug::noticeHandler($errno, $errstr, $errfile, $errline, debug_backtrace()); - break; + return Debug::noticeHandler($errno, $errstr, $errfile, $errline, debug_backtrace()); } } From b43bf68f9c5b1396ae50db6a1ea087efb7b3b19f Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Tue, 30 Aug 2011 23:40:29 +1200 Subject: [PATCH 14/17] MINOR: Minor fixes to FunctionalTest --- dev/TestSession.php | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/dev/TestSession.php b/dev/TestSession.php index 4e81e312a..afb71eb7f 100644 --- a/dev/TestSession.php +++ b/dev/TestSession.php @@ -96,8 +96,12 @@ class TestSession { $form->setField(new SimpleByName($k), $v); } - if($button) $submission = $form->submitButton(new SimpleByName($button)); - else $submission = $form->submit(); + if($button) { + $submission = $form->submitButton(new SimpleByName($button)); + if(!$submission) throw new Exception("Can't find button '$button' to submit as part of test."); + } else { + $submission = $form->submit(); + } $url = Director::makeRelative($form->getAction()->asString()); @@ -137,6 +141,15 @@ class TestSession { return $this->lastResponse; } + /** + * Return the fake HTTP_REFERER; set each time get() or post() is called. + * + * @return string + */ + public function lastUrl() { + return $this->lastUrl; + } + /** * Get the most recent response's content */ From b6fd27663aa38524ad127fb6756741689e324503 Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Thu, 18 Aug 2011 23:32:40 +1200 Subject: [PATCH 15/17] MINOR: Don't throw redirection warning if redirection to the same place. --- control/Controller.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/control/Controller.php b/control/Controller.php index b74549628..47066074f 100644 --- a/control/Controller.php +++ b/control/Controller.php @@ -454,7 +454,7 @@ class Controller extends RequestHandler implements TemplateGlobalProvider { public function redirect($url, $code=302) { if(!$this->response) $this->response = new SS_HTTPResponse(); - if($this->response->getHeader('Location')) { + if($this->response->getHeader('Location') && $this->response->getHeader('Location') != $url) { user_error("Already directed to " . $this->response->getHeader('Location') . "; now trying to direct to $url", E_USER_WARNING); return; From 9a2ba483dfe3207bb18c2571a7ee31fbbef27f38 Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Thu, 1 Sep 2011 15:41:33 +1200 Subject: [PATCH 16/17] BUGFIX: Made CSRF-error wording friendlier. --- forms/Form.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/forms/Form.php b/forms/Form.php index 2417f3b84..1f30b1371 100644 --- a/forms/Form.php +++ b/forms/Form.php @@ -250,7 +250,9 @@ class Form extends RequestHandler { // Protection against CSRF attacks $token = $this->getSecurityToken(); if(!$token->checkRequest($request)) { - $this->httpError(400, "Sorry, your session has timed out."); + $this->httpError(400, _t("Form.CSRF_FAILED_MESSAGE", + "There seems to have been a technical problem. Please click the back button," + . " refresh your browser, and try again.")); } // Determine the action button clicked From c4dde9022df3b2d1bbdaa6468301ddeeaccda48f Mon Sep 17 00:00:00 2001 From: Sam Minnee Date: Tue, 16 Oct 2012 18:24:40 +1300 Subject: [PATCH 17/17] NEW: Allow hashes to be passed as ArrayList items; the will be turned into ArrayData objects. --- model/ArrayList.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/model/ArrayList.php b/model/ArrayList.php index 4335b405c..cd1a203d0 100644 --- a/model/ArrayList.php +++ b/model/ArrayList.php @@ -55,6 +55,9 @@ class ArrayList extends ViewableData implements SS_List, SS_Filterable, SS_Sorta * @return ArrayIterator */ public function getIterator() { + foreach($this->items as $i => $item) { + if(is_array($item)) $this->items[$i] = new ArrayData($item); + } return new ArrayIterator($this->items); }