/**
  * Get the locale of the Member, or if we're not logged in or don't have a locale, use the default one
  * @return string
  */
 protected function locale()
 {
     if (($member = Member::currentUser()) && $member->Locale) {
         return $member->Locale;
     }
     return i18n::get_locale();
 }
 public function setUp()
 {
     parent::setUp();
     $this->originalLocale = i18n::get_locale();
     i18n::set_locale('en_NZ');
     $this->origTimeConfig = Config::inst()->get('SilverStripe\\Forms\\TimeField', 'default_config');
     Config::inst()->update('SilverStripe\\Forms\\TimeField', 'default_config', array('timeformat' => 'HH:mm:ss'));
 }
 public function setUp()
 {
     parent::setUp();
     $this->originalLocale = i18n::get_locale();
     i18n::set_locale('en_NZ');
     $this->origConfig = Config::inst()->get('SilverStripe\\Forms\\DateField', 'default_config');
     Config::inst()->update('SilverStripe\\Forms\\DateField', 'default_config', array('dateformat' => 'dd/MM/yyyy'));
 }
 public function __construct($name, $title = null, $value = "")
 {
     if (!$this->locale) {
         $this->locale = i18n::get_locale();
     }
     $this->config = $this->config()->default_config;
     if (!$this->getConfig('timeformat')) {
         $this->setConfig('timeformat', i18n::config()->get('time_format'));
     }
     parent::__construct($name, $title, $value);
 }
 /**
  * @return String
  */
 public function Locale()
 {
     return DBField::create_field('Locale', i18n::get_locale());
 }
 /**
  * Write a Money object to the database, then re-read it to ensure it
  * is re-read properly.
  */
 public function testGettingWrittenDataObject()
 {
     $local = i18n::get_locale();
     //make sure that the $ amount is not prefixed by US$, as it would be in non-US locale
     i18n::set_locale('en_US');
     $obj = new MoneyTest_DataObject();
     $m = new DBMoney();
     $m->setAmount(987.65);
     $m->setCurrency('USD');
     $obj->MyMoney = $m;
     $this->assertEquals("\$987.65", $obj->MyMoney->Nice(), "Money field not added to data object properly when read prior to first writing the record.");
     $objID = $obj->write();
     $moneyTest = DataObject::get_by_id('MoneyTest_DataObject', $objID);
     $this->assertTrue($moneyTest instanceof MoneyTest_DataObject);
     $this->assertEquals('USD', $moneyTest->MyMoneyCurrency);
     $this->assertEquals(987.65, $moneyTest->MyMoneyAmount);
     $this->assertEquals("\$987.65", $moneyTest->MyMoney->Nice(), "Money field not added to data object properly when read.");
     i18n::set_locale($local);
 }
 public function testRepeatedLoginAttemptsLockingPeopleOut()
 {
     $local = i18n::get_locale();
     i18n::set_locale('en_US');
     Member::config()->lock_out_after_incorrect_logins = 5;
     Member::config()->lock_out_delay_mins = 15;
     // Login with a wrong password for more than the defined threshold
     for ($i = 1; $i <= Member::config()->lock_out_after_incorrect_logins + 1; $i++) {
         $this->doTestLoginForm('*****@*****.**', 'incorrectpassword');
         $member = DataObject::get_by_id("SilverStripe\\Security\\Member", $this->idFromFixture('SilverStripe\\Security\\Member', 'test'));
         if ($i < Member::config()->lock_out_after_incorrect_logins) {
             $this->assertNull($member->LockedOutUntil, 'User does not have a lockout time set if under threshold for failed attempts');
             $this->assertContains($this->loginErrorMessage(), Convert::raw2xml(_t('Member.ERRORWRONGCRED')));
         } else {
             // Fuzzy matching for time to avoid side effects from slow running tests
             $this->assertGreaterThan(time() + 14 * 60, strtotime($member->LockedOutUntil), 'User has a lockout time set after too many failed attempts');
         }
         $msg = _t('Member.ERRORLOCKEDOUT2', 'Your account has been temporarily disabled because of too many failed attempts at ' . 'logging in. Please try again in {count} minutes.', null, array('count' => Member::config()->lock_out_delay_mins));
         if ($i > Member::config()->lock_out_after_incorrect_logins) {
             $this->assertContains($msg, $this->loginErrorMessage());
         }
     }
     $this->doTestLoginForm('*****@*****.**', '1nitialPassword');
     $this->assertNull($this->session()->inst_get('loggedInAs'), 'The user can\'t log in after being locked out, even with the right password');
     // (We fake this by re-setting LockedOutUntil)
     $member = DataObject::get_by_id("SilverStripe\\Security\\Member", $this->idFromFixture('SilverStripe\\Security\\Member', 'test'));
     $member->LockedOutUntil = date('Y-m-d H:i:s', time() - 30);
     $member->write();
     $this->doTestLoginForm('*****@*****.**', '1nitialPassword');
     $this->assertEquals($this->session()->inst_get('loggedInAs'), $member->ID, 'After lockout expires, the user can login again');
     // Log the user out
     $this->session()->inst_set('loggedInAs', null);
     // Login again with wrong password, but less attempts than threshold
     for ($i = 1; $i < Member::config()->lock_out_after_incorrect_logins; $i++) {
         $this->doTestLoginForm('*****@*****.**', 'incorrectpassword');
     }
     $this->assertNull($this->session()->inst_get('loggedInAs'));
     $this->assertContains($this->loginErrorMessage(), Convert::raw2xml(_t('Member.ERRORWRONGCRED')), 'The user can retry with a wrong password after the lockout expires');
     $this->doTestLoginForm('*****@*****.**', '1nitialPassword');
     $this->assertEquals($this->session()->inst_get('loggedInAs'), $member->ID, 'The user can login successfully after lockout expires, if staying below the threshold');
     i18n::set_locale($local);
 }
 public function testCollectFromFilesystemAndWriteMasterTables()
 {
     $local = i18n::get_locale();
     i18n::set_locale('en_US');
     //set the locale to the US locale expected in the asserts
     i18n::config()->update('default_locale', 'en_US');
     $c = new i18nTextCollector();
     $c->setWriter(new i18nTextCollector_Writer_RailsYaml());
     $c->basePath = $this->alternateBasePath;
     $c->baseSavePath = $this->alternateBaseSavePath;
     $c->run();
     // i18ntestmodule
     $moduleLangFile = "{$this->alternateBaseSavePath}/i18ntestmodule/lang/" . $c->getDefaultLocale() . '.yml';
     $this->assertTrue(file_exists($moduleLangFile), 'Master language file can be written to modules /lang folder');
     $moduleLangFileContent = file_get_contents($moduleLangFile);
     $this->assertContains("    ADDITION: Addition\n", $moduleLangFileContent);
     $this->assertContains("    ENTITY: 'Entity with \"Double Quotes\"'\n", $moduleLangFileContent);
     $this->assertContains("    MAINTEMPLATE: 'Main Template'\n", $moduleLangFileContent);
     $this->assertContains("    OTHERENTITY: 'Other Entity'\n", $moduleLangFileContent);
     $this->assertContains("    WITHNAMESPACE: 'Include Entity with Namespace'\n", $moduleLangFileContent);
     $this->assertContains("    NONAMESPACE: 'Include Entity without Namespace'\n", $moduleLangFileContent);
     // i18nothermodule
     $otherModuleLangFile = "{$this->alternateBaseSavePath}/i18nothermodule/lang/" . $c->getDefaultLocale() . '.yml';
     $this->assertTrue(file_exists($otherModuleLangFile), 'Master language file can be written to modules /lang folder');
     $otherModuleLangFileContent = file_get_contents($otherModuleLangFile);
     $this->assertContains("    ENTITY: 'Other Module Entity'\n", $otherModuleLangFileContent);
     $this->assertContains("    MAINTEMPLATE: 'Main Template Other Module'\n", $otherModuleLangFileContent);
     // testtheme1
     $theme1LangFile = "{$this->alternateBaseSavePath}/themes/testtheme1/lang/" . $c->getDefaultLocale() . '.yml';
     $this->assertTrue(file_exists($theme1LangFile), 'Master theme language file can be written to themes/testtheme1 /lang folder');
     $theme1LangFileContent = file_get_contents($theme1LangFile);
     $this->assertContains("    MAINTEMPLATE: 'Theme1 Main Template'\n", $theme1LangFileContent);
     $this->assertContains("    LAYOUTTEMPLATE: 'Theme1 Layout Template'\n", $theme1LangFileContent);
     $this->assertContains("    SPRINTFNAMESPACE: 'Theme1 My replacement: %s'\n", $theme1LangFileContent);
     $this->assertContains("    LAYOUTTEMPLATENONAMESPACE: 'Theme1 Layout Template no namespace'\n", $theme1LangFileContent);
     $this->assertContains("    SPRINTFNONAMESPACE: 'Theme1 My replacement no namespace: %s'\n", $theme1LangFileContent);
     $this->assertContains("    SPRINTFINCLUDENAMESPACE: 'Theme1 My include replacement: %s'\n", $theme1LangFileContent);
     $this->assertContains("    WITHNAMESPACE: 'Theme1 Include Entity with Namespace'\n", $theme1LangFileContent);
     $this->assertContains("    NONAMESPACE: 'Theme1 Include Entity without Namespace'\n", $theme1LangFileContent);
     $this->assertContains("    SPRINTFINCLUDENONAMESPACE: 'Theme1 My include replacement no namespace: %s'\n", $theme1LangFileContent);
     // testtheme2
     $theme2LangFile = "{$this->alternateBaseSavePath}/themes/testtheme2/lang/" . $c->getDefaultLocale() . '.yml';
     $this->assertTrue(file_exists($theme2LangFile), 'Master theme language file can be written to themes/testtheme2 /lang folder');
     $theme2LangFileContent = file_get_contents($theme2LangFile);
     $this->assertContains("    MAINTEMPLATE: 'Theme2 Main Template'\n", $theme2LangFileContent);
     i18n::set_locale($local);
     //set the locale to the US locale expected in the asserts
 }
 public function testCoreGlobalVariableCalls()
 {
     $this->assertEquals(Director::absoluteBaseURL(), $this->render('{$absoluteBaseURL}'), 'Director::absoluteBaseURL can be called from within template');
     $this->assertEquals(Director::absoluteBaseURL(), $this->render('{$AbsoluteBaseURL}'), 'Upper-case %AbsoluteBaseURL can be called from within template');
     $this->assertEquals(Director::is_ajax(), $this->render('{$isAjax}'), 'All variations of is_ajax result in the correct call');
     $this->assertEquals(Director::is_ajax(), $this->render('{$IsAjax}'), 'All variations of is_ajax result in the correct call');
     $this->assertEquals(Director::is_ajax(), $this->render('{$is_ajax}'), 'All variations of is_ajax result in the correct call');
     $this->assertEquals(Director::is_ajax(), $this->render('{$Is_ajax}'), 'All variations of is_ajax result in the correct call');
     $this->assertEquals(i18n::get_locale(), $this->render('{$i18nLocale}'), 'i18n template functions result correct result');
     $this->assertEquals(i18n::get_locale(), $this->render('{$get_locale}'), 'i18n template functions result correct result');
     $this->assertEquals((string) Member::currentUser(), $this->render('{$CurrentMember}'), 'Member template functions result correct result');
     $this->assertEquals((string) Member::currentUser(), $this->render('{$CurrentUser}'), 'Member template functions result correct result');
     $this->assertEquals((string) Member::currentUser(), $this->render('{$currentMember}'), 'Member template functions result correct result');
     $this->assertEquals((string) Member::currentUser(), $this->render('{$currentUser}'), 'Member template functions result correct result');
     $this->assertEquals(SecurityToken::getSecurityID(), $this->render('{$getSecurityID}'), 'SecurityToken template functions result correct result');
     $this->assertEquals(SecurityToken::getSecurityID(), $this->render('{$SecurityID}'), 'SecurityToken template functions result correct result');
     $this->assertEquals(Permission::check("ADMIN"), (bool) $this->render('{$HasPerm(\'ADMIN\')}'), 'Permissions template functions result correct result');
     $this->assertEquals(Permission::check("ADMIN"), (bool) $this->render('{$hasPerm(\'ADMIN\')}'), 'Permissions template functions result correct result');
 }
 /**
  * Event handler called before writing to the database.
  */
 public function onBeforeWrite()
 {
     if ($this->SetPassword) {
         $this->Password = $this->SetPassword;
     }
     // If a member with the same "unique identifier" already exists with a different ID, don't allow merging.
     // Note: This does not a full replacement for safeguards in the controller layer (e.g. in a registration form),
     // but rather a last line of defense against data inconsistencies.
     $identifierField = Member::config()->unique_identifier_field;
     if ($this->{$identifierField}) {
         // Note: Same logic as Member_Validator class
         $filter = array("\"{$identifierField}\"" => $this->{$identifierField});
         if ($this->ID) {
             $filter[] = array('"Member"."ID" <> ?' => $this->ID);
         }
         $existingRecord = DataObject::get_one('SilverStripe\\Security\\Member', $filter);
         if ($existingRecord) {
             throw new ValidationException(ValidationResult::create(false, _t('Member.ValidationIdentifierFailed', 'Can\'t overwrite existing member #{id} with identical identifier ({name} = {value}))', 'Values in brackets show "fieldname = value", usually denoting an existing email address', array('id' => $existingRecord->ID, 'name' => $identifierField, 'value' => $this->{$identifierField}))));
         }
     }
     // We don't send emails out on dev/tests sites to prevent accidentally spamming users.
     // However, if TestMailer is in use this isn't a risk.
     if ((Director::isLive() || Email::mailer() instanceof TestMailer) && $this->isChanged('Password') && $this->record['Password'] && $this->config()->notify_password_change) {
         /** @var Email $e */
         $e = Email::create();
         $e->setSubject(_t('Member.SUBJECTPASSWORDCHANGED', "Your password has been changed", 'Email subject'));
         $e->setTemplate('ChangePasswordEmail');
         $e->populateTemplate($this);
         $e->setTo($this->Email);
         $e->send();
     }
     // The test on $this->ID is used for when records are initially created.
     // Note that this only works with cleartext passwords, as we can't rehash
     // existing passwords.
     if (!$this->ID && $this->Password || $this->isChanged('Password')) {
         //reset salt so that it gets regenerated - this will invalidate any persistant login cookies
         // or other information encrypted with this Member's settings (see self::encryptWithUserSettings)
         $this->Salt = '';
         // Password was changed: encrypt the password according the settings
         $encryption_details = Security::encrypt_password($this->Password, $this->Salt, $this->PasswordEncryption ? $this->PasswordEncryption : Security::config()->password_encryption_algorithm, $this);
         // Overwrite the Password property with the hashed value
         $this->Password = $encryption_details['password'];
         $this->Salt = $encryption_details['salt'];
         $this->PasswordEncryption = $encryption_details['algorithm'];
         // If we haven't manually set a password expiry
         if (!$this->isChanged('PasswordExpiry')) {
             // then set it for us
             if (self::config()->password_expiry_days) {
                 $this->PasswordExpiry = date('Y-m-d', time() + 86400 * self::config()->password_expiry_days);
             } else {
                 $this->PasswordExpiry = null;
             }
         }
     }
     // save locale
     if (!$this->Locale) {
         $this->Locale = i18n::get_locale();
     }
     parent::onBeforeWrite();
 }
 public function __construct($name, $title = null, $value = null)
 {
     if (!$this->locale) {
         $this->locale = i18n::get_locale();
     }
     $this->config = $this->config()->default_config;
     if (!$this->getConfig('dateformat')) {
         $this->setConfig('dateformat', i18n::config()->get('date_format'));
     }
     foreach ($this->config()->default_config as $defaultK => $defaultV) {
         if ($defaultV) {
             if ($defaultK == 'locale') {
                 $this->locale = $defaultV;
             } else {
                 $this->setConfig($defaultK, $defaultV);
             }
         }
     }
     parent::__construct($name, $title, $value);
 }
 /**
  * Gets the current locale this field is set to.
  *
  * @return string
  */
 public function getLocale()
 {
     if ($this->locale) {
         return $this->locale;
     }
     return i18n::get_locale();
 }
 /**
  * Returns the script direction in format compatible with the HTML "dir" attribute.
  *
  * @see http://www.w3.org/International/tutorials/bidi-xhtml/
  * @param String $locale Optional locale incl. region (underscored)
  * @return String "rtl" or "ltr"
  */
 public static function get_script_direction($locale = null)
 {
     require_once 'Zend/Locale/Data.php';
     if (!$locale) {
         $locale = i18n::get_locale();
     }
     try {
         $dir = Zend_Locale_Data::getList($locale, 'layout');
     } catch (Zend_Locale_Exception $e) {
         $dir = Zend_Locale_Data::getList(i18n::get_lang_from_locale($locale), 'layout');
     }
     return $dir && $dir['characters'] == 'right-to-left' ? 'rtl' : 'ltr';
 }
 /**
  * @return string
  */
 public function getLocale()
 {
     return $this->locale ? $this->locale : i18n::get_locale();
 }