public function testFileDelete() { Versioned::set_stage(Versioned::DRAFT); /** @var AssetControlExtensionTest_VersionedObject $object1 */ $object1 = AssetControlExtensionTest_VersionedObject::get()->filter('Title', 'My object')->first(); /** @var AssetControlExtensionTest_Object $object2 */ $object2 = AssetControlExtensionTest_Object::get()->filter('Title', 'Unversioned')->first(); /** @var AssetControlExtensionTest_ArchivedObject $object3 */ $object3 = AssetControlExtensionTest_ArchivedObject::get()->filter('Title', 'Archived')->first(); $this->assertTrue($object1->Download->exists()); $this->assertTrue($object1->Header->exists()); $this->assertTrue($object2->Image->exists()); $this->assertTrue($object3->Header->exists()); $this->assertEquals(AssetStore::VISIBILITY_PUBLIC, $object1->Download->getVisibility()); $this->assertEquals(AssetStore::VISIBILITY_PUBLIC, $object1->Header->getVisibility()); $this->assertEquals(AssetStore::VISIBILITY_PUBLIC, $object2->Image->getVisibility()); $this->assertEquals(AssetStore::VISIBILITY_PUBLIC, $object3->Header->getVisibility()); // Check live stage for versioned objects $object1Live = Versioned::get_one_by_stage('AssetControlExtensionTest_VersionedObject', 'Live', array('"ID"' => $object1->ID)); $object3Live = Versioned::get_one_by_stage('AssetControlExtensionTest_ArchivedObject', 'Live', array('"ID"' => $object3->ID)); $this->assertTrue($object1Live->Download->exists()); $this->assertTrue($object1Live->Header->exists()); $this->assertTrue($object3Live->Header->exists()); $this->assertEquals(AssetStore::VISIBILITY_PUBLIC, $object1Live->Download->getVisibility()); $this->assertEquals(AssetStore::VISIBILITY_PUBLIC, $object1Live->Header->getVisibility()); $this->assertEquals(AssetStore::VISIBILITY_PUBLIC, $object3Live->Header->getVisibility()); // Delete live records; Should cause versioned records to be protected $object1Live->deleteFromStage('Live'); $object3Live->deleteFromStage('Live'); $this->assertTrue($object1->Download->exists()); $this->assertTrue($object1->Header->exists()); $this->assertTrue($object3->Header->exists()); $this->assertTrue($object1Live->Download->exists()); $this->assertTrue($object1Live->Header->exists()); $this->assertTrue($object3Live->Header->exists()); $this->assertEquals(AssetStore::VISIBILITY_PROTECTED, $object1->Download->getVisibility()); $this->assertEquals(AssetStore::VISIBILITY_PROTECTED, $object1->Header->getVisibility()); $this->assertEquals(AssetStore::VISIBILITY_PROTECTED, $object3->Header->getVisibility()); // Delete draft record; Should remove all records // Archived assets only should remain $object1->delete(); $object2->delete(); $object3->delete(); $this->assertFalse($object1->Download->exists()); $this->assertFalse($object1->Header->exists()); $this->assertFalse($object2->Image->exists()); $this->assertTrue($object3->Header->exists()); $this->assertFalse($object1Live->Download->exists()); $this->assertFalse($object1Live->Header->exists()); $this->assertTrue($object3Live->Header->exists()); $this->assertNull($object1->Download->getVisibility()); $this->assertNull($object1->Header->getVisibility()); $this->assertNull($object2->Image->getVisibility()); $this->assertEquals(AssetStore::VISIBILITY_PROTECTED, $object3->Header->getVisibility()); }
/** * Checks all stages other than the current stage, and check the visibility * of assets attached to those records. * * @param AssetManipulationList $manipulation Set of manipulations to add assets to */ protected function addAssetsFromOtherStages(AssetManipulationList $manipulation) { // Skip unversioned or unsaved assets if (!$this->isVersioned() || !$this->owner->isInDB()) { return; } // Unauthenticated member to use for checking visibility $baseClass = $this->owner->baseClass(); $baseTable = $this->owner->baseTable(); $filter = array("\"{$baseTable}\".\"ID\"" => $this->owner->ID); $stages = $this->owner->getVersionedStages(); // {@see Versioned::getVersionedStages} foreach ($stages as $stage) { // Skip current stage; These should be handled explicitly if ($stage === Versioned::get_stage()) { continue; } // Check if record exists in this stage $record = Versioned::get_one_by_stage($baseClass, $stage, $filter); if (!$record) { continue; } // Check visibility of this record, and record all attached assets $state = $this->getRecordState($record); $this->addAssetsFromRecord($manipulation, $record, $state); } }
public function testCanView() { $public1ID = $this->idFromFixture('VersionedTest_PublicStage', 'public1'); $public2ID = $this->idFromFixture('VersionedTest_PublicViaExtension', 'public2'); $privateID = $this->idFromFixture('VersionedTest_DataObject', 'page1'); $singleID = $this->idFromFixture('VersionedTest_SingleStage', 'single'); // Test that all (and only) public pages are viewable in stage mode Session::clear("loggedInAs"); Versioned::set_stage(Versioned::DRAFT); $public1 = Versioned::get_one_by_stage('VersionedTest_PublicStage', 'Stage', array('"ID"' => $public1ID)); $public2 = Versioned::get_one_by_stage('VersionedTest_PublicViaExtension', 'Stage', array('"ID"' => $public2ID)); $private = Versioned::get_one_by_stage('VersionedTest_DataObject', 'Stage', array('"ID"' => $privateID)); // Also test an object that has just a single-stage (eg. is only versioned) $single = Versioned::get_one_by_stage('VersionedTest_SingleStage', 'Stage', array('"ID"' => $singleID)); $this->assertTrue($public1->canView()); $this->assertTrue($public2->canView()); $this->assertFalse($private->canView()); $this->assertFalse($single->canView()); // Adjusting the current stage should not allow objects loaded in stage to be viewable Versioned::set_stage(Versioned::LIVE); $this->assertTrue($public1->canView()); $this->assertTrue($public2->canView()); $this->assertFalse($private->canView()); $this->assertFalse($single->canView()); // Writing the private page to live should be fine though $private->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE); $privateLive = Versioned::get_one_by_stage('VersionedTest_DataObject', 'Live', array('"ID"' => $privateID)); $this->assertTrue($private->canView()); $this->assertTrue($privateLive->canView()); // But if the private version becomes different to the live version, it's once again disallowed Versioned::set_stage(Versioned::DRAFT); $private->Title = 'Secret Title'; $private->write(); $this->assertFalse($private->canView()); $this->assertTrue($privateLive->canView()); // And likewise, viewing a live page (when mode is draft) should be ok Versioned::set_stage(Versioned::DRAFT); $this->assertFalse($private->canView()); $this->assertTrue($privateLive->canView()); // Logging in as admin should allow all permissions $this->logInWithPermission('ADMIN'); Versioned::set_stage(Versioned::DRAFT); $this->assertTrue($public1->canView()); $this->assertTrue($public2->canView()); $this->assertTrue($private->canView()); $this->assertTrue($single->canView()); }
/** * Move a database record from one stage to the other. * * @param int|string $fromStage Place to copy from. Can be either a stage name or a version number. * @param string $toStage Place to copy to. Must be a stage name. * @param bool $createNewVersion Set this to true to create a new version number. * By default, the existing version number will be copied over. */ public function copyVersionToStage($fromStage, $toStage, $createNewVersion = false) { $owner = $this->owner; $owner->invokeWithExtensions('onBeforeVersionedPublish', $fromStage, $toStage, $createNewVersion); $baseClass = $owner->baseClass(); $baseTable = $owner->baseTable(); /** @var Versioned|DataObject $from */ if (is_numeric($fromStage)) { $from = Versioned::get_version($baseClass, $owner->ID, $fromStage); } else { $owner->flushCache(); $from = Versioned::get_one_by_stage($baseClass, $fromStage, array("\"{$baseTable}\".\"ID\" = ?" => $owner->ID)); } if (!$from) { throw new InvalidArgumentException("Can't find {$baseClass}#{$owner->ID} in stage {$fromStage}"); } $from->forceChange(); if ($createNewVersion) { // Clear version to be automatically created on write $from->Version = null; } else { $from->migrateVersion($from->Version); // Mark this version as having been published at some stage $publisherID = isset(Member::currentUser()->ID) ? Member::currentUser()->ID : 0; $extTable = $this->extendWithSuffix($baseTable); DB::prepared_query("UPDATE \"{$extTable}_versions\"\n\t\t\t\tSET \"WasPublished\" = ?, \"PublisherID\" = ?\n\t\t\t\tWHERE \"RecordID\" = ? AND \"Version\" = ?", array(1, $publisherID, $from->ID, $from->Version)); } // Change to new stage, write, and revert state $oldMode = Versioned::get_reading_mode(); Versioned::set_stage($toStage); // Migrate stage prior to write $from->setSourceQueryParam('Versioned.mode', 'stage'); $from->setSourceQueryParam('Versioned.stage', $toStage); $conn = DB::get_conn(); if (method_exists($conn, 'allowPrimaryKeyEditing')) { $conn->allowPrimaryKeyEditing($baseTable, true); $from->write(); $conn->allowPrimaryKeyEditing($baseTable, false); } else { $from->write(); } $from->destroy(); Versioned::set_reading_mode($oldMode); $owner->invokeWithExtensions('onAfterVersionedPublish', $fromStage, $toStage, $createNewVersion); }