private function loadDocuments(AphrontPagerView $pager)
 {
     // TODO: Do we want/need a query object for this?
     $document_dao = new PhrictionDocument();
     $content_dao = new PhrictionContent();
     $conn = $document_dao->establishConnection('r');
     switch ($this->view) {
         case 'all':
             $data = queryfx_all($conn, 'SELECT * FROM %T ORDER BY id DESC LIMIT %d, %d', $document_dao->getTableName(), $pager->getOffset(), $pager->getPageSize() + 1);
             break;
         case 'updates':
             // TODO: This query is a little suspicious, verify we don't need to key
             // or change it once we get more data.
             $data = queryfx_all($conn, 'SELECT d.* FROM %T d JOIN %T c ON c.documentID = d.id
         GROUP BY c.documentID
         ORDER BY MAX(c.id) DESC LIMIT %d, %d', $document_dao->getTableName(), $content_dao->getTableName(), $pager->getOffset(), $pager->getPageSize() + 1);
             break;
         default:
             throw new Exception("Unknown view '{$this->view}'!");
     }
     $data = $pager->sliceResults($data);
     $documents = $document_dao->loadAllFromArray($data);
     if ($documents) {
         $content = $content_dao->loadAllWhere('documentID IN (%Ld)', mpull($documents, 'getID'));
         $content = mpull($content, null, 'getDocumentID');
         foreach ($documents as $document) {
             $document->attachContent($content[$document->getID()]);
         }
     }
     return $documents;
 }
Example #2
0
 public static function initializeNewDocument(PhabricatorUser $actor, $slug)
 {
     $document = new PhrictionDocument();
     $document->setSlug($slug);
     $content = new PhrictionContent();
     $content->setSlug($slug);
     $default_title = PhabricatorSlug::getDefaultTitle($slug);
     $content->setTitle($default_title);
     $document->attachContent($content);
     $parent_doc = null;
     $ancestral_slugs = PhabricatorSlug::getAncestry($slug);
     if ($ancestral_slugs) {
         $parent = end($ancestral_slugs);
         $parent_doc = id(new PhrictionDocumentQuery())->setViewer($actor)->withSlugs(array($parent))->executeOne();
     }
     if ($parent_doc) {
         $document->setViewPolicy($parent_doc->getViewPolicy());
         $document->setEditPolicy($parent_doc->getEditPolicy());
     } else {
         $default_view_policy = PhabricatorPolicies::getMostOpenPolicy();
         $document->setViewPolicy($default_view_policy);
         $document->setEditPolicy(PhabricatorPolicies::POLICY_USER);
     }
     return $document;
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $document = $request->getStr('document');
     $content_obj = new PhrictionContent();
     $content_obj->setContent($document);
     $engine = PhabricatorMarkupEngine::newPhrictionMarkupEngine();
     $content = $content_obj->renderContent();
     return id(new AphrontAjaxResponse())->setContent($content);
 }
 protected final function buildDocumentContentDictionary(PhrictionDocument $doc, PhrictionContent $content)
 {
     $uri = PhrictionDocument::getSlugURI($content->getSlug());
     $uri = PhabricatorEnv::getProductionURI($uri);
     $doc_status = $doc->getStatus();
     return array('phid' => $doc->getPHID(), 'uri' => $uri, 'slug' => $content->getSlug(), 'version' => $content->getVersion(), 'authorPHID' => $content->getAuthorPHID(), 'title' => $content->getTitle(), 'content' => $content->getContent(), 'status' => PhrictionDocumentStatus::getConduitConstant($doc_status), 'description' => $content->getDescription(), 'dateCreated' => $content->getDateCreated());
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $document = $request->getStr('document');
     $draft_key = $request->getStr('draftkey');
     if ($draft_key) {
         id(new PhabricatorDraft())->setAuthorPHID($request->getUser()->getPHID())->setDraftKey($draft_key)->setDraft($document)->replaceOrDelete();
     }
     $content_obj = new PhrictionContent();
     $content_obj->setContent($document);
     $content = $content_obj->renderContent($request->getUser());
     return id(new AphrontAjaxResponse())->setContent($content);
 }
 private function renderRevertButton(PhrictionContent $content, PhrictionContent $current)
 {
     $document_id = $content->getDocumentID();
     $version = $content->getVersion();
     $hidden_statuses = array(PhrictionChangeType::CHANGE_DELETE => true, PhrictionChangeType::CHANGE_MOVE_AWAY => true, PhrictionChangeType::CHANGE_STUB => true);
     if (isset($hidden_statuses[$content->getChangeType()])) {
         // Don't show an edit/revert button for changes which deleted, moved or
         // stubbed the content since it's silly.
         return null;
     }
     if ($content->getID() == $current->getID()) {
         return phutil_tag('a', array('href' => '/phriction/edit/' . $document_id . '/', 'class' => 'button grey'), pht('Edit Current Version'));
     }
     return phutil_tag('a', array('href' => '/phriction/edit/' . $document_id . '/?revert=' . $version, 'class' => 'button grey'), pht('Revert to Version %s...', $version));
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $document = $request->getStr('document');
     $draft_key = $request->getStr('draftkey');
     if ($draft_key) {
         $table = new PhabricatorDraft();
         queryfx($table->establishConnection('w'), 'INSERT INTO %T (authorPHID, draftKey, draft) VALUES (%s, %s, %s)
       ON DUPLICATE KEY UPDATE draft = VALUES(draft)', $table->getTableName(), $request->getUser()->getPHID(), $draft_key, $document);
     }
     $content_obj = new PhrictionContent();
     $content_obj->setContent($document);
     $engine = PhabricatorMarkupEngine::newPhrictionMarkupEngine();
     $content = $content_obj->renderContent();
     return id(new AphrontAjaxResponse())->setContent($content);
 }
 public function save()
 {
     if (!$this->user) {
         throw new Exception("Call setUser() before save()!");
     }
     $document = $this->document;
     $content = $this->content;
     $new_content = new PhrictionContent();
     $new_content->setSlug($document->getSlug());
     $new_content->setAuthorPHID($this->user->getPHID());
     $new_content->setTitle(coalesce($this->newTitle, $content->getTitle()));
     $new_content->setContent(coalesce($this->newContent, $content->getContent()));
     if (strlen($this->description)) {
         $new_content->setDescription($this->description);
     }
     $new_content->setVersion($content->getVersion() + 1);
     // TODO: This should be transactional.
     $is_new = false;
     if (!$document->getID()) {
         $is_new = true;
         $document->save();
     }
     $new_content->setDocumentID($document->getID());
     $new_content->save();
     $document->setContentID($new_content->getID());
     $document->save();
     $document->attachContent($new_content);
     PhabricatorSearchPhrictionIndexer::indexDocument($document);
     id(new PhabricatorFeedStoryPublisher())->setRelatedPHIDs(array($document->getPHID(), $this->user->getPHID()))->setStoryAuthorPHID($this->user->getPHID())->setStoryTime(time())->setStoryType(PhabricatorFeedStoryTypeConstants::STORY_PHRICTION)->setStoryData(array('phid' => $document->getPHID(), 'action' => $is_new ? PhrictionActionConstants::ACTION_CREATE : PhrictionActionConstants::ACTION_EDIT, 'content' => phutil_utf8_shorten($new_content->getContent(), 140)))->publish();
     return $this;
 }
 private function renderChildren($slug)
 {
     $document_dao = new PhrictionDocument();
     $content_dao = new PhrictionContent();
     $conn = $document_dao->establishConnection('r');
     $limit = 50;
     $d_child = PhrictionDocument::getSlugDepth($slug) + 1;
     $d_grandchild = PhrictionDocument::getSlugDepth($slug) + 2;
     // Select children and grandchildren.
     $children = queryfx_all($conn, 'SELECT d.slug, d.depth, c.title FROM %T d JOIN %T c
     ON d.contentID = c.id
     WHERE d.slug LIKE %> AND d.depth IN (%d, %d)
       AND d.status = %d
     ORDER BY d.depth, c.title LIMIT %d', $document_dao->getTableName(), $content_dao->getTableName(), $slug == '/' ? '' : $slug, $d_child, $d_grandchild, PhrictionDocumentStatus::STATUS_EXISTS, $limit);
     if (!$children) {
         return;
     }
     // We're going to render in one of three modes to try to accommodate
     // different information scales:
     //
     //  - If we found fewer than $limit rows, we know we have all the children
     //    and grandchildren and there aren't all that many. We can just render
     //    everything.
     //  - If we found $limit rows but the results included some grandchildren,
     //    we just throw them out and render only the children, as we know we
     //    have them all.
     //  - If we found $limit rows and the results have no grandchildren, we
     //    have a ton of children. Render them and then let the user know that
     //    this is not an exhaustive list.
     if (count($children) == $limit) {
         $more_children = true;
         foreach ($children as $child) {
             if ($child['depth'] == $d_grandchild) {
                 $more_children = false;
             }
         }
         $show_grandchildren = false;
     } else {
         $show_grandchildren = true;
         $more_children = false;
     }
     $grandchildren = array();
     foreach ($children as $key => $child) {
         if ($child['depth'] == $d_child) {
             continue;
         } else {
             unset($children[$key]);
             if ($show_grandchildren) {
                 $ancestors = PhrictionDocument::getSlugAncestry($child['slug']);
                 $grandchildren[end($ancestors)][] = $child;
             }
         }
     }
     // Fill in any missing children.
     $known_slugs = ipull($children, null, 'slug');
     foreach ($grandchildren as $slug => $ignored) {
         if (empty($known_slugs[$slug])) {
             $children[] = array('slug' => $slug, 'depth' => $d_child, 'title' => PhrictionDocument::getDefaultSlugTitle($slug), 'empty' => true);
         }
     }
     $list = array();
     $list[] = '<ul>';
     foreach ($children as $child) {
         $list[] = $this->renderChildDocumentLink($child);
         $grand = idx($grandchildren, $child['slug'], array());
         if ($grand) {
             $list[] = '<ul>';
             foreach ($grand as $grandchild) {
                 $list[] = $this->renderChildDocumentLink($grandchild);
             }
             $list[] = '</ul>';
         }
     }
     if ($more_children) {
         $list[] = '<li>More...</li>';
     }
     $list[] = '</ul>';
     $list = implode("\n", $list);
     return '<div class="phriction-children">' . '<div class="phriction-children-header">Document Hierarchy</div>' . $list . '</div>';
 }
 private function renderRevertButton(PhrictionContent $content, PhrictionContent $current)
 {
     $document_id = $content->getDocumentID();
     $version = $content->getVersion();
     if ($content->getID() == $current->getID()) {
         return phutil_render_tag('a', array('href' => '/phriction/edit/' . $document_id . '/', 'class' => 'button'), 'Edit Current Version');
     }
     return phutil_render_tag('a', array('href' => '/phriction/edit/' . $document_id . '/?revert=' . $version, 'class' => 'button'), 'Revert to Version ' . phutil_escape_html($version) . '...');
 }
 public function loadHandles()
 {
     $types = phid_group_by_type($this->phids);
     $handles = array();
     $external_loaders = PhabricatorEnv::getEnvConfig('phid.external-loaders');
     foreach ($types as $type => $phids) {
         switch ($type) {
             case PhabricatorPHIDConstants::PHID_TYPE_MAGIC:
                 // Black magic!
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     switch ($phid) {
                         case ManiphestTaskOwner::OWNER_UP_FOR_GRABS:
                             $handle->setName('Up For Grabs');
                             $handle->setFullName('upforgrabs (Up For Grabs)');
                             $handle->setComplete(true);
                             break;
                         case ManiphestTaskOwner::PROJECT_NO_PROJECT:
                             $handle->setName('No Project');
                             $handle->setFullName('noproject (No Project)');
                             $handle->setComplete(true);
                             break;
                         default:
                             $handle->setName('Foul Magicks');
                             break;
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_USER:
                 $object = new PhabricatorUser();
                 $users = $object->loadAllWhere('phid IN (%Ls)', $phids);
                 $users = mpull($users, null, 'getPHID');
                 $image_phids = mpull($users, 'getProfileImagePHID');
                 $image_phids = array_unique(array_filter($image_phids));
                 $images = array();
                 if ($image_phids) {
                     $images = id(new PhabricatorFile())->loadAllWhere('phid IN (%Ls)', $image_phids);
                     $images = mpull($images, 'getBestURI', 'getPHID');
                 }
                 $statuses = id(new PhabricatorUserStatus())->loadCurrentStatuses($phids);
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($users[$phid])) {
                         $handle->setName('Unknown User');
                     } else {
                         $user = $users[$phid];
                         $handle->setName($user->getUsername());
                         $handle->setURI('/p/' . $user->getUsername() . '/');
                         $handle->setFullName($user->getUsername() . ' (' . $user->getRealName() . ')');
                         $handle->setAlternateID($user->getID());
                         $handle->setComplete(true);
                         if (isset($statuses[$phid])) {
                             $handle->setStatus($statuses[$phid]->getTextStatus());
                         }
                         $handle->setDisabled($user->getIsDisabled());
                         $img_uri = idx($images, $user->getProfileImagePHID());
                         if ($img_uri) {
                             $handle->setImageURI($img_uri);
                         } else {
                             $handle->setImageURI(PhabricatorUser::getDefaultProfileImageURI());
                         }
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_MLST:
                 $object = new PhabricatorMetaMTAMailingList();
                 $lists = $object->loadAllWhere('phid IN (%Ls)', $phids);
                 $lists = mpull($lists, null, 'getPHID');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($lists[$phid])) {
                         $handle->setName('Unknown Mailing List');
                     } else {
                         $list = $lists[$phid];
                         $handle->setName($list->getName());
                         $handle->setURI($list->getURI());
                         $handle->setFullName($list->getName());
                         $handle->setComplete(true);
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_DREV:
                 $object = new DifferentialRevision();
                 $revs = $object->loadAllWhere('phid in (%Ls)', $phids);
                 $revs = mpull($revs, null, 'getPHID');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($revs[$phid])) {
                         $handle->setName('Unknown Revision');
                     } else {
                         $rev = $revs[$phid];
                         $handle->setName($rev->getTitle());
                         $handle->setURI('/D' . $rev->getID());
                         $handle->setFullName('D' . $rev->getID() . ': ' . $rev->getTitle());
                         $handle->setComplete(true);
                         $status = $rev->getStatus();
                         if ($status == ArcanistDifferentialRevisionStatus::CLOSED || $status == ArcanistDifferentialRevisionStatus::ABANDONED) {
                             $closed = PhabricatorObjectHandleStatus::STATUS_CLOSED;
                             $handle->setStatus($closed);
                         }
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_CMIT:
                 $object = new PhabricatorRepositoryCommit();
                 $commits = $object->loadAllWhere('phid in (%Ls)', $phids);
                 $commits = mpull($commits, null, 'getPHID');
                 $repository_ids = array();
                 $callsigns = array();
                 if ($commits) {
                     $repository_ids = mpull($commits, 'getRepositoryID');
                     $repositories = id(new PhabricatorRepository())->loadAllWhere('id in (%Ld)', array_unique($repository_ids));
                     $callsigns = mpull($repositories, 'getCallsign');
                 }
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($commits[$phid]) || !isset($callsigns[$repository_ids[$phid]])) {
                         $handle->setName('Unknown Commit');
                     } else {
                         $commit = $commits[$phid];
                         $callsign = $callsigns[$repository_ids[$phid]];
                         $repository = $repositories[$repository_ids[$phid]];
                         $commit_identifier = $commit->getCommitIdentifier();
                         // In case where the repository for the commit was deleted,
                         // we don't have have info about the repository anymore.
                         if ($repository) {
                             $name = $repository->formatCommitName($commit_identifier);
                             $handle->setName($name);
                         } else {
                             $handle->setName('Commit ' . 'r' . $callsign . $commit_identifier);
                         }
                         $handle->setURI('/r' . $callsign . $commit_identifier);
                         $handle->setFullName('r' . $callsign . $commit_identifier);
                         $handle->setTimestamp($commit->getEpoch());
                         $handle->setComplete(true);
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_TASK:
                 $object = new ManiphestTask();
                 $tasks = $object->loadAllWhere('phid in (%Ls)', $phids);
                 $tasks = mpull($tasks, null, 'getPHID');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($tasks[$phid])) {
                         $handle->setName('Unknown Revision');
                     } else {
                         $task = $tasks[$phid];
                         $handle->setName($task->getTitle());
                         $handle->setURI('/T' . $task->getID());
                         $handle->setFullName('T' . $task->getID() . ': ' . $task->getTitle());
                         $handle->setComplete(true);
                         $handle->setAlternateID($task->getID());
                         if ($task->getStatus() != ManiphestTaskStatus::STATUS_OPEN) {
                             $closed = PhabricatorObjectHandleStatus::STATUS_CLOSED;
                             $handle->setStatus($closed);
                         }
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_FILE:
                 $object = new PhabricatorFile();
                 $files = $object->loadAllWhere('phid IN (%Ls)', $phids);
                 $files = mpull($files, null, 'getPHID');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($files[$phid])) {
                         $handle->setName('Unknown File');
                     } else {
                         $file = $files[$phid];
                         $handle->setName($file->getName());
                         $handle->setURI($file->getBestURI());
                         $handle->setComplete(true);
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_PROJ:
                 $object = new PhabricatorProject();
                 $projects = $object->loadAllWhere('phid IN (%Ls)', $phids);
                 $projects = mpull($projects, null, 'getPHID');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($projects[$phid])) {
                         $handle->setName('Unknown Project');
                     } else {
                         $project = $projects[$phid];
                         $handle->setName($project->getName());
                         $handle->setURI('/project/view/' . $project->getID() . '/');
                         $handle->setComplete(true);
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_REPO:
                 $object = new PhabricatorRepository();
                 $repositories = $object->loadAllWhere('phid in (%Ls)', $phids);
                 $repositories = mpull($repositories, null, 'getPHID');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($repositories[$phid])) {
                         $handle->setName('Unknown Repository');
                     } else {
                         $repository = $repositories[$phid];
                         $handle->setName($repository->getCallsign());
                         $handle->setURI('/diffusion/' . $repository->getCallsign() . '/');
                         $handle->setComplete(true);
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_OPKG:
                 $object = new PhabricatorOwnersPackage();
                 $packages = $object->loadAllWhere('phid in (%Ls)', $phids);
                 $packages = mpull($packages, null, 'getPHID');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($packages[$phid])) {
                         $handle->setName('Unknown Package');
                     } else {
                         $package = $packages[$phid];
                         $handle->setName($package->getName());
                         $handle->setURI('/owners/package/' . $package->getID() . '/');
                         $handle->setComplete(true);
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_APRJ:
                 $project_dao = new PhabricatorRepositoryArcanistProject();
                 $projects = $project_dao->loadAllWhere('phid IN (%Ls)', $phids);
                 $projects = mpull($projects, null, 'getPHID');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($projects[$phid])) {
                         $handle->setName('Unknown Arcanist Project');
                     } else {
                         $project = $projects[$phid];
                         $handle->setName($project->getName());
                         $handle->setComplete(true);
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             case PhabricatorPHIDConstants::PHID_TYPE_WIKI:
                 $document_dao = new PhrictionDocument();
                 $content_dao = new PhrictionContent();
                 $conn = $document_dao->establishConnection('r');
                 $documents = queryfx_all($conn, 'SELECT * FROM %T document JOIN %T content
           ON document.contentID = content.id
           WHERE document.phid IN (%Ls)', $document_dao->getTableName(), $content_dao->getTableName(), $phids);
                 $documents = ipull($documents, null, 'phid');
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setPHID($phid);
                     $handle->setType($type);
                     if (empty($documents[$phid])) {
                         $handle->setName('Unknown Document');
                     } else {
                         $info = $documents[$phid];
                         $handle->setName($info['title']);
                         $handle->setURI(PhrictionDocument::getSlugURI($info['slug']));
                         $handle->setComplete(true);
                     }
                     $handles[$phid] = $handle;
                 }
                 break;
             default:
                 $loader = null;
                 if (isset($external_loaders[$type])) {
                     $loader = $external_loaders[$type];
                 } else {
                     if (isset($external_loaders['*'])) {
                         $loader = $external_loaders['*'];
                     }
                 }
                 if ($loader) {
                     $object = newv($loader, array());
                     $handles += $object->loadHandles($phids);
                     break;
                 }
                 foreach ($phids as $phid) {
                     $handle = new PhabricatorObjectHandle();
                     $handle->setType($type);
                     $handle->setPHID($phid);
                     $handle->setName('Unknown Object');
                     $handle->setFullName('An Unknown Object');
                     $handles[$phid] = $handle;
                 }
                 break;
         }
     }
     return $handles;
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     if ($this->id) {
         $document = id(new PhrictionDocument())->load($this->id);
         if (!$document) {
             return new Aphront404Response();
         }
         $revert = $request->getInt('revert');
         if ($revert) {
             $content = id(new PhrictionContent())->loadOneWhere('documentID = %d AND version = %d', $document->getID(), $revert);
             if (!$content) {
                 return new Aphront404Response();
             }
         } else {
             $content = id(new PhrictionContent())->load($document->getContentID());
         }
     } else {
         $slug = $request->getStr('slug');
         $slug = PhabricatorSlug::normalize($slug);
         if (!$slug) {
             return new Aphront404Response();
         }
         $document = id(new PhrictionDocument())->loadOneWhere('slug = %s', $slug);
         if ($document) {
             $content = id(new PhrictionContent())->load($document->getContentID());
         } else {
             $document = new PhrictionDocument();
             $document->setSlug($slug);
             $content = new PhrictionContent();
             $content->setSlug($slug);
             $default_title = PhabricatorSlug::getDefaultTitle($slug);
             $content->setTitle($default_title);
         }
     }
     if ($request->getBool('nodraft')) {
         $draft = null;
         $draft_key = null;
     } else {
         if ($document->getPHID()) {
             $draft_key = $document->getPHID() . ':' . $content->getVersion();
         } else {
             $draft_key = 'phriction:' . $content->getSlug();
         }
         $draft = id(new PhabricatorDraft())->loadOneWhere('authorPHID = %s AND draftKey = %s', $user->getPHID(), $draft_key);
     }
     require_celerity_resource('phriction-document-css');
     $e_title = true;
     $errors = array();
     if ($request->isFormPost()) {
         $title = $request->getStr('title');
         if (!strlen($title)) {
             $e_title = 'Required';
             $errors[] = 'Document title is required.';
         } else {
             $e_title = null;
         }
         if (!count($errors)) {
             $editor = id(PhrictionDocumentEditor::newForSlug($document->getSlug()))->setUser($user)->setTitle($title)->setContent($request->getStr('content'))->setDescription($request->getStr('description'));
             $editor->save();
             if ($draft) {
                 $draft->delete();
             }
             $uri = PhrictionDocument::getSlugURI($document->getSlug());
             return id(new AphrontRedirectResponse())->setURI($uri);
         }
     }
     $error_view = null;
     if ($errors) {
         $error_view = id(new AphrontErrorView())->setTitle('Form Errors')->setErrors($errors);
     }
     if ($document->getID()) {
         $panel_header = 'Edit Phriction Document';
         $submit_button = 'Save Changes';
         $delete_button = phutil_render_tag('a', array('href' => '/phriction/delete/' . $document->getID() . '/', 'class' => 'grey button'), 'Delete Document');
     } else {
         $panel_header = 'Create New Phriction Document';
         $submit_button = 'Create Document';
         $delete_button = null;
     }
     $uri = $document->getSlug();
     $uri = PhrictionDocument::getSlugURI($uri);
     $uri = PhabricatorEnv::getProductionURI($uri);
     $remarkup_reference = phutil_render_tag('a', array('href' => PhabricatorEnv::getDoclink('article/Remarkup_Reference.html'), 'tabindex' => '-1', 'target' => '_blank'), 'Formatting Reference');
     $cancel_uri = PhrictionDocument::getSlugURI($document->getSlug());
     if ($draft && strlen($draft->getDraft()) && $draft->getDraft() != $content->getContent()) {
         $content_text = $draft->getDraft();
         $discard = phutil_render_tag('a', array('href' => $request->getRequestURI()->alter('nodraft', true)), 'discard this draft');
         $draft_note = new AphrontErrorView();
         $draft_note->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
         $draft_note->setTitle('Recovered Draft');
         $draft_note->appendChild('<p>Showing a saved draft of your edits, you can ' . $discard . '.</p>');
     } else {
         $content_text = $content->getContent();
         $draft_note = null;
     }
     $form = id(new AphrontFormView())->setUser($user)->setAction($request->getRequestURI()->getPath())->addHiddenInput('slug', $document->getSlug())->addHiddenInput('nodraft', $request->getBool('nodraft'))->appendChild(id(new AphrontFormTextControl())->setLabel('Title')->setValue($content->getTitle())->setError($e_title)->setName('title'))->appendChild(id(new AphrontFormStaticControl())->setLabel('URI')->setValue($uri))->appendChild(id(new AphrontFormTextAreaControl())->setLabel('Content')->setValue($content_text)->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)->setName('content')->setID('document-textarea')->setEnableDragAndDropFileUploads(true)->setCaption($remarkup_reference))->appendChild(id(new AphrontFormTextControl())->setLabel('Edit Notes')->setValue($content->getDescription())->setError(null)->setName('description'))->appendChild(id(new AphrontFormSubmitControl())->addCancelButton($cancel_uri)->setValue($submit_button));
     $panel = id(new AphrontPanelView())->setWidth(AphrontPanelView::WIDTH_WIDE)->setHeader($panel_header)->appendChild($form);
     if ($delete_button) {
         $panel->addButton($delete_button);
     }
     $preview_panel = '<div class="aphront-panel-preview aphront-panel-preview-wide">
     <div class="phriction-document-preview-header">
       Document Preview
     </div>
     <div id="document-preview">
       <div class="aphront-panel-preview-loading-text">
         Loading preview...
       </div>
     </div>
   </div>';
     Javelin::initBehavior('phriction-document-preview', array('preview' => 'document-preview', 'textarea' => 'document-textarea', 'uri' => '/phriction/preview/?draftkey=' . $draft_key));
     return $this->buildStandardPageResponse(array($draft_note, $error_view, $panel, $preview_panel), array('title' => 'Edit Document'));
 }
 private function renderDocumentChildren($slug)
 {
     $document_dao = new PhrictionDocument();
     $content_dao = new PhrictionContent();
     $conn = $document_dao->establishConnection('r');
     $limit = 250;
     $d_child = PhabricatorSlug::getDepth($slug) + 1;
     $d_grandchild = PhabricatorSlug::getDepth($slug) + 2;
     // Select children and grandchildren.
     $children = queryfx_all($conn, 'SELECT d.slug, d.depth, c.title FROM %T d JOIN %T c
     ON d.contentID = c.id
     WHERE d.slug LIKE %> AND d.depth IN (%d, %d)
       AND d.status IN (%Ld)
     ORDER BY d.depth, c.title LIMIT %d', $document_dao->getTableName(), $content_dao->getTableName(), $slug == '/' ? '' : $slug, $d_child, $d_grandchild, array(PhrictionDocumentStatus::STATUS_EXISTS, PhrictionDocumentStatus::STATUS_STUB), $limit);
     if (!$children) {
         return;
     }
     // We're going to render in one of three modes to try to accommodate
     // different information scales:
     //
     //  - If we found fewer than $limit rows, we know we have all the children
     //    and grandchildren and there aren't all that many. We can just render
     //    everything.
     //  - If we found $limit rows but the results included some grandchildren,
     //    we just throw them out and render only the children, as we know we
     //    have them all.
     //  - If we found $limit rows and the results have no grandchildren, we
     //    have a ton of children. Render them and then let the user know that
     //    this is not an exhaustive list.
     if (count($children) == $limit) {
         $more_children = true;
         foreach ($children as $child) {
             if ($child['depth'] == $d_grandchild) {
                 $more_children = false;
             }
         }
         $show_grandchildren = false;
     } else {
         $show_grandchildren = true;
         $more_children = false;
     }
     $grandchildren = array();
     foreach ($children as $key => $child) {
         if ($child['depth'] == $d_child) {
             continue;
         } else {
             unset($children[$key]);
             if ($show_grandchildren) {
                 $ancestors = PhabricatorSlug::getAncestry($child['slug']);
                 $grandchildren[end($ancestors)][] = $child;
             }
         }
     }
     // Fill in any missing children.
     $known_slugs = ipull($children, null, 'slug');
     foreach ($grandchildren as $slug => $ignored) {
         if (empty($known_slugs[$slug])) {
             $children[] = array('slug' => $slug, 'depth' => $d_child, 'title' => PhabricatorSlug::getDefaultTitle($slug), 'empty' => true);
         }
     }
     $children = isort($children, 'title');
     $list = array();
     foreach ($children as $child) {
         $list[] = hsprintf('<li>');
         $list[] = $this->renderChildDocumentLink($child);
         $grand = idx($grandchildren, $child['slug'], array());
         if ($grand) {
             $list[] = hsprintf('<ul>');
             foreach ($grand as $grandchild) {
                 $list[] = hsprintf('<li>');
                 $list[] = $this->renderChildDocumentLink($grandchild);
                 $list[] = hsprintf('</li>');
             }
             $list[] = hsprintf('</ul>');
         }
         $list[] = hsprintf('</li>');
     }
     if ($more_children) {
         $list[] = phutil_tag('li', array(), pht('More...'));
     }
     $content = array(phutil_tag('div', array('class' => 'phriction-children-header ' . 'sprite-gradient gradient-lightblue-header'), pht('Document Hierarchy')), phutil_tag('div', array('class' => 'phriction-children'), phutil_tag('ul', array(), $list)));
     return id(new PHUIDocumentView())->setOffset(true)->appendChild($content);
 }
 private function renderRevertButton(PhrictionContent $content, PhrictionContent $current)
 {
     $document_id = $content->getDocumentID();
     $version = $content->getVersion();
     if ($content->getChangeType() == PhrictionChangeType::CHANGE_DELETE) {
         // Don't show an edit/revert button for changes which deleted the content
         // since it's silly.
         return null;
     }
     if ($content->getID() == $current->getID()) {
         return phutil_render_tag('a', array('href' => '/phriction/edit/' . $document_id . '/', 'class' => 'button'), 'Edit Current Version');
     }
     return phutil_render_tag('a', array('href' => '/phriction/edit/' . $document_id . '/?revert=' . $version, 'class' => 'button'), 'Revert to Version ' . phutil_escape_html($version) . '...');
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     if ($this->id) {
         $document = id(new PhrictionDocument())->load($this->id);
         if (!$document) {
             return new Aphront404Response();
         }
         $revert = $request->getInt('revert');
         if ($revert) {
             $content = id(new PhrictionContent())->loadOneWhere('documentID = %d AND version = %d', $document->getID(), $revert);
             if (!$content) {
                 return new Aphront404Response();
             }
         } else {
             $content = id(new PhrictionContent())->load($document->getContentID());
         }
     } else {
         $slug = $request->getStr('slug');
         $slug = PhrictionDocument::normalizeSlug($slug);
         if (!$slug) {
             return new Aphront404Response();
         }
         $document = id(new PhrictionDocument())->loadOneWhere('slug = %s', $slug);
         if ($document) {
             $content = id(new PhrictionContent())->load($document->getContentID());
         } else {
             $document = new PhrictionDocument();
             $document->setSlug($slug);
             $content = new PhrictionContent();
             $content->setSlug($slug);
             $default_title = PhrictionDocument::getDefaultSlugTitle($slug);
             $content->setTitle($default_title);
         }
     }
     require_celerity_resource('phriction-document-css');
     $e_title = true;
     $errors = array();
     if ($request->isFormPost()) {
         $title = $request->getStr('title');
         if (!strlen($title)) {
             $e_title = 'Required';
             $errors[] = 'Document title is required.';
         } else {
             $e_title = null;
         }
         if (!count($errors)) {
             $editor = id(PhrictionDocumentEditor::newForSlug($document->getSlug()))->setUser($user)->setTitle($title)->setContent($request->getStr('content'))->setDescription($request->getStr('description'));
             $editor->save();
             $uri = PhrictionDocument::getSlugURI($document->getSlug());
             return id(new AphrontRedirectResponse())->setURI($uri);
         }
     }
     $error_view = null;
     if ($errors) {
         $error_view = id(new AphrontErrorView())->setTitle('Form Errors')->setErrors($errors);
     }
     if ($document->getID()) {
         $panel_header = 'Edit Phriction Document';
         $submit_button = 'Save Changes';
     } else {
         $panel_header = 'Create New Phriction Document';
         $submit_button = 'Create Document';
     }
     $uri = $document->getSlug();
     $uri = PhrictionDocument::getSlugURI($uri);
     $uri = PhabricatorEnv::getProductionURI($uri);
     $remarkup_reference = phutil_render_tag('a', array('href' => PhabricatorEnv::getDoclink('article/Remarkup_Reference.html')), 'Formatting Reference');
     $cancel_uri = PhrictionDocument::getSlugURI($document->getSlug());
     $form = id(new AphrontFormView())->setUser($user)->setAction($request->getRequestURI()->getPath())->addHiddenInput('slug', $document->getSlug())->appendChild(id(new AphrontFormTextControl())->setLabel('Title')->setValue($content->getTitle())->setError($e_title)->setName('title'))->appendChild(id(new AphrontFormTextControl())->setLabel('Description')->setValue($content->getDescription())->setError(null)->setName('description'))->appendChild(id(new AphrontFormStaticControl())->setLabel('URI')->setValue($uri))->appendChild(id(new AphrontFormTextAreaControl())->setLabel('Content')->setValue($content->getContent())->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)->setName('content')->setID('document-textarea')->setEnableDragAndDropFileUploads(true)->setCaption($remarkup_reference))->appendChild(id(new AphrontFormSubmitControl())->addCancelButton($cancel_uri)->setValue($submit_button));
     $panel = id(new AphrontPanelView())->setWidth(AphrontPanelView::WIDTH_WIDE)->setHeader($panel_header)->appendChild($form);
     $preview_panel = '<div class="aphront-panel-preview aphront-panel-preview-wide">
     <div class="phriction-document-preview-header">
       Document Preview
     </div>
     <div id="document-preview">
       <div class="aphront-panel-preview-loading-text">
         Loading preview...
       </div>
     </div>
   </div>';
     Javelin::initBehavior('phriction-document-preview', array('preview' => 'document-preview', 'textarea' => 'document-textarea', 'uri' => '/phriction/preview/'));
     return $this->buildStandardPageResponse(array($error_view, $panel, $preview_panel), array('title' => 'Edit Document'));
 }
 private function buildContentTemplate(PhrictionDocument $document, PhrictionContent $content)
 {
     $new_content = new PhrictionContent();
     $new_content->setSlug($document->getSlug());
     $new_content->setAuthorPHID($this->user->getPHID());
     $new_content->setChangeType(PhrictionChangeType::CHANGE_EDIT);
     $new_content->setTitle(coalesce($this->newTitle, $content->getTitle()));
     $new_content->setContent(coalesce($this->newContent, $content->getContent()));
     if (strlen($this->description)) {
         $new_content->setDescription($this->description);
     }
     return $new_content;
 }
 protected function buildJoinClause(AphrontDatabaseConnection $conn)
 {
     $join = '';
     if ($this->getOrderVector()->containsKey('updated')) {
         $content_dao = new PhrictionContent();
         $join = qsprintf($conn, 'JOIN %T c ON d.contentID = c.id', $content_dao->getTableName());
     }
     return $join;
 }
 private function buildPropertyListView(PhrictionDocument $document, PhrictionContent $content, $slug)
 {
     $viewer = $this->getRequest()->getUser();
     $view = id(new PHUIPropertyListView())->setUser($viewer)->setObject($document);
     $view->addProperty(pht('Last Author'), $viewer->renderHandle($content->getAuthorPHID()));
     return $view;
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $slug = $request->getStr('slug');
     $slug = PhrictionDocument::normalizeSlug($slug);
     if ($this->id) {
         $document = id(new PhrictionDocument())->load($this->id);
         if (!$document) {
             return new Aphront404Response();
         }
         $revert = $request->getInt('revert');
         if ($revert) {
             $content = id(new PhrictionContent())->loadOneWhere('documentID = %d AND version = %d', $document->getID(), $revert);
             if (!$content) {
                 return new Aphront404Response();
             }
         } else {
             $content = id(new PhrictionContent())->load($document->getContentID());
         }
     } else {
         if ($slug) {
             $document = id(new PhrictionDocument())->loadOneWhere('slug = %s', $slug);
             if ($document) {
                 $content = id(new PhrictionContent())->load($document->getContentID());
             } else {
                 $document = new PhrictionDocument();
                 $document->setSlug($slug);
                 $content = new PhrictionContent();
                 $content->setSlug($slug);
                 $default_title = PhrictionDocument::getDefaultSlugTitle($slug);
                 $content->setTitle($default_title);
             }
         } else {
             return new Aphront404Response();
         }
     }
     require_celerity_resource('phriction-document-css');
     $e_title = true;
     $errors = array();
     if ($request->isFormPost()) {
         $title = $request->getStr('title');
         if (!strlen($title)) {
             $e_title = 'Required';
             $errors[] = 'Document title is required.';
         } else {
             $e_title = null;
         }
         if (!count($errors)) {
             // TODO: This should all be transactional.
             $is_new = false;
             if (!$document->getID()) {
                 $is_new = true;
                 $document->save();
             }
             $new_content = new PhrictionContent();
             $new_content->setSlug($document->getSlug());
             $new_content->setTitle($title);
             $new_content->setDescription($request->getStr('description'));
             $new_content->setContent($request->getStr('content'));
             $new_content->setDocumentID($document->getID());
             $new_content->setVersion($content->getVersion() + 1);
             $new_content->setAuthorPHID($user->getPHID());
             $new_content->save();
             $document->setContentID($new_content->getID());
             $document->save();
             $document->attachContent($new_content);
             PhabricatorSearchPhrictionIndexer::indexDocument($document);
             id(new PhabricatorFeedStoryPublisher())->setRelatedPHIDs(array($document->getPHID(), $user->getPHID()))->setStoryAuthorPHID($user->getPHID())->setStoryTime(time())->setStoryType(PhabricatorFeedStoryTypeConstants::STORY_PHRICTION)->setStoryData(array('phid' => $document->getPHID(), 'action' => $is_new ? PhrictionActionConstants::ACTION_CREATE : PhrictionActionConstants::ACTION_EDIT, 'content' => phutil_utf8_shorten($new_content->getContent(), 140)))->publish();
             $uri = PhrictionDocument::getSlugURI($document->getSlug());
             return id(new AphrontRedirectResponse())->setURI($uri);
         }
     }
     $error_view = null;
     if ($errors) {
         $error_view = id(new AphrontErrorView())->setTitle('Form Errors')->setErrors($errors);
     }
     if ($document->getID()) {
         $panel_header = 'Edit Phriction Document';
         $submit_button = 'Save Changes';
     } else {
         $panel_header = 'Create New Phriction Document';
         $submit_button = 'Create Document';
     }
     $uri = $document->getSlug();
     $uri = PhrictionDocument::getSlugURI($uri);
     $uri = PhabricatorEnv::getProductionURI($uri);
     $remarkup_reference = phutil_render_tag('a', array('href' => PhabricatorEnv::getDoclink('article/Remarkup_Reference.html')), 'Formatting Reference');
     $cancel_uri = PhrictionDocument::getSlugURI($document->getSlug());
     $form = id(new AphrontFormView())->setUser($user)->setAction($request->getRequestURI()->getPath())->addHiddenInput('slug', $slug)->appendChild(id(new AphrontFormTextControl())->setLabel('Title')->setValue($content->getTitle())->setError($e_title)->setName('title'))->appendChild(id(new AphrontFormTextControl())->setLabel('Description')->setValue($content->getDescription())->setError(null)->setName('description'))->appendChild(id(new AphrontFormStaticControl())->setLabel('URI')->setValue($uri))->appendChild(id(new AphrontFormTextAreaControl())->setLabel('Content')->setValue($content->getContent())->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)->setName('content')->setID('document-textarea')->setCaption($remarkup_reference))->appendChild(id(new AphrontFormSubmitControl())->addCancelButton($cancel_uri)->setValue($submit_button));
     $panel = id(new AphrontPanelView())->setWidth(AphrontPanelView::WIDTH_WIDE)->setHeader($panel_header)->appendChild($form);
     $preview_panel = '<div class="aphront-panel-preview aphront-panel-preview-wide">
     <div class="phriction-document-preview-header">
       Document Preview
     </div>
     <div id="document-preview">
       <div class="aphront-panel-preview-loading-text">
         Loading preview...
       </div>
     </div>
   </div>';
     Javelin::initBehavior('phriction-document-preview', array('preview' => 'document-preview', 'textarea' => 'document-textarea', 'uri' => '/phriction/preview/'));
     return $this->buildStandardPageResponse(array($error_view, $panel, $preview_panel), array('title' => 'Edit Document'));
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $current_version = null;
     if ($this->id) {
         $document = id(new PhrictionDocumentQuery())->setViewer($user)->withIDs(array($this->id))->needContent(true)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne();
         if (!$document) {
             return new Aphront404Response();
         }
         $current_version = $document->getContent()->getVersion();
         $revert = $request->getInt('revert');
         if ($revert) {
             $content = id(new PhrictionContent())->loadOneWhere('documentID = %d AND version = %d', $document->getID(), $revert);
             if (!$content) {
                 return new Aphront404Response();
             }
         } else {
             $content = $document->getContent();
         }
     } else {
         $slug = $request->getStr('slug');
         $slug = PhabricatorSlug::normalize($slug);
         if (!$slug) {
             return new Aphront404Response();
         }
         $document = id(new PhrictionDocumentQuery())->setViewer($user)->withSlugs(array($slug))->needContent(true)->executeOne();
         if ($document) {
             $content = $document->getContent();
             $current_version = $content->getVersion();
         } else {
             if (PhrictionDocument::isProjectSlug($slug)) {
                 $project = id(new PhabricatorProjectQuery())->setViewer($user)->withPhrictionSlugs(array(PhrictionDocument::getProjectSlugIdentifier($slug)))->executeOne();
                 if (!$project) {
                     return new Aphront404Response();
                 }
             }
             $document = new PhrictionDocument();
             $document->setSlug($slug);
             $content = new PhrictionContent();
             $content->setSlug($slug);
             $default_title = PhabricatorSlug::getDefaultTitle($slug);
             $content->setTitle($default_title);
         }
     }
     if ($request->getBool('nodraft')) {
         $draft = null;
         $draft_key = null;
     } else {
         if ($document->getPHID()) {
             $draft_key = $document->getPHID() . ':' . $content->getVersion();
         } else {
             $draft_key = 'phriction:' . $content->getSlug();
         }
         $draft = id(new PhabricatorDraft())->loadOneWhere('authorPHID = %s AND draftKey = %s', $user->getPHID(), $draft_key);
     }
     require_celerity_resource('phriction-document-css');
     $e_title = true;
     $notes = null;
     $errors = array();
     if ($request->isFormPost()) {
         $overwrite = $request->getBool('overwrite');
         if (!$overwrite) {
             $edit_version = $request->getStr('contentVersion');
             if ($edit_version != $current_version) {
                 $dialog = $this->newDialog()->setTitle(pht('Edit Conflict!'))->appendParagraph(pht('Another user made changes to this document after you began ' . 'editing it. Do you want to overwrite their changes?'))->appendParagraph(pht('If you choose to overwrite their changes, you should review ' . 'the document edit history to see what you overwrote, and ' . 'then make another edit to merge the changes if necessary.'))->addSubmitButton(pht('Overwrite Changes'))->addCancelButton($request->getRequestURI());
                 $dialog->addHiddenInput('overwrite', 'true');
                 foreach ($request->getPassthroughRequestData() as $key => $value) {
                     $dialog->addHiddenInput($key, $value);
                 }
                 return $dialog;
             }
         }
         $title = $request->getStr('title');
         $notes = $request->getStr('description');
         if (!strlen($title)) {
             $e_title = pht('Required');
             $errors[] = pht('Document title is required.');
         } else {
             $e_title = null;
         }
         if ($document->getID()) {
             if ($content->getTitle() == $title && $content->getContent() == $request->getStr('content')) {
                 $dialog = new AphrontDialogView();
                 $dialog->setUser($user);
                 $dialog->setTitle(pht('No Edits'));
                 $dialog->appendChild(phutil_tag('p', array(), pht('You did not make any changes to the document.')));
                 $dialog->addCancelButton($request->getRequestURI());
                 return id(new AphrontDialogResponse())->setDialog($dialog);
             }
         } else {
             if (!strlen($request->getStr('content'))) {
                 // We trigger this only for new pages. For existing pages, deleting
                 // all the content counts as deleting the page.
                 $dialog = new AphrontDialogView();
                 $dialog->setUser($user);
                 $dialog->setTitle(pht('Empty Page'));
                 $dialog->appendChild(phutil_tag('p', array(), pht('You can not create an empty document.')));
                 $dialog->addCancelButton($request->getRequestURI());
                 return id(new AphrontDialogResponse())->setDialog($dialog);
             }
         }
         if (!count($errors)) {
             $editor = id(PhrictionDocumentEditor::newForSlug($document->getSlug()))->setActor($user)->setTitle($title)->setContent($request->getStr('content'))->setDescription($notes);
             $editor->save();
             if ($draft) {
                 $draft->delete();
             }
             $uri = PhrictionDocument::getSlugURI($document->getSlug());
             return id(new AphrontRedirectResponse())->setURI($uri);
         }
     }
     if ($document->getID()) {
         $panel_header = pht('Edit Phriction Document');
         $submit_button = pht('Save Changes');
     } else {
         $panel_header = pht('Create New Phriction Document');
         $submit_button = pht('Create Document');
     }
     $uri = $document->getSlug();
     $uri = PhrictionDocument::getSlugURI($uri);
     $uri = PhabricatorEnv::getProductionURI($uri);
     $cancel_uri = PhrictionDocument::getSlugURI($document->getSlug());
     if ($draft && strlen($draft->getDraft()) && $draft->getDraft() != $content->getContent()) {
         $content_text = $draft->getDraft();
         $discard = phutil_tag('a', array('href' => $request->getRequestURI()->alter('nodraft', true)), pht('discard this draft'));
         $draft_note = new AphrontErrorView();
         $draft_note->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
         $draft_note->setTitle('Recovered Draft');
         $draft_note->appendChild(hsprintf('<p>Showing a saved draft of your edits, you can %s.</p>', $discard));
     } else {
         $content_text = $content->getContent();
         $draft_note = null;
     }
     $form = id(new AphrontFormView())->setUser($user)->setWorkflow(true)->setAction($request->getRequestURI()->getPath())->addHiddenInput('slug', $document->getSlug())->addHiddenInput('nodraft', $request->getBool('nodraft'))->addHiddenInput('contentVersion', $current_version)->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Title'))->setValue($content->getTitle())->setError($e_title)->setName('title'))->appendChild(id(new AphrontFormStaticControl())->setLabel(pht('URI'))->setValue($uri))->appendChild(id(new PhabricatorRemarkupControl())->setLabel(pht('Content'))->setValue($content_text)->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)->setName('content')->setID('document-textarea')->setUser($user))->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Edit Notes'))->setValue($notes)->setError(null)->setName('description'))->appendChild(id(new AphrontFormSubmitControl())->addCancelButton($cancel_uri)->setValue($submit_button));
     $form_box = id(new PHUIObjectBoxView())->setHeaderText(pht('Edit Document'))->setFormErrors($errors)->setForm($form);
     $preview = id(new PHUIRemarkupPreviewPanel())->setHeader(pht('Document Preview'))->setPreviewURI('/phriction/preview/')->setControlID('document-textarea')->setSkin('document');
     $crumbs = $this->buildApplicationCrumbs();
     if ($document->getID()) {
         $crumbs->addTextCrumb($content->getTitle(), PhrictionDocument::getSlugURI($document->getSlug()));
         $crumbs->addTextCrumb(pht('Edit'));
     } else {
         $crumbs->addTextCrumb(pht('Create'));
     }
     return $this->buildApplicationPage(array($crumbs, $draft_note, $form_box, $preview), array('title' => pht('Edit Document')));
 }
 protected function getToc(PhrictionContent $content)
 {
     $toc = $content->getRenderedTableOfContents();
     if ($toc) {
         $toc = phutil_tag_div('phui-document-toc-content', array(phutil_tag_div('phui-document-toc-header', pht('Contents')), $toc));
     }
     return $toc;
 }