From b6abd40783b9a207f410045fd85042b52564b680 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Mon, 11 Aug 2008 03:03:52 +0000 Subject: [PATCH] (merged from branches/roa. use "svn log -c -g " for detailed commit message) git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@60330 467b73ca-7a2a-4603-9d3b-597d59a354a9 --- _config.php | 1 + api/SOAPModelAccess.php | 247 +++++++++++++++++++++++++++ api/SapphireSoapServer.php | 3 +- api/SapphireSoapServer_wsdl.ss | 46 +++++ core/control/Director.php | 12 +- core/control/HTTPResponse.php | 13 +- core/control/RequestHandlingData.php | 1 + core/model/ComponentSet.php | 54 +++--- core/model/DataObject.php | 10 +- core/model/SQLQuery.php | 2 +- forms/CheckboxSetField.php | 20 ++- tests/DataObjectTest.php | 88 ++++++++++ tests/DataObjectTest.yml | 12 ++ tests/GroupTest.php | 96 +++++++++++ tests/GroupTest.yml | 21 +++ tests/SoapModelAccessTest.php | 137 +++++++++++++++ tests/SoapModelAccessTest.yml | 38 +++++ 17 files changed, 761 insertions(+), 40 deletions(-) create mode 100755 api/SOAPModelAccess.php create mode 100755 api/SapphireSoapServer_wsdl.ss create mode 100644 tests/GroupTest.php create mode 100644 tests/GroupTest.yml create mode 100644 tests/SoapModelAccessTest.php create mode 100644 tests/SoapModelAccessTest.yml diff --git a/_config.php b/_config.php index 931351e24..8bdb5d720 100644 --- a/_config.php +++ b/_config.php @@ -28,6 +28,7 @@ Director::addRules(10, array( '' => 'RootURLController', 'sitemap.xml' => 'GoogleSitemap', 'api/v1' => 'RestfulServer', + 'soap/v1' => 'SOAPModelAccess', 'dev' => 'DevelopmentAdmin' )); diff --git a/api/SOAPModelAccess.php b/api/SOAPModelAccess.php new file mode 100755 index 000000000..959cfc931 --- /dev/null +++ b/api/SOAPModelAccess.php @@ -0,0 +1,247 @@ + + * $c = new SoapClient('http://mysite.com/soap/v1/wsdl'); + * echo $c->getXML("MyClassName", 99); // gets record #99 as xml + * + * + * Usage - Updating a record: + * + * $c = new SoapClient('http://mysite.com/soap/v1/wsdl'); + * $data = array('MyProperty' => 'MyUpdatedValue'); + * echo $c->putXML("MyClassName", 99, null, $data); + * + * + * Usage - Creating a record: + * + * $c = new SoapClient('http://mysite.com/soap/v1/wsdl'); + * $data = array('MyProperty' => 'MyValue'); + * echo $c->putXML("MyClassName", null, null, $data); + * + * + * Usage - Creating a record: + * + * $c = new SoapClient('http://mysite.com/soap/v1/wsdl'); + * echo $c->deleteXML("MyClassName"); + * + * + * @todo Test relation methods + * + * @package sapphire + * @subpackage api + */ +class SOAPModelAccess extends SapphireSoapServer { + + public static $methods = array( + 'getXML' => array( + 'class' => 'string', + 'id' => 'int', + 'relation' => 'string', + '_returns' => 'string', + ), + 'getJSON' => array( + 'class' => 'string', + 'id' => 'int', + 'relation' => 'string', + '_returns' => 'string', + ), + 'putXML' => array( + 'class' => 'string', + 'id' => 'int', + 'relation' => 'string', + 'data' => 'string', + 'username' => 'string', + 'password' => 'string', + '_returns' => 'boolean', + ), + 'putJSON' => array( + 'class' => 'string', + 'id' => 'int', + 'relation' => 'string', + '_returns' => 'boolean', + ), + ); + + function Link() { + return "soap/v1/"; + } + + /** + * Used to emulate RESTful GET requests with XML data. + * + * @param string $class + * @param Number $id + * @param string $relation Relation name + * @return string + */ + function getXML($class, $id, $relation = false, $username = null, $password = null) { + $this->authenticate($username, $password); + + $response = Director::test( + $this->buildRestfulURL($class, $id, $relation, 'xml'), + null, + null, + 'GET' + ); + + return ($response->isError()) ? $this->getErrorMessage($response) : $response->getBody(); + } + + /** + * Used to emulate RESTful GET requests with JSON data. + * + * @param string $class + * @param Number $id + * @param string $relation Relation name + * @param string $username + * @param string $password + * @return string + */ + function getJSON($class, $id, $relation = false, $username = null, $password = null) { + $this->authenticate($username, $password); + + $response = Director::test( + $this->buildRestfulURL($class, $id, $relation, 'json'), + null, + null, + 'GET' + ); + + return ($response->isError()) ? $this->getErrorMessage($response) : $response->getBody(); + } + + /** + * Used to emulate RESTful POST and PUT requests with XML data. + * + * @param string $class + * @param Number $id + * @param string $relation Relation name + * @param array $data + * @param string $username + * @param string $password + * @return string + */ + function putXML($class, $id = false, $relation = false, $data, $username = null, $password = null) { + $this->authenticate($username, $password); + + $response = Director::test( + $this->buildRestfulURL($class, $id, $relation, 'xml'), + $data, + null, + ($id) ? 'PUT' : 'POST' + ); + + return ($response->isError()) ? $this->getErrorMessage($response) : $response->getBody(); + } + + /** + * Used to emulate RESTful POST and PUT requests with JSON data. + * + * @param string $class + * @param Number $id + * @param string $relation Relation name + * @param array $data + * @param string $username + * @param string $password + * @return string + */ + function putJSON($class = false, $id = false, $relation = false, $data, $username = null, $password = null) { + $this->authenticate($username, $password); + + $response = Director::test( + $this->buildRestfulURL($class, $id, $relation, 'json'), + $data, + null, + ($id) ? 'PUT' : 'POST' + ); + + return ($response->isError()) ? $this->getErrorMessage($response) : $response->getBody(); + } + + /** + * Used to emulate RESTful DELETE requests. + * + * @param string $class + * @param Number $id + * @param string $relation Relation name + * @param string $username + * @param string $password + * @return string + */ + function deleteXML($class, $id, $relation = false, $username = null, $password = null) { + $this->authenticate($username, $password); + + $response = Director::test( + $this->buildRestfulURL($class, $id, $relation, 'xml'), + null, + null, + 'DELETE' + ); + + return ($response->isError()) ? $this->getErrorMessage($response) : $response->getBody(); + } + + /** + * Used to emulate RESTful DELETE requests. + * + * @param string $class + * @param Number $id + * @param string $relation Relation name + * @param string $username + * @param string $password + * @return string + */ + function deleteJSON($class, $id, $relation = false, $username = null, $password = null) { + $this->authenticate($username, $password); + + $response = Director::test( + $this->buildRestfulURL($class, $id, $relation, 'json'), + null, + null, + 'DELETE' + ); + + return ($response->isError()) ? $this->getErrorMessage($response) : $response->getBody(); + } + + /** + * Faking an HTTP Basicauth login in the PHP environment + * that RestfulServer can pick up. + * + * @param string $username Username + * @param string $password Plaintext password + */ + protected function authenticate($username, $password) { + $_SERVER['PHP_AUTH_USER'] = $username; + $_SERVER['PHP_AUTH_PW'] = $password; + } + + /** + * @param string $class + * @param Number $id + * @param string $relation + * @param string $extension + * @return string + */ + protected function buildRestfulURL($class, $id, $relation, $extension) { + $url = "api/v1/{$class}"; + if($id) $url .= "/{$id}"; + if($relation) $url .= "/{$relation}"; + if($extension) $url .= "/.{$extension}"; + return $url; + } + + /** + * @param HTTPResponse $response + * @return string XML string containing the HTTP error message + */ + protected function getErrorMessage($response) { + return "getStatusCode() . "\">" . $response->getStatusDescription() . ""; + } +} + +?> \ No newline at end of file diff --git a/api/SapphireSoapServer.php b/api/SapphireSoapServer.php index 021d2792d..9efb216a6 100755 --- a/api/SapphireSoapServer.php +++ b/api/SapphireSoapServer.php @@ -9,6 +9,7 @@ class SapphireSoapServer extends Controller { static $methods = array(); static $xsd_types = array( 'int' => 'xsd:int', + 'boolean' => 'xsd:boolean', 'string' => 'xsd:string', 'binary' => 'xsd:base64Binary', ); @@ -20,7 +21,7 @@ class SapphireSoapServer extends Controller { } function getWSDLURL() { - return Director::absoluteBaseURLWithAuth() . $this->class . "/wsdl"; + return Director::absoluteBaseURLWithAuth() . $this->Link() . "wsdl"; } function Methods() { diff --git a/api/SapphireSoapServer_wsdl.ss b/api/SapphireSoapServer_wsdl.ss new file mode 100755 index 000000000..a0c46b88e --- /dev/null +++ b/api/SapphireSoapServer_wsdl.ss @@ -0,0 +1,46 @@ + + + <% control Methods %> + + <% control Arguments %> + + <% end_control %> + + + + + <% end_control %> + + + <% control Methods %> + + + + + <% end_control %> + + + + <% control Methods %> + + + + + + + + + + <% end_control %> + + + + + + + + diff --git a/core/control/Director.php b/core/control/Director.php index 7b4ce36fc..9eb9192b4 100644 --- a/core/control/Director.php +++ b/core/control/Director.php @@ -164,6 +164,8 @@ class Director { /** * Handle an HTTP request, defined with a HTTPRequest object. + * + * @return HTTPResponse|string */ protected static function handleRequest(HTTPRequest $request, Session $session) { krsort(Director::$rules); @@ -452,10 +454,12 @@ class Director { * Returns the Absolute URL of the site root, embedding the current basic-auth credentials into the URL. */ static function absoluteBaseURLWithAuth() { - if($_SERVER['PHP_AUTH_USER']) - $login = "$_SERVER[PHP_AUTH_USER]:$_SERVER[PHP_AUTH_PW]@"; - - if($_SERVER['SSL']) $s = "s"; + $s = ""; + $login = ""; + + if(isset($_SERVER['PHP_AUTH_USER'])) $login = "$_SERVER[PHP_AUTH_USER]:$_SERVER[PHP_AUTH_PW]@"; + if(isset($_SERVER['SSL']) && $_SERVER['SSL'] != 'Off') $s = "s"; + return "http$s://" . $login . $_SERVER['HTTP_HOST'] . Director::baseURL(); } diff --git a/core/control/HTTPResponse.php b/core/control/HTTPResponse.php index ead9067c7..958446657 100644 --- a/core/control/HTTPResponse.php +++ b/core/control/HTTPResponse.php @@ -79,6 +79,17 @@ class HTTPResponse extends Object { function getStatusCode() { return $this->statusCode; } + + /** + * @return string Description for a HTTP status code + */ + function getStatusDescription() { + if(isset(self::$status_codes[$this->statusCode])) { + return self::$status_codes[$this->statusCode]; + } else { + return false; + } + } /** * Returns true if this HTTP response is in error @@ -148,7 +159,7 @@ class HTTPResponse extends Object { function output() { if(in_array($this->statusCode, self::$redirect_codes) && headers_sent($file, $line)) { $url = $this->headers['Location']; - echo + echo "

Redirecting to $url... (output started on $file, line $line)

"; diff --git a/core/control/RequestHandlingData.php b/core/control/RequestHandlingData.php index 6115b6246..efbced146 100644 --- a/core/control/RequestHandlingData.php +++ b/core/control/RequestHandlingData.php @@ -68,6 +68,7 @@ class RequestHandlingData extends ViewableData { * @param $params The parameters taken from the parsed URL of the parent url handler * @param $request The {@link HTTPRequest} object that is reponsible for distributing URL parsing * @uses HTTPRequest + * @return HTTPResponse|RequestHandlingData|string|array */ function handleRequest($request) { $this->request = $request; diff --git a/core/model/ComponentSet.php b/core/model/ComponentSet.php index 4f44c515d..56bb4749a 100755 --- a/core/model/ComponentSet.php +++ b/core/model/ComponentSet.php @@ -157,36 +157,31 @@ class ComponentSet extends DataObjectSet { function setByIDList($idList) { $has = array(); // Index current data - if($this->items) { - foreach( $this->items as $item ) - $has[$item->ID] = true; + if($this->items) foreach($this->items as $item) { + $has[$item->ID] = true; } // Keep track of items to delete - if( isset( $has ) ) - $itemsToDelete = $has; + $itemsToDelete = $has; - if($idList){ - foreach($idList as $id) { - if( isset( $itemsToDelete ) ) - $itemsToDelete[$id] = false; - if( ! isset( $has ) || ( $id && ! isset( $has[$id] ) ) ) - $this->add($id); - } + // add items in the list + // $id is the database ID of the record + if($idList) foreach($idList as $id) { + $itemsToDelete[$id] = false; + if($id && !isset($has[$id])) $this->add($id); } - // Delete any unmentionedItems - if( isset( $itemsToDelete ) ) { - foreach($itemsToDelete as $id => $actuallyDelete) { - if($actuallyDelete) $removeList[] = $id; - } - - if( isset( $removeList ) ) - $this->removeMany($removeList); + + // delete items not in the list + $removeList = array(); + foreach($itemsToDelete as $id => $actuallyDelete) { + if($actuallyDelete) $removeList[] = $id; } + $this->removeMany($removeList); } /** * Remove an item from this set. + * * @param DataObject|string|int $item Item to remove, either as a DataObject or as the ID. */ function remove($item) { @@ -226,20 +221,19 @@ class ComponentSet extends DataObjectSet { /** * Remove many items from this set. - * @param array $itemList The items to remove. + Ü + * @param array $itemList The items to remove, as a numerical array with IDs or as a DataObjectSet */ function removeMany($itemList) { + if(!count($itemList)) return false; + if($this->type == '1-to-many') { - if(isset($itemList)) { - foreach($itemList as $item) $this->remove($item); - } + foreach($itemList as $item) $this->remove($item); } else { - if(isset($itemList)) { - $itemCSV = implode(", ", $itemList); - $parentField = $this->ownerClass . 'ID'; - $childField = ($this->childClass == $this->ownerClass) ? "ChildID" : ($this->childClass . 'ID'); - DB::query("DELETE FROM `$this->tableName` WHERE $parentField = {$this->ownerObj->ID} AND $childField IN ($itemCSV)"); - } + $itemCSV = implode(", ", $itemList); + $parentField = $this->ownerClass . 'ID'; + $childField = ($this->childClass == $this->ownerClass) ? "ChildID" : ($this->childClass . 'ID'); + DB::query("DELETE FROM `$this->tableName` WHERE $parentField = {$this->ownerObj->ID} AND $childField IN ($itemCSV)"); } } diff --git a/core/model/DataObject.php b/core/model/DataObject.php index 59cecabd9..99aa45dd4 100644 --- a/core/model/DataObject.php +++ b/core/model/DataObject.php @@ -1803,7 +1803,7 @@ class DataObject extends ViewableData implements DataObjectInterface { $object = $component->dbObject($fieldName); - if (!($object instanceof DBField)) { + if (!($object instanceof DBField) && !($object instanceof ComponentSet)) { user_error("Unable to traverse to related object field [$fieldPath] on [$this->class]", E_USER_ERROR); } return $object; @@ -2057,7 +2057,7 @@ class DataObject extends ViewableData implements DataObjectInterface { } /** - * Flush the cached results for get_one() + * Flush the cached results for all relations (has_one, has_many, many_many) */ public function flushCache() { if($this->class == 'DataObject') { @@ -2073,6 +2073,8 @@ class DataObject extends ViewableData implements DataObjectInterface { // if(DataObject::$cache_get_one[$class]) foreach(DataObject::$cache_get_one[$class] as $obj) if($obj) $obj->destroy(); DataObject::$cache_get_one[$class] = null; } + + $this->componentCache = array(); } /** @@ -2450,6 +2452,10 @@ class DataObject extends ViewableData implements DataObjectInterface { $filters = array(); foreach($this->searchableFields() as $name => $spec) { $filterClass = $spec['filter']; + // if $filterClass is not set a name of any subclass of SearchFilter than assing 'PartiailMatchFilter' to it + if (!is_subclass_of($filterClass, 'SearchFilter')) { + $filterClass = 'PartialMatchFilter'; + } $filters[$name] = new $filterClass($name); } return $filters; diff --git a/core/model/SQLQuery.php b/core/model/SQLQuery.php index bfd3120f4..606683454 100755 --- a/core/model/SQLQuery.php +++ b/core/model/SQLQuery.php @@ -141,7 +141,7 @@ class SQLQuery extends Object { * @return SQLQuery This instance */ public function leftJoin($table, $onPredicate) { - $this->from[$table] = "LEFT JOIN $table ON $onPredicate"; + $this->from[$table] = "LEFT JOIN `$table` ON $onPredicate"; return $this; } diff --git a/forms/CheckboxSetField.php b/forms/CheckboxSetField.php index 67e93c0c4..b92815c04 100755 --- a/forms/CheckboxSetField.php +++ b/forms/CheckboxSetField.php @@ -119,7 +119,11 @@ class CheckboxSetField extends OptionsetField { $fieldname = $this->name ; if($fieldname && $record && ($record->has_many($fieldname) || $record->many_many($fieldname))) { - $record->$fieldname()->setByIDList($this->value); + $idList = array(); + foreach($this->value as $id => $bool) { + if($bool) $idList[] = $id; + } + $record->$fieldname()->setByIDList($idList); } elseif($fieldname && $record) { if($this->value) { $this->value = str_replace(",", "{comma}", $this->value); @@ -130,6 +134,20 @@ class CheckboxSetField extends OptionsetField { } } + /** + * Return the CheckboxSetField value, as an array of the selected item keys + */ + function dataValue() { + if($this->value){ + // Filter items to those who aren't 0 + $filtered = array(); + foreach($this->value as $item) if($item) $filtered[] = str_replace(",", "{comma}", $item); + return implode(",", $filtered); + } else { + return ''; + } + } + /** * Makes a pretty readonly field */ diff --git a/tests/DataObjectTest.php b/tests/DataObjectTest.php index 471beb23b..c642e0458 100644 --- a/tests/DataObjectTest.php +++ b/tests/DataObjectTest.php @@ -154,6 +154,94 @@ class DataObjectTest extends SapphireTest { $this->assertTrue($comment->ParentID == $page->ID); } } + + /** + * @todo Test removeMany() and addMany() on $many_many relationships + */ + function testManyManyRelationships() { + $player1 = $this->fixture->objFromFixture('DataObjectTest_Player', 'player1'); + $player2 = $this->fixture->objFromFixture('DataObjectTest_Player', 'player2'); + $team1 = $this->fixture->objFromFixture('DataObjectTest_Team', 'team1'); + $team2 = $this->fixture->objFromFixture('DataObjectTest_Team', 'team2'); + + // Test adding single DataObject by reference + $player1->Teams()->add($team1); + $player1->flushCache(); + $compareTeams = new ComponentSet($team1); + $this->assertEquals( + $player1->Teams()->column('ID'), + $compareTeams->column('ID'), + "Adding single record as DataObject to many_many" + ); + + // test removing single DataObject by reference + $player1->Teams()->remove($team1); + $player1->flushCache(); + $compareTeams = new ComponentSet(); + $this->assertEquals( + $player1->Teams()->column('ID'), + $compareTeams->column('ID'), + "Removing single record as DataObject from many_many" + ); + + // test adding single DataObject by ID + $player1->Teams()->add($team1->ID); + $player1->flushCache(); + $compareTeams = new ComponentSet($team1); + $this->assertEquals( + $player1->Teams()->column('ID'), + $compareTeams->column('ID'), + "Adding single record as ID to many_many" + ); + + // test removing single DataObject by ID + $player1->Teams()->remove($team1->ID); + $player1->flushCache(); + $compareTeams = new ComponentSet(); + $this->assertEquals( + $player1->Teams()->column('ID'), + $compareTeams->column('ID'), + "Removing single record as ID from many_many" + ); + } + + /** + * @todo Extend type change tests (e.g. '0'==NULL) + */ + function testChangedFields() { + $page = $this->fixture->objFromFixture('Page', 'home'); + $page->Title = 'Home-Changed'; + $page->ShowInMenus = true; + + $this->assertEquals( + $page->getChangedFields(false, 1), + array( + 'Title' => array( + 'before' => 'Home', + 'after' => 'Home-Changed', + 'level' => 2 + ), + 'ShowInMenus' => array( + 'before' => 1, + 'after' => true, + 'level' => 1 + ) + ), + 'Changed fields are correctly detected with strict type changes (level=1)' + ); + + $this->assertEquals( + $page->getChangedFields(false, 2), + array( + 'Title' => array( + 'before'=>'Home', + 'after'=>'Home-Changed', + 'level' => 2 + ) + ), + 'Changed fields are correctly detected while ignoring type changes (level=2)' + ); + } } ?> diff --git a/tests/DataObjectTest.yml b/tests/DataObjectTest.yml index 9d07d46cc..f3d1ecc58 100644 --- a/tests/DataObjectTest.yml +++ b/tests/DataObjectTest.yml @@ -23,3 +23,15 @@ Page: page2: Title: Second Page +DataObjectTest_Team: + team1: + Title: Team 1 + team2: + Title: Team 2 + +DataObjectTest_Player: + player1: + FirstName: Player 1 + player2: + FirstName: Player 2 + Teams: =>DataObjectTest_Team.team1,=>DataObjectTest_Team.team2 \ No newline at end of file diff --git a/tests/GroupTest.php b/tests/GroupTest.php new file mode 100644 index 000000000..7b3848e4d --- /dev/null +++ b/tests/GroupTest.php @@ -0,0 +1,96 @@ +fixture->objFromFixture('Group', 'admingroup'); + $parentGroup = $this->fixture->objFromFixture('Group', 'parentgroup'); + $childGroup = $this->fixture->objFromFixture('Group', 'childgroup'); + + // Test single group relation through checkboxsetfield + $form = new GroupTest_MemberForm($this, 'Form'); + $member = $this->fixture->objFromFixture('GroupTest_Member', 'admin'); + $form->loadDataFrom($member); + $checkboxSetField = $form->Fields()->fieldByName('Groups'); + $checkboxSetField->setValue(array( + $adminGroup->ID => $adminGroup->ID, // keep existing relation + $parentGroup->ID => $parentGroup->ID, // add new relation + )); + $form->saveInto($member); + $updatedGroups = $member->Groups(); + $controlGroups = new Member_GroupSet( + $adminGroup, + $parentGroup + ); + $this->assertEquals( + $updatedGroups->Map('ID','ID'), + $controlGroups->Map('ID','ID'), + "Adding a toplevel group works" + ); + + // Test unsetting relationship + $form->loadDataFrom($member); + $checkboxSetField = $form->Fields()->fieldByName('Groups'); + $checkboxSetField->setValue(array( + $adminGroup->ID => $adminGroup->ID, // keep existing relation + //$parentGroup->ID => $parentGroup->ID, // remove previously set relation + )); + $form->saveInto($member); + $member->flushCache(); + $updatedGroups = $member->Groups(); + $controlGroups = new Member_GroupSet( + $adminGroup + ); + $this->assertEquals( + $updatedGroups->Map('ID','ID'), + $controlGroups->Map('ID','ID'), + "Removing a previously added toplevel group works" + ); + + // Test adding child group + + } + +} + +class GroupTest_Member extends Member implements TestOnly { + + function getCMSFields() { + $groups = DataObject::get('Group'); + $groupsMap = ($groups) ? $groups->toDropDownMap() : false; + $fields = new FieldSet( + new HiddenField('ID', 'ID'), + new CheckboxSetField( + 'Groups', + 'Groups', + $groupsMap + ) + ); + + return $fields; + } + +} + +class GroupTest_MemberForm extends Form { + + function __construct($controller, $name) { + $fields = singleton('GroupTest_Member')->getCMSFields(); + $actions = new FieldSet( + new FormAction('doSave','save') + ); + + parent::__construct($controller, $name, $fields, $actions); + } + + function doSave($data, $form) { + // done in testing methods + } + +} +?> \ No newline at end of file diff --git a/tests/GroupTest.yml b/tests/GroupTest.yml new file mode 100644 index 000000000..b6542e1cf --- /dev/null +++ b/tests/GroupTest.yml @@ -0,0 +1,21 @@ +Group: + admingroup: + Code: admingroup + parentgroup: + Code: parentgroup + childgroup: + Code: childgroup + Parent: =>Group.parentgroup +GroupTest_Member: + admin: + FirstName: Admin + Groups: =>Group.admingroup + parentgroupuser: + FirstName: Parent Group User + Groups: =>Group.parentgroup + childgroupuser: + FirstName: Child Group User + Groups: =>Group.childgroup + allgroupuser: + FirstName: All Group User + Groups: =>Group.admingroup,=>Group.parentgroup,=>Group.childgroup diff --git a/tests/SoapModelAccessTest.php b/tests/SoapModelAccessTest.php new file mode 100644 index 000000000..14c88fbf4 --- /dev/null +++ b/tests/SoapModelAccessTest.php @@ -0,0 +1,137 @@ +getXML( + "SoapModelAccessTest_Comment", + 1, + null, + null, + 'editor@test.com', + 'editor' + ); + var_dump($soapResponse); + die(); + $responseArr = Convert::xml2array($soapResponse); + $this->assertEquals($responseArr['ID'], 1); + $this->assertEquals($responseArr['Name'], 'Joe'); + } + + public function testAuthenticatedPUT() { + // test wrong details + $c = new SoapClient(Director::absoluteBaseURL() . 'soap/v1/wsdl'); + $soapResponse = $c->getXML( + "SoapModelAccessTest_Comment", + 1, + null, + array( + 'Name' => 'Updated Name' + ), + 'editor@test.com', + 'wrongpassword' + ); + $this->assertEquals( + $soapResponse, + 'Forbidden' + ); + + // test correct details + $c = new SoapClient(Director::absoluteBaseURL() . 'soap/v1/wsdl'); + $soapResponse = $c->getXML( + "SoapModelAccessTest_Comment", + 1, + null, + array( + 'Name' => 'Updated Name' + ), + 'editor@test.com', + 'editor' + ); + $responseArr = Convert::xml2array($soapResponse); + $this->assertEquals($responseArr['ID'], 1); + $this->assertEquals($responseArr['Name'], 'Updated Name'); + } + + public function testAuthenticatedPOST() { + $c = new SoapClient(Director::absoluteBaseURL() . 'soap/v1/wsdl'); + $soapResponse = $c->getXML( + "SoapModelAccessTest_Comment", + null, + null, + array( + 'Name' => 'Created Name' + ), + 'editor@test.com', + 'editor' + ); + $responseArr = Convert::xml2array($soapResponse); + $this->assertEquals($responseArr['Name'], 'Created Name'); + } + */ + +} + +/** + * Everybody can view comments, logged in members in the "users" group can create comments, + * but only "editors" can edit or delete them. + * + */ +class SoapModelAccessTest_Comment extends DataObject implements PermissionProvider,TestOnly { + + static $api_access = true; + + static $db = array( + "Name" => "Varchar(255)", + "Comment" => "Text" + ); + + static $has_many = array(); + + public function providePermissions(){ + return array( + 'EDIT_Comment' => 'Edit Comment Objects', + 'CREATE_Comment' => 'Create Comment Objects', + 'DELETE_Comment' => 'Delete Comment Objects', + ); + } + + public function canView($member = null) { + return true; + } + + public function canEdit($member = null) { + return Permission::checkMember($member, 'EDIT_Comment'); + } + + public function canDelete($member = null) { + return Permission::checkMember($member, 'DELETE_Comment'); + } + + public function canCreate($member = null) { + return Permission::checkMember($member, 'CREATE_Comment'); + } + +} + +class SoapModelAccessTest_Page extends DataObject implements TestOnly { + + static $api_access = false; + + static $db = array( + 'Title' => 'Text', + 'Content' => 'HTMLText', + ); +} +?> \ No newline at end of file diff --git a/tests/SoapModelAccessTest.yml b/tests/SoapModelAccessTest.yml new file mode 100644 index 000000000..11b4f7b49 --- /dev/null +++ b/tests/SoapModelAccessTest.yml @@ -0,0 +1,38 @@ +SoapModelAccessTest_Comment: + comment1: + Name: Joe + Comment: This is a test comment +Member: + editor: + FirstName: Editor + Email: editor@test.com + Password: editor + user: + FirstName: User + Email: user@test.com + Password: user +Group: + editorgroup: + Title: Editors + Code: editors + Members: =>Member.editor + usergroup: + Title: Users + Code: users + Members: =>Member.user +Permission: + perm1: + Code: CREATE_Comment + Group: =>Group.usergroup + perm3: + Code: EDIT_Comment + Group: =>Group.editorgroup + perm4: + Code: DELETE_Comment + Group: =>Group.editorgroup + perm5: + Code: CREATE_Comment + Group: =>Group.editorgroup +SoapModelAccessTest_Page: + page1: + Title: Testpage without API Access \ No newline at end of file