function testReadOnlyTransaction()
 {
     if (DB::get_conn()->supportsTransactions() == true && DB::get_conn() instanceof PostgreSQLDatabase) {
         $page = new Page();
         $page->Title = 'Read only success';
         $page->write();
         DB::get_conn()->transactionStart('READ ONLY');
         try {
             $page = new Page();
             $page->Title = 'Read only page failed';
             $page->write();
         } catch (Exception $e) {
             //could not write this record
             //We need to do a rollback or a commit otherwise we'll get error messages
             DB::get_conn()->transactionRollback();
         }
         DB::get_conn()->transactionEnd();
         DataObject::flush_and_destroy_cache();
         $success = DataObject::get('Page', "\"Title\"='Read only success'");
         $fail = DataObject::get('Page', "\"Title\"='Read only page failed'");
         //This page should be in the system
         $this->assertTrue(is_object($success) && $success->exists());
         //This page should NOT exist, we had 'read only' permissions
         $this->assertFalse(is_object($fail) && $fail->exists());
     } else {
         $this->markTestSkipped('Current database is not PostgreSQL');
     }
 }
 public function testCleartextPasswordsAreHashedWithDefaultAlgo()
 {
     $loader = new MemberCsvBulkLoader();
     $results = $loader->load($this->getCurrentRelativePath() . '/MemberCsvBulkLoaderTest_cleartextpws.csv');
     $member = $results->Created()->First();
     $memberID = $member->ID;
     DataObject::flush_and_destroy_cache();
     $member = DataObject::get_by_id('Member', $memberID);
     // TODO Direct getter doesn't work, wtf!
     $this->assertEquals(Security::config()->password_encryption_algorithm, $member->getField('PasswordEncryption'));
     $result = $member->checkPassword('mypassword');
     $this->assertTrue($result->valid());
 }
 function testDeleteWithoutGroupDeletesFromDatabase()
 {
     $member1 = $this->objFromFixture('Member', 'member1');
     $member1ID = $member1->ID;
     $group1 = $this->objFromFixture('Group', 'group1');
     $tf = new MemberTableField($this, "Members");
     $tfItem = new MemberTableField_ItemRequest($tf, $member1->ID);
     $tfItem->delete();
     $group1->flushCache();
     $this->assertNotContains($member1->ID, $group1->Members()->column('ID'), 'Member relation to group is removed');
     DataObject::flush_and_destroy_cache();
     $this->assertFalse(DataObject::get_by_id('Member', $member1ID), 'Member record is removed from database');
 }
 public function testDiscountRoundingError()
 {
     // This extension adds a fractional discount, which could cause
     // the displayed unit price not to match the charged price at
     // large quantities.
     Product::add_extension('ProductTest_FractionalDiscountExtension');
     DataObject::flush_and_destroy_cache();
     $tshirt = Product::get()->byID($this->tshirt->ID);
     Config::inst()->update('Order', 'rounding_precision', 2);
     $this->assertEquals(24.99, $tshirt->sellingPrice());
     Config::inst()->update('Order', 'rounding_precision', 3);
     $this->assertEquals(24.985, $tshirt->sellingPrice());
     Product::remove_extension('ProductTest_FractionalDiscountExtension');
 }
 function testDeleteWithoutGroupDeletesFromDatabase()
 {
     $member1 = $this->objFromFixture('Member', 'member1');
     $member1ID = $member1->ID;
     $group1 = $this->objFromFixture('Group', 'group1');
     $response = $this->get('MemberTableFieldTest_Controller');
     $token = SecurityToken::inst();
     $url = sprintf('MemberTableFieldTest_Controller/FormNoGroup/field/Members/item/%d/delete/?usetestmanifest=1', $member1->ID);
     $url = $token->addToUrl($url);
     $response = $this->get($url);
     $group1->flushCache();
     $this->assertNotContains($member1->ID, $group1->Members()->column('ID'), 'Member relation to group is removed');
     DataObject::flush_and_destroy_cache();
     $this->assertFalse(DataObject::get_by_id('Member', $member1ID), 'Member record is removed from database');
 }
Example #6
0
 function testOrderPaymentStatusUpdated()
 {
     $order = $this->objFromFixture('Order', 'orderOne');
     $payment = $order->Payments()->First();
     $this->assertEquals('Paid', $order->PaymentStatus);
     $this->loginAs('admin');
     $payment->Status = 'Pending';
     $payment->write();
     $this->logOut();
     $order = $this->objFromFixture('Order', 'orderOne');
     $this->assertEquals('Unpaid', $order->PaymentStatus);
     $this->loginAs('admin');
     $payment->Status = 'Success';
     $payment->write();
     $this->logOut();
     DataObject::flush_and_destroy_cache();
     $order = $this->objFromFixture('Order', 'orderOne');
     $this->assertEquals('Paid', $order->PaymentStatus);
 }
 function run($request)
 {
     $ids = array();
     echo "#################################\n";
     echo "# Adding translation groups to existing records" . "\n";
     echo "#################################\n";
     $allSiteTreeIDs = DB::query('SELECT `ID` FROM `SiteTree`')->column();
     if ($allSiteTreeIDs) {
         foreach ($allSiteTreeIDs as $id) {
             $original = DataObject::get_by_id('SiteTree', $id);
             $existingGroupID = $original->getTranslationGroup();
             if (!$existingGroupID) {
                 $original->addTranslationGroup($original->ID);
             }
             $original->destroy();
             unset($original);
         }
     }
     DataObject::flush_and_destroy_cache();
     echo sprintf("Created translation groups for %d records\n", count($allSiteTreeIDs));
     foreach (array('Stage', 'Live') as $stage) {
         echo "\n\n#################################\n";
         echo "# Migrating stage {$stage}" . "\n";
         echo "#################################\n";
         $suffix = $stage == 'Live' ? '_Live' : '';
         // First get all entries in SiteTree_lang
         // This should be all translated pages
         $trans = DB::query(sprintf('SELECT * FROM `_obsolete_SiteTree_lang%s`', $suffix));
         // Iterate over each translated pages
         foreach ($trans as $oldtrans) {
             $newLocale = i18n::get_locale_from_lang($oldtrans['Lang']);
             echo sprintf("Migrating from %s to %s translation of '%s' (#%d)\n", $oldtrans['Lang'], $newLocale, Convert::raw2xml($oldtrans['Title']), $oldtrans['OriginalLangID']);
             // Get the untranslated page
             $original = Versioned::get_one_by_stage($oldtrans['ClassName'], $stage, '`SiteTree`.`ID` = ' . $oldtrans['OriginalLangID']);
             if (!$original) {
                 echo sprintf("Couldn't find original for #%d", $oldtrans['OriginalLangID']);
                 continue;
             }
             // write locale to $original
             $original->Locale = i18n::get_locale_from_lang(Translatable::default_lang());
             $original->writeToStage($stage);
             // Clone the original, and set it up as a translation
             $existingTrans = $original->getTranslation($newLocale, $stage);
             if ($existingTrans) {
                 echo sprintf("Found existing new-style translation for #%d. Already merged? Skipping.\n", $oldtrans['OriginalLangID']);
                 continue;
             }
             // Doesn't work with stage/live split
             //$newtrans = $original->createTranslation($newLocale);
             $newtrans = $original->duplicate(false);
             $newtrans->OriginalID = $original->ID;
             // we have to "guess" a locale based on the language
             $newtrans->Locale = $newLocale;
             if ($stage == 'Live' && array_key_exists($original->ID, $ids)) {
                 $newtrans->ID = $ids[$original->ID];
             }
             // Look at each class in the ancestry, and see if there is a _lang table for it
             foreach (ClassInfo::ancestry($oldtrans['ClassName']) as $classname) {
                 $oldtransitem = false;
                 // If the class is SiteTree, we already have the DB record, else check for the table and get the record
                 if ($classname == 'SiteTree') {
                     $oldtransitem = $oldtrans;
                 } elseif (in_array(strtolower($classname) . '_lang', DB::tableList())) {
                     $oldtransitem = DB::query(sprintf('SELECT * FROM `_obsolete_%s_lang%s` WHERE `OriginalLangID` = %d AND `Lang` = \'%s\'', $classname, $suffix, $original->ID, $oldtrans['Lang']))->first();
                 }
                 // Copy each translated field into the new translation
                 if ($oldtransitem) {
                     foreach ($oldtransitem as $key => $value) {
                         if (!in_array($key, array('ID', 'OriginalLangID'))) {
                             $newtrans->{$key} = $value;
                         }
                     }
                 }
             }
             // Write the new translation to the database
             $sitelang = Translatable::get_current_locale();
             Translatable::set_current_locale($newtrans->Locale);
             $newtrans->writeToStage($stage);
             Translatable::set_current_locale($sitelang);
             $newtrans->addTranslationGroup($original->getTranslationGroup(), true);
             if ($stage == 'Stage') {
                 $ids[$original->ID] = $newtrans->ID;
             }
         }
     }
     echo "\n\n#################################\n";
     echo "Done!\n";
 }
 /**
  * Executes a callback with a locale to temporarily emulate.
  *
  * Warning: Existing DataObjects will contain fields in the actual locale if already lazily loaded, or if
  * used within the callback, will populate itself with the overriding locale. The inverse will occur once the
  * callback is complete. The best practice is to consider this a sandbox, and re-requery all objects required,
  * discarding these afterwards.
  *
  * @param string $locale The locale to set
  * @param callable $callback The callback
  * @return mixed The returned value from the $callback
  */
 public static function with_locale($locale, $callback)
 {
     // Check and set locale
     if (self::$_override_locale) {
         throw new BadMethodCallException("Fluent::with_locale cannot be nested");
     }
     if (!in_array($locale, self::locales())) {
         throw new BadMethodCallException("Invalid locale {$locale}");
     }
     self::$_override_locale = $locale;
     DataObject::flush_and_destroy_cache();
     // Callback
     $result = call_user_func($callback);
     // Reset
     self::$_override_locale = null;
     DataObject::flush_and_destroy_cache();
     return $result;
 }
 public function testDeleteDatabaseOnly()
 {
     $file = $this->objFromFixture('File', 'asdf');
     $fileID = $file->ID;
     $filePath = $file->getFullPath();
     $file->deleteDatabaseOnly();
     DataObject::flush_and_destroy_cache();
     $this->assertFileExists($filePath);
     $this->assertFalse(DataObject::get_by_id('File', $fileID));
 }
 /**
  * Add a product variation to the cart, change the cart so that it is out of date
  * then delete it
  */
 function testRemoveAbandonedCartsWithProductVariationsTask()
 {
     $teeshirtA = $this->objFromFixture('Product', 'teeshirtA');
     $this->logInAs('admin');
     $teeshirtA->doPublish();
     $this->logOut();
     $teeshirtAVariation = $this->objFromFixture('Variation', 'teeshirtExtraLargePurpleCotton');
     $this->assertEquals('Enabled', $teeshirtAVariation->Status);
     $this->assertEquals(5, $teeshirtAVariation->StockLevel()->Level);
     //Add variation to the cart
     $this->get(Director::makeRelative($teeshirtA->Link()));
     $data = array('Quantity' => 1);
     foreach ($teeshirtAVariation->Options() as $option) {
         $data["Options[{$option->AttributeID}]"] = $option->ID;
     }
     $this->submitForm('AddToCartForm_AddToCartForm', null, $data);
     $teeshirtAVariation = $this->objFromFixture('Variation', 'teeshirtExtraLargePurpleCotton');
     $this->assertEquals(4, $teeshirtAVariation->StockLevel()->Level);
     $order = CartControllerExtension::get_current_order();
     $this->logInAs('admin');
     $order->LastActive = '2011-12-22 17:02:49';
     $order->Status = 'Cart';
     $order->write();
     $this->logOut();
     Order::delete_abandoned();
     DataObject::flush_and_destroy_cache();
     $teeshirtAVariation = $this->objFromFixture('Variation', 'teeshirtExtraLargePurpleCotton');
     $this->assertEquals(5, $teeshirtAVariation->StockLevel()->Level);
 }
 function testPromoOnCategory()
 {
     /** @var Product $p1 */
     $p1 = $this->objFromFixture('Product', 'p1');
     /** @var Product $p3 */
     $p3 = $this->objFromFixture('Product', 'p3');
     /** @var ProductCategory $c1 */
     $c1 = $this->objFromFixture('ProductCategory', 'c1');
     /** @var ProductVaration $p4v1 */
     $p4v1 = $this->objFromFixture('ProductVariation', 'p4v1');
     // Products are initially right
     $this->assertEquals(27.5, $p1->sellingPrice(), 'Products are initially right');
     $this->assertEquals(25, $p3->sellingPrice(), 'Products are initially right');
     $this->assertEquals(20, $p4v1->sellingPrice(), 'Products are initially right');
     // When a promo is added to the parent category, it changes the price on products
     $c1->PromoActive = true;
     $c1->PromoType = 'Amount';
     $c1->PromoAmount = 10;
     $c1->write();
     DataObject::flush_and_destroy_cache();
     $p1 = Product::get()->byID($p1->ID);
     $this->assertEquals(17.5, $p1->sellingPrice(), 'When a promo is added to the parent category, it changes the price on products');
     // Check that it also works if the category is not the main parent category
     $this->assertEquals(15, $p3->sellingPrice(), 'Check that it also works if the category is not the main parent category');
     // When a promo is added to the parent category, it changes the price on variations
     $this->assertEquals(10, $p4v1->sellingPrice(), 'When a promo is added to the parent category, it changes the price on variations');
 }
Example #12
0
 /**
  * @see FileTest->testDeleteDatabaseOnly()
  */
 public function testDeleteDatabaseOnly()
 {
     $subfolder = $this->objFromFixture('Folder', 'subfolder');
     $subfolderID = $subfolder->ID;
     $subfolderFile = $this->objFromFixture('File', 'subfolderfile');
     $subfolderFileID = $subfolderFile->ID;
     $subfolder->deleteDatabaseOnly();
     DataObject::flush_and_destroy_cache();
     $this->assertFileExists($subfolder->getFullPath());
     $this->assertFalse(DataObject::get_by_id('Folder', $subfolderID));
     $this->assertFileExists($subfolderFile->getFullPath());
     $this->assertFalse(DataObject::get_by_id('File', $subfolderFileID));
 }
Example #13
0
 /**
  * Carts abandoned longer than set lifetime are deleted
  */
 public function testDeleteAbandonedCarts()
 {
     $productA = $this->objFromFixture('Product', 'productA');
     $shopConfig = $this->objFromFixture('ShopConfig', 'config');
     $this->assertEquals(1, $shopConfig->CartTimeout);
     $this->assertEquals('hour', $shopConfig->CartTimeoutUnit);
     $this->loginAs('admin');
     $productA->doPublish();
     $this->logOut();
     $productALink = $productA->Link();
     $this->get(Director::makeRelative($productALink));
     $this->submitForm('ProductForm_ProductForm', null, array('Quantity' => 1));
     $order = Cart::get_current_order();
     $this->assertTrue($order->exists());
     Order::delete_abandoned();
     DataObject::flush_and_destroy_cache();
     $order = Cart::get_current_order();
     $this->assertTrue($order->exists());
     //Log in as admin, change the shop config and the cart last active and try to delete it
     $this->loginAs('admin');
     $shopConfig->CartTimeout = 15;
     $shopConfig->CartTimeoutUnit = 'minute';
     $shopConfig->write();
     $date = new DateTime();
     $date->sub(new DateInterval('PT20M'));
     $order->LastActive = $date->format('Y-m-d H:i:s');
     $order->write();
     $this->logOut();
     Order::delete_abandoned();
     DataObject::flush_and_destroy_cache();
     $order = Cart::get_current_order();
     $this->assertTrue(!$order->exists());
 }
 public function testWriteWithoutVersion()
 {
     $original = new SiteTree();
     $original->write();
     // Create a second version (different behaviour),
     // as SiteTree->onAfterWrite() checks for Version == 1
     $original->Title = 'prepare';
     $original->write();
     $originalVersion = $original->Version;
     $virtual = new VirtualPage();
     $virtual->CopyContentFromID = $original->ID;
     $virtual->write();
     // Create a second version, see above.
     $virtual->Title = 'prepare';
     $virtual->write();
     $virtualVersion = $virtual->Version;
     $virtual->Title = 'changed 1';
     $virtual->writeWithoutVersion();
     $this->assertEquals($virtual->Version, $virtualVersion, 'writeWithoutVersion() on VirtualPage doesnt increment version');
     $original->Title = 'changed 2';
     $original->writeWithoutVersion();
     DataObject::flush_and_destroy_cache();
     $virtual = DataObject::get_by_id('VirtualPage', $virtual->ID, false);
     $this->assertEquals($virtual->Version, $virtualVersion, 'writeWithoutVersion() on original page doesnt increment version on related VirtualPage');
     $original->Title = 'changed 3';
     $original->write();
     DataObject::flush_and_destroy_cache();
     $virtual = DataObject::get_by_id('VirtualPage', $virtual->ID, false);
     $this->assertGreaterThan($virtualVersion, $virtual->Version, 'write() on original page does increment version on related VirtualPage');
 }
 public function testLazyLoadedFieldsWriteNullFields()
 {
     $subteam1 = $this->objFromFixture('DataObjectTest_SubTeam', 'subteam1');
     $subteam1ID = $subteam1->ID;
     $teams = DataObject::get('DataObjectTest_Team');
     // query parent class
     $subteam1Lazy = $teams->find('ID', $subteam1->ID);
     // Updated lazyloaded field
     $subteam1Lazy->SubclassDatabaseField = null;
     $subteam1Lazy->write();
     // Reload from database
     DataObject::flush_and_destroy_cache();
     $subteam1Reloaded = DataObject::get_by_id('DataObjectTest_SubTeam', $subteam1ID);
     $this->assertEquals(null, $subteam1Reloaded->getField('SubclassDatabaseField'));
 }
 public function testUploadsDisabled()
 {
     Config::inst()->update('CloudAssets', 'uploads_disabled', true);
     // this is needed to undo the upload done during setup
     $f1 = $this->objFromFixture('File', 'file1-folder1');
     if ($f1->CloudStatus != 'Local') {
         $f1->CloudStatus = 'Local';
         $f1->downloadFromCloud();
         $f1->write();
     }
     CloudAssets::inst()->updateAllFiles();
     DataObject::flush_and_destroy_cache();
     $f1 = File::get()->byID($f1->ID);
     $this->assertEquals('Local', $f1->CloudStatus);
     $this->assertEquals(0, count($f1->getCloudBucket()->uploads));
 }
 /**
  * Exports the website with the given base url. Returns the path where the
  * exported version of the website is located.
  *
  * @param string website base url
  * @param string folder to export the site into
  * @param bool symlink assets
  * @param bool suppress output progress
  *
  * @return string path to export
  */
 public function doExport($base, $folder, $symlink = true, $quiet = true)
 {
     ini_set('max_execution_time', 0);
     Config::inst()->update('Director', 'alternate_base_url', $base);
     if (is_dir($folder)) {
         Filesystem::removeFolder($folder);
     }
     Filesystem::makeFolder($folder);
     // symlink or copy /assets
     $f1 = ASSETS_PATH;
     $f2 = Director::baseFolder() . '/' . project();
     if ($symlink) {
         `cd {$folder}; ln -s {$f1}; ln -s {$f2}`;
     } else {
         `cp -R {$f1} {$folder}; cp -R {$f2} {$folder}`;
     }
     // iterate through items we need to export
     $urls = $this->getExportUrls();
     if ($urls) {
         $total = count($urls);
         $i = 1;
         foreach ($urls as $url) {
             $subfolder = "{$folder}/" . trim($url, '/');
             $contentfile = "{$folder}/" . trim($url, '/') . '/index.html';
             // Make the folder
             if (!file_exists($subfolder)) {
                 Filesystem::makeFolder($subfolder);
             }
             // Run the page
             Requirements::clear();
             DataObject::flush_and_destroy_cache();
             $response = Director::test($url);
             // Write to file
             if ($fh = fopen($contentfile, 'w')) {
                 if (!$quiet) {
                     printf("-- (%s/%s) Outputting page (%s)%s", $i, $total, $url, PHP_EOL);
                 }
                 fwrite($fh, $response->getBody());
                 fclose($fh);
             }
             $i++;
         }
     }
     return $folder;
 }