diff --git a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php index 507ad4ef73..ce26384b35 100644 --- a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php +++ b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php @@ -315,10 +315,9 @@ class AphrontDefaultApplicationConfiguration '/status/$' => 'PhabricatorStatusController', '/paste/' => array( - '$' => 'PhabricatorPasteCreateController', - 'list/' => 'PhabricatorPasteListController', + '$' => 'PhabricatorPasteListController', + 'filter/(?P\w+)/$' => 'PhabricatorPasteListController', ), - '/P(?P\d+)$' => 'PhabricatorPasteViewController', '/help/' => array( diff --git a/src/applications/paste/controller/base/PhabricatorPasteController.php b/src/applications/paste/controller/base/PhabricatorPasteController.php index 92eac1bba7..97a5fae593 100644 --- a/src/applications/paste/controller/base/PhabricatorPasteController.php +++ b/src/applications/paste/controller/base/PhabricatorPasteController.php @@ -26,15 +26,6 @@ abstract class PhabricatorPasteController extends PhabricatorController { $page->setBaseURI('/paste/'); $page->setTitle(idx($data, 'title')); $page->setGlyph("\xE2\x9C\x8E"); - $page->setTabs( - array( - 'list' => array( - 'href' => '/paste/list/', - 'name' => 'Paste List', - ), - ), - idx($data, 'tab')); - $page->appendChild($view); $response = new AphrontWebpageResponse(); diff --git a/src/applications/paste/controller/create/PhabricatorPasteCreateController.php b/src/applications/paste/controller/create/PhabricatorPasteCreateController.php deleted file mode 100644 index 27aa6ef28a..0000000000 --- a/src/applications/paste/controller/create/PhabricatorPasteCreateController.php +++ /dev/null @@ -1,156 +0,0 @@ -getRequest(); - $user = $request->getUser(); - $paste = new PhabricatorPaste(); - - $error_view = null; - $e_text = true; - - $fork = $request->getInt('fork'); - - $paste_text = null; - $paste_parent = null; - - if ($request->isFormPost()) { - $errors = array(); - $title = $request->getStr('title'); - - $paste_language = $request->getStr('language'); - - $text = $request->getStr('text'); - - if (!strlen($text)) { - $e_text = 'Required'; - $errors[] = 'The paste may not be blank.'; - } else { - $e_text = null; - } - - $parent = id(new PhabricatorPaste())->loadOneWhere( - 'phid = %s', - $request->getStr('parent')); - - if ($parent) { - $paste->setParentPHID($parent->getPHID()); - } - - $paste->setTitle($title); - - if (!$errors) { - if ($paste_language == 'infer') { - // If it's infer, store an empty string. Otherwise, store the - // language name. We do this so we can refer to 'infer' elsewhere - // in the code (such as default value) while retaining backwards - // compatibility with old posts with no language stored. - $paste_language = ''; - } - $paste->setLanguage($paste_language); - - $paste_file = PhabricatorFile::newFromFileData( - $text, - array( - 'name' => $title, - 'mime-type' => 'text/plain; charset=utf-8', - 'authorPHID' => $user->getPHID(), - )); - $paste->setFilePHID($paste_file->getPHID()); - $paste->setAuthorPHID($user->getPHID()); - $paste->save(); - - return id(new AphrontRedirectResponse()) - ->setURI('/P'.$paste->getID()); - } else { - $error_view = new AphrontErrorView(); - $error_view->setErrors($errors); - $error_view->setTitle('A problem has occurred!'); - } - } else { - if ($fork) { - $fork_paste = id(new PhabricatorPaste())->load($fork); - if ($fork_paste) { - $paste->setTitle('Fork of '.$fork_paste->getID().': '. - $fork_paste->getTitle()); - $fork_file = id(new PhabricatorFile())->loadOneWhere( - 'phid = %s', - $fork_paste->getFilePHID()); - $paste_text = $fork_file->loadFileData(); - $paste_language = nonempty($fork_paste->getLanguage(), 'infer'); - $paste_parent = $fork_paste->getPHID(); - } - } else { - $paste_language = PhabricatorEnv::getEnvConfig( - 'pygments.dropdown-default'); - } - } - - $form = new AphrontFormView(); - - $available_languages = PhabricatorEnv::getEnvConfig( - 'pygments.dropdown-choices'); - asort($available_languages); - - $language_select = id(new AphrontFormSelectControl()) - ->setLabel('Language') - ->setName('language') - ->setValue($paste_language) - ->setOptions($available_languages); - - $form - ->setUser($user) - ->setAction($request->getRequestURI()->getPath()) - ->addHiddenInput('parent', $paste_parent) - ->appendChild( - id(new AphrontFormTextControl()) - ->setLabel('Title') - ->setValue($paste->getTitle()) - ->setName('title')) - ->appendChild($language_select) - ->appendChild( - id(new AphrontFormTextAreaControl()) - ->setLabel('Text') - ->setError($e_text) - ->setValue($paste_text) - ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL) - ->setName('text')) - ->appendChild( - id(new AphrontFormSubmitControl()) - ->addCancelButton('/paste/') - ->setValue('Create Paste')); - - $panel = new AphrontPanelView(); - $panel->setWidth(AphrontPanelView::WIDTH_FORM); - $panel->setHeader('Create a Paste'); - $panel->appendChild($form); - - return $this->buildStandardPageResponse( - array( - $error_view, - $panel, - ), - array( - 'title' => 'Paste Creation', - 'tab' => 'create', - )); - } -} diff --git a/src/applications/paste/controller/create/__init__.php b/src/applications/paste/controller/create/__init__.php deleted file mode 100644 index d0215f70f2..0000000000 --- a/src/applications/paste/controller/create/__init__.php +++ /dev/null @@ -1,25 +0,0 @@ -filter = $filter; + return $this; + } + private function getFilter() { + return $this->filter; + } + + private function setErrorView($error_view) { + $this->errorView = $error_view; + return $this; + } + private function getErrorView() { + return $this->errorView; + } + + private function setErrorText($error_text) { + $this->errorText = $error_text; + return $this; + } + private function getErrorText() { + return $this->errorText; + } + + private function setPaste(PhabricatorPaste $paste) { + $this->paste = $paste; + return $this; + } + private function getPaste() { + return $this->paste; + } + + private function setPasteText($paste_text) { + $this->pasteText = $paste_text; + return $this; + } + private function getPasteText() { + return $this->pasteText; + } + + private function setOffset($offset) { + $this->offset = $offset; + return $this; + } + private function getOffset() { + return $this->offset; + } + + private function setPageSize($page_size) { + $this->pageSize = $page_size; + return $this; + } + private function getPageSize() { + return $this->pageSize; + } + + private function setAuthor($author) { + $this->author = $author; + return $this; + } + private function getAuthor() { + return $this->author; + } + + public function willProcessRequest(array $data) { + $this->setFilter(idx($data, 'filter', 'create')); + } public function processRequest() { $request = $this->getRequest(); + $user = $request->getUser(); + $paste_list = array(); + $pager = null; + + switch ($this->getFilter()) { + case 'create': + default: + // if we successfully create a paste, we redirect to view it + $created_paste_redirect = $this->processCreateRequest(); + if ($created_paste_redirect) { + return $created_paste_redirect; + } + // if we didn't succeed or we weren't trying, load just a few + // recent pastes with NO pagination + $this->setOffset(0); + $this->setPageSize(10); + list($paste_list, $pager) = $this->loadPasteList(); + break; + + case 'my': + $this->setAuthor($user->getPHID()); + $this->setOffset($request->getInt('page', 0)); + list($paste_list, $pager) = $this->loadPasteList(); + break; + + case 'all': + $this->setOffset($request->getInt('page', 0)); + list($paste_list, $pager) = $this->loadPasteList(); + break; + } + + $filters = array( + 'create' => array( + 'name' => 'Create Paste', + ), + 'my' => array( + 'name' => 'My Pastes', + ), + 'all' => array( + 'name' => 'All Pastes', + ), + ); + + $side_nav = new AphrontSideNavView(); + foreach ($filters as $filter_key => $filter) { + $selected = $filter_key == $this->getFilter(); + $side_nav->addNavItem( + phutil_render_tag( + 'a', + array( + 'href' => '/paste/filter/'.$filter_key.'/', + 'class' => $selected ? 'aphront-side-nav-selected': null, + ), + $filter['name']) + ); + } + + if ($this->getErrorView()) { + $side_nav->appendChild($this->getErrorView()); + } + + switch ($this->getFilter()) { + case 'create': + default: + $side_nav->appendChild($this->renderCreatePaste()); + $see_all = phutil_render_tag( + 'a', + array( + 'href' => '/paste/filter/all', + ), + 'See all Pastes'); + $header = "Recent Pastes · {$see_all}"; + $side_nav->appendChild($this->renderPasteList($paste_list, + $header, + $pager = null)); + break; + case 'my': + $header = 'Your Pastes'; + $side_nav->appendChild($this->renderPasteList($paste_list, + $header, + $pager)); + break; + case 'all': + $header = 'All Pastes'; + $side_nav->appendChild($this->renderPasteList($paste_list, + $header, + $pager)); + break; + } + + return $this->buildStandardPageResponse( + $side_nav, + array( + 'title' => 'Paste', + ) + ); + } + + private function processCreateRequest() { + $request = $this->getRequest(); + $user = $request->getUser(); + $fork = $request->getInt('fork'); + + $error_view = null; + $e_text = true; + $new_paste = new PhabricatorPaste(); + $new_paste_text = null; + $new_paste_language = PhabricatorEnv::getEnvConfig( + 'pygments.dropdown-default'); + + if ($request->isFormPost()) { + $errors = array(); + + $text = $request->getStr('text'); + if (!strlen($text)) { + $e_text = 'Required'; + $errors[] = 'The paste may not be blank.'; + } else { + $e_text = null; + } + + $parent_phid = $request->getStr('parent'); + if ($parent_phid) { + $parent = id(new PhabricatorPaste())->loadOneWhere('phid = %s', + $parent_phid); + if ($parent) { + $new_paste->setParentPHID($parent->getPHID()); + } + } + + $title = $request->getStr('title'); + $new_paste->setTitle($title); + + $new_paste_language = $request->getStr('language'); + + if (!$errors) { + if ($new_paste_language == 'infer') { + // If it's infer, store an empty string. Otherwise, store the + // language name. We do this so we can refer to 'infer' elsewhere + // in the code (such as default value) while retaining backwards + // compatibility with old posts with no language stored. + $new_paste_language = ''; + } + $new_paste->setLanguage($new_paste_language); + + $new_paste_file = PhabricatorFile::newFromFileData( + $text, + array( + 'name' => $title, + 'mime-type' => 'text/plain; charset=utf-8', + 'authorPHID' => $user->getPHID(), + )); + $new_paste->setFilePHID($new_paste_file->getPHID()); + $new_paste->setAuthorPHID($user->getPHID()); + $new_paste->save(); + + return id(new AphrontRedirectResponse()) + ->setURI('/P'.$new_paste->getID()); + } else { + $error_view = new AphrontErrorView(); + $error_view->setErrors($errors); + $error_view->setTitle('A problem has occurred!'); + } + } else if ($fork) { + $fork_paste = id(new PhabricatorPaste())->load($fork); + if ($fork_paste) { + $new_paste->setTitle('Fork of '.$fork_paste->getID().': '. + $fork_paste->getTitle()); + $fork_file = id(new PhabricatorFile())->loadOneWhere( + 'phid = %s', + $fork_paste->getFilePHID()); + $new_paste_text = $fork_file->loadFileData(); + $new_paste_language = nonempty($fork_paste->getLanguage(), 'infer'); + $new_paste->setParentPHID($fork_paste->getPHID()); + } + } + $this->setErrorView($error_view); + $this->setErrorText($e_text); + $this->setPasteText($new_paste_text); + $new_paste->setLanguage($new_paste_language); + $this->setPaste($new_paste); + } + + private function loadPasteList() { + $request = $this->getRequest(); $pager = new AphrontPagerView(); - $pager->setOffset($request->getInt('page')); + $pager->setOffset($this->getOffset()); + if ($this->getPageSize()) { + $pager->setPageSize($this->getPageSize()); + } - $pastes = id(new PhabricatorPaste())->loadAllWhere( - '1 = 1 ORDER BY id DESC LIMIT %d, %d', - $pager->getOffset(), - $pager->getPageSize() + 1); + if ($this->getAuthor()) { + $pastes = id(new PhabricatorPaste())->loadAllWhere( + 'authorPHID = %s ORDER BY id DESC LIMIT %d, %d', + $this->getAuthor(), + $pager->getOffset(), + $pager->getPageSize() + 1); + } else { + $pastes = id(new PhabricatorPaste())->loadAllWhere( + '1 = 1 ORDER BY id DESC LIMIT %d, %d', + $pager->getOffset(), + $pager->getPageSize() + 1); + } $pastes = $pager->sliceResults($pastes); $pager->setURI($request->getRequestURI(), 'page'); @@ -39,12 +313,12 @@ class PhabricatorPasteListController extends PhabricatorPasteController { $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles(); } - $rows = array(); + $paste_list_rows = array(); foreach ($pastes as $paste) { $handle = $handles[$paste->getAuthorPHID()]; - $rows[] = array( + $paste_list_rows[] = array( phutil_escape_html('P'.$paste->getID()), // TODO: Make this filter by user instead of going to their profile. @@ -77,7 +351,60 @@ class PhabricatorPasteListController extends PhabricatorPasteController { ); } - $table = new AphrontTableView($rows); + return array($paste_list_rows, $pager); + } + + private function renderCreatePaste() { + $request = $this->getRequest(); + $user = $request->getUser(); + + $new_paste = $this->getPaste(); + + $form = new AphrontFormView(); + + $available_languages = PhabricatorEnv::getEnvConfig( + 'pygments.dropdown-choices'); + asort($available_languages); + $language_select = id(new AphrontFormSelectControl()) + ->setLabel('Language') + ->setName('language') + ->setValue($new_paste->getLanguage()) + ->setOptions($available_languages); + + $form + ->setUser($user) + ->setAction($request->getRequestURI()->getPath()) + ->addHiddenInput('parent', $new_paste->getParentPHID()) + ->appendChild( + id(new AphrontFormTextControl()) + ->setLabel('Title') + ->setValue($new_paste->getTitle()) + ->setName('title')) + ->appendChild($language_select) + ->appendChild( + id(new AphrontFormTextAreaControl()) + ->setLabel('Text') + ->setError($this->getErrorText()) + ->setValue($this->getPasteText()) + ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL) + ->setName('text')) + ->appendChild( + id(new AphrontFormSubmitControl()) + ->addCancelButton('/paste/') + ->setValue('Create Paste')); + + $create_panel = new AphrontPanelView(); + $create_panel->setWidth(AphrontPanelView::WIDTH_FULL); + $create_panel->setHeader('Create a Paste'); + $create_panel->appendChild($form); + + return $create_panel; + } + + private function renderPasteList($paste_list_rows, + $header, + $pager = null) { + $table = new AphrontTableView($paste_list_rows); $table->setHeaders( array( 'Paste ID', @@ -98,17 +425,12 @@ class PhabricatorPasteListController extends PhabricatorPasteController { $panel = new AphrontPanelView(); $panel->setWidth(AphrontPanelView::WIDTH_FULL); - $panel->setHeader("Paste"); - $panel->setCreateButton('Paste Something', '/paste/'); + $panel->setHeader($header); $panel->appendChild($table); - $panel->appendChild($pager); + if ($pager) { + $panel->appendChild($pager); + } - return $this->buildStandardPageResponse( - $panel, - array( - 'title' => 'Paste List', - 'tab' => 'list', - ) - ); + return $panel; } } diff --git a/src/applications/paste/controller/list/__init__.php b/src/applications/paste/controller/list/__init__.php index 76dd5f1fa1..3732b36750 100644 --- a/src/applications/paste/controller/list/__init__.php +++ b/src/applications/paste/controller/list/__init__.php @@ -6,13 +6,23 @@ +phutil_require_module('phabricator', 'aphront/response/redirect'); +phutil_require_module('phabricator', 'applications/files/storage/file'); phutil_require_module('phabricator', 'applications/files/uri'); phutil_require_module('phabricator', 'applications/paste/controller/base'); phutil_require_module('phabricator', 'applications/paste/storage/paste'); phutil_require_module('phabricator', 'applications/phid/handle/data'); +phutil_require_module('phabricator', 'infrastructure/env'); phutil_require_module('phabricator', 'view/control/pager'); phutil_require_module('phabricator', 'view/control/table'); +phutil_require_module('phabricator', 'view/form/base'); +phutil_require_module('phabricator', 'view/form/control/select'); +phutil_require_module('phabricator', 'view/form/control/submit'); +phutil_require_module('phabricator', 'view/form/control/text'); +phutil_require_module('phabricator', 'view/form/control/textarea'); +phutil_require_module('phabricator', 'view/form/error'); phutil_require_module('phabricator', 'view/layout/panel'); +phutil_require_module('phabricator', 'view/layout/sidenav'); phutil_require_module('phutil', 'markup'); phutil_require_module('phutil', 'utils');