/** * Edit file view. * * @throws Exception */ public function showEdit() { $files = self::getFileList(); $file = $_GET['file']; if (!isset($files[$file])) { throw new Exception('File not found'); } $file = $files[$file]; $form = $this->getEditForm($file); if (isPost()) { $ajax = array('success' => 1); if ($form->isValid($_POST)) { // Save content and preserve EOL style $values = $form->getValues(); $code = $values['content']; $eol = Curry_Util::getStringEol($code); $targetEol = urldecode($values['eol']); if ($eol !== $targetEol) { $code = str_replace($eol, $targetEol, $code); } file_put_contents($file->getPathname(), $code); $form = $this->getEditForm($file); } else { $error = "Validation error!"; foreach ($form->getMessages() as $element => $messages) { $error .= "\n{$element}: " . join(', ', $messages); } $ajax['success'] = 0; $ajax['error'] = $error; } if ($_POST['_ajaxsubmit']) { $form->render(); // fixes issue with csrf-token $ajax['values'] = $form->getValues(); Curry_Application::returnJson($ajax); } } Curry_Admin::getInstance()->addBodyClass('tpl-fullscreen'); Curry_Admin::getInstance()->addBodyClass('tpl-fileeditor'); $this->addMenu($_GET['file']); $this->addMainContent($form); }
/** {@inheritdoc} */ public function showMain() { $rootPage = PageQuery::create()->findRoot(); $code = Curry_Backend_PageSyncHelper::getPageCode($rootPage); $localChecksum = sha1(serialize($code)); if (isPost('fetch')) { Curry_Application::returnJson($code); } $form = new Curry_Form(array('csrfCheck' => false, 'action' => (string) url('', $_GET), 'method' => 'post', 'elements' => array('url' => array('text', array('label' => 'URL', 'placeholder' => 'http://example.com/admin.php', 'value' => isset($_COOKIE['curry:remote_url']) ? $_COOKIE['curry:remote_url'] : '')), 'user' => array('text', array('label' => 'User', 'value' => isset($_COOKIE['curry:remote_user']) ? $_COOKIE['curry:remote_user'] : '******')), 'password' => array('password', array('label' => 'Password', 'value' => '')), 'submit' => array('submit', array('class' => 'btn btn-primary', 'label' => 'Fetch'))))); if (isPost('code')) { // we have page-code if ($localChecksum !== $_POST['local_checksum']) { throw new Exception('Local pages were changed during synchronization process, aborting!'); } $remoteCode = json_decode($_POST['code'], true); // Update selected pages if (isset($_POST['page'])) { $updatedPages = Curry_Backend_PageSyncHelper::restorePages($rootPage, $remoteCode, array_keys($_POST['page'])); $this->addMessage(count($updatedPages) . ' pages updated!', self::MSG_SUCCESS); } // Delete selected pages if (isset($_POST['delete'])) { $pagesToDelete = array_keys($_POST['delete']); foreach ($pagesToDelete as $pageId) { $page = PageQuery::create()->findPk($pageId); if (!$page) { throw new Exception('Unable to find page to delete.'); } if (!$page->isLeaf()) { $this->addMessage('Unable to delete page "' . $page->getName() . '" because it has subpages.', self::MSG_ERROR); continue; } $dependantPages = $page->getDependantPages(); if (count($dependantPages)) { $this->addMessage('Unable to delete page "' . $page->getName() . '" because other pages depend on it.', self::MSG_ERROR); continue; } $page->delete(); $this->addMessage('Deleted page "' . $page->getName() . '"', self::MSG_WARNING); } } } else { if (isPost() && $form->isValid($_POST)) { // have user/password try { $context = stream_context_create(array('http' => array('method' => 'POST', 'header' => 'Content-type: application/x-www-form-urlencoded', 'content' => http_build_query(array('login_username' => $form->user->getValue(), 'login_password' => $form->password->getValue(), 'fetch' => '1'))))); $remote = (string) url($form->url->getValue(), array('module' => 'Curry_Backend_PageSync')); $remoteResponse = file_get_contents($remote, null, $context); if ($remoteResponse === false) { throw new Exception('Invalid response'); } $remoteCode = json_decode($remoteResponse, true); if ($remoteCode === null) { throw new Exception('Invalid json: ' . $remoteResponse); } setcookie('curry:remote_url', $form->url->getValue(), time() + 86400 * 365); setcookie('curry:remote_user', $form->user->getValue(), time() + 86400 * 365); $this->addMainContent('<form action="' . url('', $_GET) . '" method="post" class="well">'); $this->addMainContent('<input type="hidden" name="code" value="' . htmlspecialchars($remoteResponse) . '" />'); $this->addMainContent('<input type="hidden" name="local_checksum" value="' . htmlspecialchars($localChecksum) . '" />'); $this->addMainContent('<ul>'); $this->comparePageCode($code, $remoteCode); $this->addMainContent('</ul>'); $this->addMainContent('<button type="submit" class="btn btn-primary">Sync</button>'); $this->addMainContent('</form>'); } catch (Exception $e) { $this->addMainContent($form); $this->addMessage($e->getMessage(), self::MSG_ERROR); } } else { $this->addMainContent(self::INTRO); $this->addMainContent($form); } } }
public function dispatch(array $action, Curry_Backend $backend, array $params) { if (count($action)) { $nextAction = array_shift($action); if ($nextAction === 'json') { Curry_Application::returnJson($this->getJson($params)); } else { if ($nextAction === 'sort' && is_callable($this->options['sortable'])) { call_user_func($this->options['sortable'], $params); Curry_Application::returnJson(array('success' => 1)); } } $a = $this->actions[$nextAction]; if (!isset($a)) { throw new Exception("Action '{$nextAction}' not found."); } if (!isset($a['action'])) { throw new Exception("Action '{$nextAction}' is not defined."); } $a = $a['action']; if (is_object($a) && $a instanceof Curry_ModelView_Abstract) { $a->parentView = $this; $a->dispatch($action, $backend, $params); } else { if (is_callable($a)) { call_user_func($a, $this->getSelfSelection($params), $backend, $params, $this); } else { throw new Exception("Action '{$nextAction}' has unknown type."); } } } else { $this->render($backend, $params); } }
/** * Return json-data to browser and exit. Will set content-type header and encode the data. * * @deprecated Use Curry_Application::returnJson() instead. * @param mixed $content Data to encode with json_encode. Note that this must be utf-8 encoded. Strings will not be encoded. */ public function returnJson($content) { Curry_Application::returnJson($content); }
/** * Main view. * * @return string */ public function getFinder() { if (isPost() && isset($_REQUEST['action'])) { try { // call instance method $method = 'action' . $_REQUEST['action']; if (!method_exists($this, $method)) { throw new Curry_Exception('Action does not exist.'); } $contentType = isset($_GET['iframe']) ? 'text/html' : 'application/json'; Curry_Application::returnJson($this->{$method}($_REQUEST), "", $contentType); } catch (Exception $e) { if (isAjax()) { $this->returnJson(array('status' => 0, 'error' => $e->getMessage())); } else { $this->addMessage($e->getMessage(), self::MSG_ERROR); } } } $template = Curry_Twig_Template::loadTemplateString(<<<TPL {% spaceless %} <div class="finder"> {% if selection %} <input type="hidden" name="selection" value="{{selection}}" /> {% endif %} <div class="finder-overlay"><p></p></div> <div class="wrapper"> {% for path in paths %} <ul class="folder {{path.IsRoot?'root':''}}" data-finder='{"path":"{{path.Path}}","action":"{{path.UploadUrl}}"}'> {% for file in path.files %} <li class="{{file.IsSelected?'selected':(file.IsHighlighted?'highlighted':'')}} {{file.Icon}}"><a href="{{file.Url}}" class="navigate" data-finder='{"name":"{{file.Name}}","path":"{{file.Path}}"}'>{{file.Name}}</a></li> {% endfor %} </ul> {% endfor %} {% if fileInfo %} <ul class="fileinfo"> {% for Key,Value in fileInfo %} <li class="fileinfo-{{Key|lower}}">{{Value|raw}}</li> {% endfor %} </ul> {% endif %} </div> <div class="btn-toolbar"> <div class="btn-group"> {% for action in actions %} <a href="{{action.Action}}" class="btn {{action.Class}}" data-finder='{{action.Data ? action.Data|json_encode : ''}}'>{{action.Label}}</a> {% endfor %} </div> <select></select> <div class="btn-group"> <button class="btn cancel">Cancel</button> <button class="btn btn-primary select" {{selection?'':'disabled=""'}}>Select</button> </ul> </div> </div> {% endspaceless %} TPL ); $vars = array(); $selected = (array) $_GET['path']; if ($_GET['public'] == 'true') { $virtual = array(); foreach ($selected as $s) { $virtual[] = self::publicToVirtual($s); } $selected = $virtual; } // Verify selection and show selection info if (count($selected)) { try { $vars['fileInfo'] = $this->getFileInfo($selected); $selection = array(); foreach ($selected as $s) { $physical = self::virtualToPhysical($s); $public = self::virtualToPublic($s); $selection[] = $public; if (isset($_GET['type'])) { if ($_GET['type'] == 'folder' && !is_dir($physical)) { $selection = false; break; } if ($_GET['type'] == 'file' && !is_file($physical)) { $selection = false; break; } } } if ($selection) { $vars['selection'] = join(PATH_SEPARATOR, $selection); } } catch (Exception $e) { $selected = array(); } } // Show actions if ($selected && $selected[0]) { $vars['actions'] = array(array('Label' => 'Download', 'Action' => (string) url('', array('module', 'view' => 'Download', 'path' => $selected)))); if ($this->isPhysicalWritable(self::virtualToPhysical($selected[0]))) { $vars['actions'][] = array('Label' => 'Upload', 'Action' => (string) url('', array('module', 'view', 'path' => $selected[0], 'action' => 'Upload')), 'Class' => 'upload'); $vars['actions'][] = array('Label' => 'Delete', 'Action' => (string) url('', array('module', 'view', 'path' => $selected, 'action' => 'Delete')), 'Class' => 'delete'); $vars['actions'][] = array('Label' => 'Create directory', 'Action' => (string) url('', array('module', 'view', 'path' => $selected[0], 'action' => 'CreateDirectory')), 'Class' => 'create-directory'); if (count($selected) == 1) { $vars['actions'][] = array('Label' => 'Rename', 'Action' => (string) url('', array('module', 'view', 'path' => $selected[0], 'action' => 'Rename')), 'Class' => 'rename', 'Data' => array('name' => basename($selected[0]))); } } } $vars['paths'] = self::getPaths($selected); $content = $template->render($vars); if (isAjax()) { $this->returnJson(array('content' => $content, 'maxUploadSize' => Curry_Util::computerReadableBytes(get_cfg_var('upload_max_filesize')), 'path' => $selected)); } else { return $content; } return ''; }
/** * Get properties for tree node. */ public function getTreeJson() { $packages = array(); foreach (Curry_Propel::getModels() as $package => $classes) { $p = array('title' => $package, 'iconClass' => 'icon-folder-open', 'key' => $package, 'children' => array(), 'expand' => true); foreach ($classes as $clazz) { $icon = 'icon-table'; try { $count = call_user_func(array($clazz . 'Peer', 'doCount'), new Criteria()); } catch (Exception $e) { $count = '?'; $icon = 'icon-warning-sign'; } $p['children'][] = array('title' => $clazz . ' (' . $count . ')', 'iconClass' => $icon, 'key' => $clazz, 'href' => (string) url('', array('module', 'view' => 'Table', 'table' => $clazz))); } $packages[] = $p; } Curry_Application::returnJson($packages); }
/** * Return json-data to browser and exit. Will set content-type header and encode the data. * * @deprecated Please use Curry_Application::returnJson() instead. * * @param mixed $content Data to encode with json_encode. Note that this must be utf-8 encoded. Strings will not be encoded. */ public function returnJson($content) { trace_warning('DEPRECATED: ' . __CLASS__ . '::' . __METHOD__ . '(), please use Curry_Application::' . __METHOD__ . '() instead.'); Curry_Application::returnJson($content); }
/** * Rebuild the search index. * * @param bool $ajax * @throws Exception */ public static function doRebuild($ajax = false) { $ses = new Zend_Session_Namespace(__CLASS__); $index = Curry_Core::getSearchIndex(); $app = new Curry_Application(); Curry_URL::setReverseRouteCallback(array($app, 'reverseRoute')); try { while ($ses->model < count($ses->models)) { $model = $ses->models[$ses->model]; if ($model === '@custom') { // Trigger custom indexer $ses->model++; $indexerClass = Curry_Core::$config->curry->indexerClass; if ($indexerClass && is_callable(array($indexerClass, 'build'))) { call_user_func(array($indexerClass, 'build')); } } else { // Remove old entries if (!$ses->offset) { $hits = $index->find('model:' . $model); foreach ($hits as $hit) { $index->delete($hit->id); } } $query = PropelQuery::from($model); $maxItems = $query->count(); $items = $query->offset($ses->offset)->limit($ses->limit)->find(); foreach ($items as $item) { $ses->offset++; if (!self::updateItem($item, $index, false)) { $ses->failed++; } else { $ses->success++; } } // move on to next model? if ($ses->offset >= $maxItems || count($items) < $ses->limit) { $ses->model++; $ses->offset = 0; $maxItems = 1; } } $continue = $ses->model < count($ses->models); if ($continue && $ajax) { // Return current status $part = 1 / count($ses->models); $progress = $ses->model * $part + $ses->offset / $maxItems * $part; Curry_Application::returnJson(array('progress' => round(100 * $progress), 'continue' => true, 'status' => "Indexing " . $ses->models[$ses->model] . "...")); } } // All done! if ($ajax) { $status = "Completed, " . $ses->success . ' entries updated successfully!'; if ($ses->failed) { $status .= ' ' . $ses->failed . ' items failed.'; } Curry_Application::returnJson(array('progress' => 100, 'continue' => false, 'status' => $status)); } } catch (Exception $e) { if ($ajax) { Curry_Application::returnJson(array('continue' => false, 'status' => $e->getMessage())); } else { throw $e; } } }
/** * Cast to string, return HTML or JSON. * * @return string */ public function __toString() { try { if (isset($_GET['json'])) { Curry_Application::returnJson($this->getJson()); } else { return $this->getHtml(); } } catch (Exception $e) { return $e->getMessage(); } return ''; }