diff --git a/.gitignore b/.gitignore index 6f2a14d2b2..4b1b47df26 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,7 @@ /src/.phutil_module_cache /conf/custom/* /.divinercache +.#* +*# +*~ +*.swp diff --git a/resources/sql/patches/043.pastebin.sql b/resources/sql/patches/043.pastebin.sql new file mode 100644 index 0000000000..208ade90a1 --- /dev/null +++ b/resources/sql/patches/043.pastebin.sql @@ -0,0 +1,17 @@ +CREATE DATABASE phabricator_pastebin; + +CREATE TABLE phabricator_pastebin.pastebin_paste ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + title VARCHAR(255) NOT NULL, + phid VARCHAR(64) BINARY NOT NULL, + authorPHID VARCHAR(64) BINARY NOT NULL, + filePHID VARCHAR(64) BINARY NOT NULL, + dateCreated INT UNSIGNED NOT NULL, + dateModified INT UNSIGNED NOT NULL +); + +INSERT INTO phabricator_directory.directory_item + (name, description, href, categoryID, sequence, dateCreated, dateModified) +VALUES + ("Paste", "Mmm... tasty, delicious paste.", "/paste/", 5, 150, + UNIX_TIMESTAMP(), UNIX_TIMESTAMP()); \ No newline at end of file diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 2bcb47d2e3..344b963863 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -398,6 +398,12 @@ phutil_register_library_map(array( 'PhabricatorPHIDDAO' => 'applications/phid/storage/base', 'PhabricatorPHIDListController' => 'applications/phid/controller/list', 'PhabricatorPHIDLookupController' => 'applications/phid/controller/lookup', + 'PhabricatorPaste' => 'applications/paste/storage/paste', + 'PhabricatorPasteController' => 'applications/paste/controller/base', + 'PhabricatorPasteCreateController' => 'applications/paste/controller/create', + 'PhabricatorPasteDAO' => 'applications/paste/storage/base', + 'PhabricatorPasteHomeController' => 'applications/paste/controller/home', + 'PhabricatorPasteViewController' => 'applications/paste/controller/view', 'PhabricatorPeopleController' => 'applications/people/controller/base', 'PhabricatorPeopleEditController' => 'applications/people/controller/edit', 'PhabricatorPeopleListController' => 'applications/people/controller/list', @@ -840,6 +846,12 @@ phutil_register_library_map(array( 'PhabricatorPHIDDAO' => 'PhabricatorLiskDAO', 'PhabricatorPHIDListController' => 'PhabricatorPHIDController', 'PhabricatorPHIDLookupController' => 'PhabricatorPHIDController', + 'PhabricatorPaste' => 'PhabricatorPasteDAO', + 'PhabricatorPasteController' => 'PhabricatorController', + 'PhabricatorPasteCreateController' => 'PhabricatorPasteController', + 'PhabricatorPasteDAO' => 'PhabricatorLiskDAO', + 'PhabricatorPasteHomeController' => 'PhabricatorPasteController', + 'PhabricatorPasteViewController' => 'PhabricatorPasteController', 'PhabricatorPeopleController' => 'PhabricatorController', 'PhabricatorPeopleEditController' => 'PhabricatorPeopleController', 'PhabricatorPeopleListController' => 'PhabricatorPeopleController', diff --git a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php index 519aed0c70..a7a28111a9 100644 --- a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php +++ b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php @@ -305,6 +305,13 @@ class AphrontDefaultApplicationConfiguration '/status/$' => 'PhabricatorStatusController', + '/paste/' => array( + '$' => 'PhabricatorPasteHomeController', + 'create/' => 'PhabricatorPasteCreateController', + ), + + '/P(?P\d+)$' => 'PhabricatorPasteViewController', + '/help/' => array( 'keyboardshortcut/$' => 'PhabricatorHelpKeyboardShortcutController', ), diff --git a/src/applications/paste/controller/base/PhabricatorPasteController.php b/src/applications/paste/controller/base/PhabricatorPasteController.php new file mode 100644 index 0000000000..2ec153c9dd --- /dev/null +++ b/src/applications/paste/controller/base/PhabricatorPasteController.php @@ -0,0 +1,44 @@ +buildStandardPageView(); + + $page->setApplicationName('Paste'); + $page->setBaseURI('/paste/'); + $page->setTitle(idx($data, 'title')); + $page->setGlyph("\xE2\x9C\x8E"); + $page->setTabs( + array( + 'create' => array( + 'href' => '/paste/create', + 'name' => 'Create a Paste', + ), + ), + idx($data, 'tab')); + + $page->appendChild($view); + + $response = new AphrontWebpageResponse(); + return $response->setContent($page->render()); + + } +} diff --git a/src/applications/paste/controller/base/__init__.php b/src/applications/paste/controller/base/__init__.php new file mode 100644 index 0000000000..b488b10f35 --- /dev/null +++ b/src/applications/paste/controller/base/__init__.php @@ -0,0 +1,15 @@ +getRequest(); + $user = $request->getUser(); + $paste = new PhabricatorPaste(); + + $error_view = null; + $e_text = true; + + if ($request->isFormPost()) { + $errors = array(); + $title = $request->getStr('title'); + $text = $request->getStr('text'); + + if (!strlen($text)) { + $e_text = 'Required'; + $errors[] = 'The paste may not be blank.'; + } else { + $e_text = null; + } + + $paste->setTitle($title); + + if (!$errors) { + $paste_file = PhabricatorFile::newFromFileData( + $text, + array( + 'name' => $title, + )); + $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!'); + } + } + + $form = new AphrontFormView(); + $form + ->setUser($user) + ->setAction($request->getRequestURI()->getPath()) + ->appendChild( + id(new AphrontFormTextControl()) + ->setLabel('Title') + ->setValue($paste->getTitle()) + ->setName('title')) + ->appendChild( + id(new AphrontFormTextAreaControl()) + ->setLabel('Text') + ->setError($e_text) + ->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 new file mode 100644 index 0000000000..f6151ac905 --- /dev/null +++ b/src/applications/paste/controller/create/__init__.php @@ -0,0 +1,23 @@ +getRequest(); + + $pager = new AphrontPagerView(); + $pager->setOffset($request->getInt('page')); + + $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'); + + $phids = mpull($pastes, 'getAuthorPHID'); + $handles = array(); + if ($phids) { + $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles(); + } + + $rows = array(); + foreach ($pastes as $paste) { + + $handle = $handles[$paste->getAuthorPHID()]; + + $rows[] = array( + phutil_escape_html($paste->getPHID()), + phutil_escape_html($paste->getTitle()), + + // TODO: Make this filter by user instead of going to their profile. + phutil_render_tag( + 'a', + array( + 'href' => '/p/'.$handle->getName().'/', + ), + phutil_escape_html($handle->getName())), + + phutil_render_tag( + 'a', + array( + 'href' => PhabricatorFileURI::getViewURIForPHID( + $paste->getFilePHID()), + ), + phutil_escape_html($paste->getFilePHID())), + + phutil_render_tag( + 'a', + array( + 'class' => 'small button grey', + 'href' => '/P'.$paste->getID(), + ), + 'View'), + ); + } + + $table = new AphrontTableView($rows); + $table->setHeaders( + array( + 'PHID', + 'Title', + 'Author', + 'File PHID', + 'View' + )); + + $panel = new AphrontPanelView(); + $panel->setWidth(AphrontPanelView::WIDTH_FULL); + $panel->setHeader("Paste"); + $panel->setCreateButton('Paste Something', '/paste/create/'); + $panel->appendChild($table); + $panel->appendChild($pager); + + return $this->buildStandardPageResponse( + $panel, + array( + 'title' => 'Paste', + ) + ); + } +} diff --git a/src/applications/paste/controller/home/__init__.php b/src/applications/paste/controller/home/__init__.php new file mode 100644 index 0000000000..5962fbc537 --- /dev/null +++ b/src/applications/paste/controller/home/__init__.php @@ -0,0 +1,21 @@ +id = $data['id']; + } + + public function processRequest() { + + $request = $this->getRequest(); + $user = $request->getUser(); + + $paste = id(new PhabricatorPaste())->load($this->id); + if (!$paste) { + return new Aphront404Response(); + } + + $file = id(new PhabricatorFile())->loadOneWhere( + 'phid = %s', + $paste->getFilePHID()); + if (!$file) { + return new Aphront400Response(); + } + + $corpus = $this->buildCorpus($paste, $file); + + /* TODO + $raw_button = phutil_render_tag( + 'a', + array( + 'class' => 'small button grey', + 'href' => '/P'.$paste->getId().'/raw/', + ), + 'Raw Paste'); + */ + + $panel = new AphrontPanelView(); + + if (strlen($paste->getTitle())) { + $panel->setHeader( + 'Viewing Paste '.$paste->getID().' - '. + phutil_escape_html($paste->getTitle())); + } else { + $panel->setHeader('Viewing Paste '.$paste->getID()); + } + + $panel->setWidth(AphrontPanelView::WIDTH_FULL); + $panel->setCreateButton('Paste Something', '/paste/create/'); + $panel->appendChild($corpus); + // $panel->appendChild($raw_button); + + return $this->buildStandardPageResponse( + $panel, + array( + 'title' => 'Viewing Paste '.$this->id, + 'tab' => 'view', + )); + } + + private function buildCorpus($paste, $file) { + // Blantently copied from DiffusionBrowseFileController + + require_celerity_resource('diffusion-source-css'); + require_celerity_resource('syntax-highlighting-css'); + + $highlightEngine = new PhutilDefaultSyntaxHighlighterEngine(); + $highlightEngine->setConfig( + 'pygments.enabled', + PhabricatorEnv::getEnvConfig('pygments.enabled')); + + $text_list = explode( + "\n", $highlightEngine->highlightSource( + $paste->getTitle(), + $file->loadFileData())); + + $rows = $this->buildDisplayRows($text_list); + + $corpus_table = phutil_render_tag( + 'table', + array( + 'class' => "diffusion-source remarkup-code PhabricatorMonospaced", + ), + implode("\n", $rows)); + + $corpus = phutil_render_tag( + 'div', + array( + 'style' => 'padding: 0pt 2em;', + ), + $corpus_table); + + return $corpus; + } + + private function buildDisplayRows($text_list) { + $rows = array(); + $n = 1; + + foreach ($text_list as $k => $line) { + // Pardon the ugly for the time being. + // And eventually this will highlight a line that you click + // like diffusion does. Or maybe allow for line comments + // like differential. Either way it will be better than it is now. + $rows[] = ''.$n.''.$line.''; + ++$n; + } + + return $rows; + } + +} diff --git a/src/applications/paste/controller/view/__init__.php b/src/applications/paste/controller/view/__init__.php new file mode 100644 index 0000000000..6d7b9dc150 --- /dev/null +++ b/src/applications/paste/controller/view/__init__.php @@ -0,0 +1,23 @@ + true, + ) + parent::getConfiguration(); + } + + public function generatePHID() { + return PhabricatorPHID::generateNewPHID( + PhabricatorPHIDConstants::PHID_TYPE_PSTE); + } + +} diff --git a/src/applications/paste/storage/paste/__init__.php b/src/applications/paste/storage/paste/__init__.php new file mode 100644 index 0000000000..ef2ac38a2f --- /dev/null +++ b/src/applications/paste/storage/paste/__init__.php @@ -0,0 +1,14 @@ +