public function Field($properties = array())
 {
     $config = array('timeformat' => $this->getConfig('timeformat'));
     $config = array_filter($config);
     $this->addExtraClass(Convert::raw2json($config));
     return parent::Field($properties);
 }
 public function run(SS_List $records)
 {
     $status = array('modified' => array(), 'deleted' => array());
     foreach ($records as $record) {
         $id = $record->ID;
         // Perform the action
         if ($record->canDelete()) {
             $record->delete();
         }
         $status['deleted'][$id] = array();
         $record->destroy();
         unset($record);
     }
     return Convert::raw2json($status);
 }
 /**
  * Helper method for responding to a back action request
  * @param string $successMessage The message to return as a notification.
  * Can have up to two %d's in it. The first will be replaced by the number of successful
  * changes, the second by the number of failures
  * @param array $status A status array like batchactions builds. Should be
  * key => value pairs, the key can be any string: "error" indicates errors, anything
  * else indicates a type of success. The value is an array. We don't care what's in it,
  * we just use count($value) to find the number of items that succeeded or failed
  * @return string
  */
 public function response($successMessage, $status)
 {
     $count = 0;
     $errors = 0;
     foreach ($status as $k => $v) {
         switch ($k) {
             case 'error':
                 $errors += count($v);
                 break;
             case 'success':
                 $count += count($v);
                 break;
         }
     }
     $response = Controller::curr()->getResponse();
     if ($response) {
         $response->setStatusCode(200, sprintf($successMessage, $count, $errors));
     }
     return Convert::raw2json($status);
 }
 /**
  * Update the position and parent of a tree node.
  * Only saves the node if changes were made.
  *
  * Required data:
  * - 'ID': The moved node
  * - 'ParentID': New parent relation of the moved node (0 for root)
  * - 'SiblingIDs': Array of all sibling nodes to the moved node (incl. the node itself).
  *   In case of a 'ParentID' change, relates to the new siblings under the new parent.
  *
  * @param HTTPRequest $request
  * @return HTTPResponse JSON string with a
  * @throws HTTPResponse_Exception
  */
 public function savetreenode($request)
 {
     if (!SecurityToken::inst()->checkRequest($request)) {
         return $this->httpError(400);
     }
     if (!Permission::check('SITETREE_REORGANISE') && !Permission::check('ADMIN')) {
         $this->getResponse()->setStatusCode(403, _t('LeftAndMain.CANT_REORGANISE', "You do not have permission to rearange the site tree. Your change was not saved."));
         return;
     }
     $className = $this->stat('tree_class');
     $statusUpdates = array('modified' => array());
     $id = $request->requestVar('ID');
     $parentID = $request->requestVar('ParentID');
     if ($className == 'SilverStripe\\CMS\\Model\\SiteTree' && ($page = DataObject::get_by_id('Page', $id))) {
         $root = $page->getParentType();
         if (($parentID == '0' || $root == 'root') && !SiteConfig::current_site_config()->canCreateTopLevel()) {
             $this->getResponse()->setStatusCode(403, _t('LeftAndMain.CANT_REORGANISE', "You do not have permission to alter Top level pages. Your change was not saved."));
             return;
         }
     }
     $siblingIDs = $request->requestVar('SiblingIDs');
     $statusUpdates = array('modified' => array());
     if (!is_numeric($id) || !is_numeric($parentID)) {
         throw new InvalidArgumentException();
     }
     $node = DataObject::get_by_id($className, $id);
     if ($node && !$node->canEdit()) {
         return Security::permissionFailure($this);
     }
     if (!$node) {
         $this->getResponse()->setStatusCode(500, _t('LeftAndMain.PLEASESAVE', "Please Save Page: This page could not be updated because it hasn't been saved yet."));
         return;
     }
     // Update hierarchy (only if ParentID changed)
     if ($node->ParentID != $parentID) {
         $node->ParentID = (int) $parentID;
         $node->write();
         $statusUpdates['modified'][$node->ID] = array('TreeTitle' => $node->TreeTitle);
         // Update all dependent pages
         if (class_exists('SilverStripe\\CMS\\Model\\VirtualPage')) {
             $virtualPages = VirtualPage::get()->filter("CopyContentFromID", $node->ID);
             foreach ($virtualPages as $virtualPage) {
                 $statusUpdates['modified'][$virtualPage->ID] = array('TreeTitle' => $virtualPage->TreeTitle());
             }
         }
         $this->getResponse()->addHeader('X-Status', rawurlencode(_t('LeftAndMain.REORGANISATIONSUCCESSFUL', 'Reorganised the site tree successfully.')));
     }
     // Update sorting
     if (is_array($siblingIDs)) {
         $counter = 0;
         foreach ($siblingIDs as $id) {
             if ($id == $node->ID) {
                 $node->Sort = ++$counter;
                 $node->write();
                 $statusUpdates['modified'][$node->ID] = array('TreeTitle' => $node->TreeTitle);
             } else {
                 if (is_numeric($id)) {
                     // Nodes that weren't "actually moved" shouldn't be registered as
                     // having been edited; do a direct SQL update instead
                     ++$counter;
                     DB::prepared_query("UPDATE \"{$className}\" SET \"Sort\" = ? WHERE \"ID\" = ?", array($counter, $id));
                 }
             }
         }
         $this->getResponse()->addHeader('X-Status', rawurlencode(_t('LeftAndMain.REORGANISATIONSUCCESSFUL', 'Reorganised the site tree successfully.')));
     }
     return Convert::raw2json($statusUpdates);
 }
 /**
  * Return JSON encoded value
  *
  * @return string
  */
 public function JSON()
 {
     return Convert::raw2json($this->RAW());
 }
 /**
  * Determines if a specified file exists
  *
  * @param HTTPRequest $request
  * @return HTTPResponse
  */
 public function fileexists(HTTPRequest $request)
 {
     // Assert that requested filename doesn't attempt to escape the directory
     $originalFile = $request->requestVar('filename');
     if ($originalFile !== basename($originalFile)) {
         $return = array('error' => _t('File.NOVALIDUPLOAD', 'File is not a valid upload'));
     } else {
         $return = array('exists' => $this->checkFileExists($originalFile));
     }
     // Encode and present response
     $response = new HTTPResponse(Convert::raw2json($return));
     $response->addHeader('Content-Type', 'application/json');
     if (!empty($return['error'])) {
         $response->setStatusCode(400);
     }
     return $response;
 }
 /**
  * REST endpoint to publish a {@link ChangeSet} and all of its items.
  *
  * @param HTTPRequest $request
  *
  * @return HTTPResponse
  */
 public function publishCampaign(HTTPRequest $request)
 {
     // Protect against CSRF on destructive action
     if (!SecurityToken::inst()->checkRequest($request)) {
         return new HTTPResponse(null, 400);
     }
     $id = $request->param('ID');
     if (!$id || !is_numeric($id)) {
         return new HTTPResponse(null, 400);
     }
     /** @var ChangeSet $record */
     $record = ChangeSet::get()->byID($id);
     if (!$record) {
         return new HTTPResponse(null, 404);
     }
     if (!$record->canPublish()) {
         return new HTTPResponse(null, 403);
     }
     try {
         $record->publish();
     } catch (LogicException $e) {
         return (new HTTPResponse(json_encode(['status' => 'error', 'message' => $e->getMessage()]), 401))->addHeader('Content-Type', 'application/json');
     }
     return (new HTTPResponse(Convert::raw2json($this->getChangeSetResource($record)), 200))->addHeader('Content-Type', 'application/json');
 }
 /**
  * @param array $properties
  * @return string
  */
 public function Field($properties = array())
 {
     $item = DataObject::singleton($this->sourceObject);
     $emptyTitle = _t('DropdownField.CHOOSE_MODEL', '(Choose {name})', ['name' => $item->i18n_singular_name()]);
     $record = $this->Value() ? $this->objectForKey($this->Value()) : null;
     if ($record instanceof ViewableData) {
         $title = $record->obj($this->labelField)->forTemplate();
     } elseif ($record) {
         $title = Convert::raw2xml($record->{$this->labelField});
     } else {
         $title = $emptyTitle;
     }
     // TODO Implement for TreeMultiSelectField
     $metadata = array('id' => $record ? $record->ID : null, 'ClassName' => $record ? $record->ClassName : $this->sourceObject);
     $properties = array_merge($properties, array('Title' => $title, 'EmptyTitle' => $emptyTitle, 'Metadata' => $metadata ? Convert::raw2json($metadata) : null));
     return parent::Field($properties);
 }
 /**
  * Out of the box, the handler "CurrentForm" value, which will return the rendered form.
  * Non-Ajax calls will redirect back.
  *
  * @param HTTPRequest $request
  * @param array $extraCallbacks List of anonymous functions or callables returning either a string
  * or HTTPResponse, keyed by their fragment identifier. The 'default' key can
  * be used as a fallback for non-ajax responses.
  * @return HTTPResponse
  * @throws HTTPResponse_Exception
  */
 public function respond(HTTPRequest $request, $extraCallbacks = array())
 {
     // Prepare the default options and combine with the others
     $callbacks = array_merge($this->callbacks, $extraCallbacks);
     $response = $this->getResponse();
     $responseParts = array();
     if (isset($this->fragmentOverride)) {
         $fragments = $this->fragmentOverride;
     } elseif ($fragmentStr = $request->getHeader('X-Pjax')) {
         $fragments = explode(',', $fragmentStr);
     } else {
         if ($request->isAjax()) {
             throw new HTTPResponse_Exception("Ajax requests to this URL require an X-Pjax header.", 400);
         } elseif (empty($callbacks['default'])) {
             throw new HTTPResponse_Exception("Missing default response handler for this URL", 400);
         }
         $response->setBody(call_user_func($callbacks['default']));
         return $response;
     }
     // Execute the fragment callbacks and build the response.
     foreach ($fragments as $fragment) {
         if (isset($callbacks[$fragment])) {
             $res = call_user_func($callbacks[$fragment]);
             $responseParts[$fragment] = $res ? (string) $res : $res;
         } else {
             throw new HTTPResponse_Exception("X-Pjax = '{$fragment}' not supported for this URL.", 400);
         }
     }
     $response->setBody(Convert::raw2json($responseParts));
     $response->addHeader('Content-Type', 'text/json');
     return $response;
 }
 /**
  * Tests {@link Convert::raw2json()}
  */
 public function testRaw2JSON()
 {
     // Test object
     $input = new stdClass();
     $input->Title = 'My Object';
     $input->Content = '<p>Data</p>';
     $this->assertEquals('{"Title":"My Object","Content":"<p>Data<\\/p>"}', Convert::raw2json($input));
     // Array
     $array = array('One' => 'Apple', 'Two' => 'Banana');
     $this->assertEquals('{"One":"Apple","Two":"Banana"}', Convert::raw2json($array));
     // String value with already encoded data. Result should be quoted.
     $value = '{"Left": "Value"}';
     $this->assertEquals('"{\\"Left\\": \\"Value\\"}"', Convert::raw2json($value));
 }
 /**
  * Action to handle upload of a single file
  *
  * @param HTTPRequest $request
  * @return HTTPResponse
  */
 public function upload(HTTPRequest $request)
 {
     if ($this->isDisabled() || $this->isReadonly() || !$this->canUpload()) {
         return $this->httpError(403);
     }
     // Protect against CSRF on destructive action
     $token = $this->getForm()->getSecurityToken();
     if (!$token->checkRequest($request)) {
         return $this->httpError(400);
     }
     // Get form details
     $name = $this->getName();
     $postVars = $request->postVar($name);
     // Extract uploaded files from Form data
     $uploadedFile = $this->extractUploadedFileData($postVars);
     if (!$uploadedFile) {
         return $this->httpError(400);
     }
     // Save the temporary files into a File objects
     // and save data/error on a per file basis
     $result = $this->saveTemporaryFile($uploadedFile, $error);
     if (empty($result)) {
         $return = array('error' => $error);
     } else {
         $return = $this->encodeAssetAttributes($result['Filename'], $result['Hash'], $result['Variant']);
     }
     $this->getUpload()->clearErrors();
     // Format response with json
     $response = new HTTPResponse(Convert::raw2json(array($return)));
     $response->addHeader('Content-Type', 'text/plain');
     return $response;
 }