public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $e_name = null;
     $e_bloggers = null;
     $errors = array();
     if ($this->isBlogEdit()) {
         $blogs = id(new PhameBlogQuery())->withPHIDs(array($this->getBlogPHID()))->execute();
         $blog = reset($blogs);
         if (empty($blog)) {
             return new Aphront404Response();
         }
         $bloggers = $blog->loadBloggers()->getBloggers();
         // TODO -- make this check use a policy
         if (!isset($bloggers[$user->getPHID()]) && !$user->isAdmin()) {
             return new Aphront403Response();
         }
         $blogger_tokens = mpull($bloggers, 'getFullName', 'getPHID');
         $submit_button = 'Save Changes';
         $delete_button = javelin_render_tag('a', array('href' => $blog->getDeleteURI(), 'class' => 'grey button', 'sigil' => 'workflow'), 'Delete Blog');
         $page_title = 'Edit Blog';
     } else {
         $blog = id(new PhameBlog())->setCreatorPHID($user->getPHID());
         $blogger_tokens = array($user->getPHID() => $user->getFullName());
         $submit_button = 'Create Blog';
         $delete_button = null;
         $page_title = 'Create Blog';
     }
     if ($request->isFormPost()) {
         $saved = true;
         $name = $request->getStr('name');
         $description = $request->getStr('description');
         $blogger_arr = $request->getArr('bloggers');
         if (empty($blogger_arr)) {
             $error = 'Bloggers must be nonempty.';
             if ($this->isBlogEdit()) {
                 $error .= ' To delete the blog, use the delete button.';
             } else {
                 $error .= ' A blog cannot exist without bloggers.';
             }
             $e_bloggers = 'Required';
             $errors[] = $error;
         }
         $new_bloggers = array_values($blogger_arr);
         if ($this->isBlogEdit()) {
             $old_bloggers = array_keys($blogger_tokens);
         } else {
             $old_bloggers = array();
         }
         if (empty($name)) {
             $errors[] = 'Name must be nonempty.';
             $e_name = 'Required';
         }
         $blog->setName($name);
         $blog->setDescription($description);
         if (empty($errors)) {
             $blog->save();
             $add_phids = $new_bloggers;
             $rem_phids = array_diff($old_bloggers, $new_bloggers);
             $editor = new PhabricatorEdgeEditor();
             $edge_type = PhabricatorEdgeConfig::TYPE_BLOG_HAS_BLOGGER;
             $editor->setUser($user);
             foreach ($add_phids as $phid) {
                 $editor->addEdge($blog->getPHID(), $edge_type, $phid);
             }
             foreach ($rem_phids as $phid) {
                 $editor->removeEdge($blog->getPHID(), $edge_type, $phid);
             }
             $editor->save();
         } else {
             $saved = false;
         }
         if ($saved) {
             $uri = new PhutilURI($blog->getViewURI());
             $uri->setQueryParam('new', true);
             return id(new AphrontRedirectResponse())->setURI($uri);
         }
     }
     $panel = new AphrontPanelView();
     $panel->setHeader($page_title);
     $panel->setWidth(AphrontPanelView::WIDTH_FULL);
     if ($delete_button) {
         $panel->addButton($delete_button);
     }
     $remarkup_reference = phutil_render_tag('a', array('href' => PhabricatorEnv::getDoclink('article/Remarkup_Reference.html'), 'tabindex' => '-1', 'target' => '_blank'), 'Formatting Reference');
     $form = id(new AphrontFormView())->setUser($user)->appendChild(id(new AphrontFormTextControl())->setLabel('Name')->setName('name')->setValue($blog->getName())->setID('blog-name')->setError($e_name))->appendChild(id(new AphrontFormTextAreaControl())->setLabel('Description')->setName('description')->setValue($blog->getDescription())->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)->setID('blog-description')->setCaption($remarkup_reference))->appendChild(id(new AphrontFormTokenizerControl())->setLabel('Bloggers')->setName('bloggers')->setValue($blogger_tokens)->setUser($user)->setDatasource('/typeahead/common/users/')->setError($e_bloggers))->appendChild(id(new AphrontFormSubmitControl())->addCancelButton('/phame/blog/')->setValue($submit_button));
     $panel->appendChild($form);
     if ($errors) {
         $error_view = id(new AphrontErrorView())->setTitle('Errors saving blog.')->setErrors($errors);
     } else {
         $error_view = null;
     }
     $this->setShowSideNav(true);
     return $this->buildStandardPageResponse(array($error_view, $panel), array('title' => $page_title));
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $e_phame_title = null;
     $e_title = null;
     $errors = array();
     if ($this->isPostEdit()) {
         $posts = id(new PhamePostQuery())->withPHIDs(array($this->getPostPHID()))->execute();
         $post = reset($posts);
         if (empty($post)) {
             return new Aphront404Response();
         }
         if ($post->getBloggerPHID() != $user->getPHID()) {
             return new Aphront403Response();
         }
         $post_noun = ucfirst($post->getHumanName());
         $cancel_uri = $post->getViewURI($user->getUsername());
         $submit_button = 'Save Changes';
         $delete_button = javelin_render_tag('a', array('href' => $post->getDeleteURI(), 'class' => 'grey button', 'sigil' => 'workflow'), 'Delete ' . $post_noun);
         $page_title = 'Edit ' . $post_noun;
     } else {
         $post = id(new PhamePost())->setBloggerPHID($user->getPHID())->setVisibility(PhamePost::VISIBILITY_DRAFT);
         $cancel_uri = '/phame/draft/';
         $submit_button = 'Create Draft';
         $delete_button = null;
         $page_title = 'Create Draft';
     }
     $this->setPost($post);
     $this->loadEdgesAndBlogs();
     if ($request->isFormPost()) {
         $saved = true;
         $visibility = $request->getInt('visibility');
         $comments = $request->getStr('comments_widget');
         $data = array('comments_widget' => $comments);
         $phame_title = $request->getStr('phame_title');
         $phame_title = PhabricatorSlug::normalize($phame_title);
         $title = $request->getStr('title');
         $post->setTitle($title);
         $post->setPhameTitle($phame_title);
         $post->setBody($request->getStr('body'));
         $post->setVisibility($visibility);
         $post->setConfigData($data);
         // only publish once...!
         if ($visibility == PhamePost::VISIBILITY_PUBLISHED) {
             if (!$post->getDatePublished()) {
                 $post->setDatePublished(time());
             }
             // this is basically a cast of null to 0 if its a new post
         } else {
             if (!$post->getDatePublished()) {
                 $post->setDatePublished(0);
             }
         }
         if ($phame_title == '/') {
             $errors[] = 'Phame title must be nonempty.';
             $e_phame_title = 'Required';
         }
         if (empty($title)) {
             $errors[] = 'Title must be nonempty.';
             $e_title = 'Required';
         }
         $blogs_published = array_keys($this->getPostBlogs());
         $blogs_to_publish = array();
         $blogs_to_depublish = array();
         if ($visibility == PhamePost::VISIBILITY_PUBLISHED) {
             $blogs_arr = $request->getArr('blogs');
             $blogs_to_publish = array_values($blogs_arr);
             $blogs_to_depublish = array_diff($blogs_published, $blogs_to_publish);
         } else {
             $blogs_to_depublish = $blogs_published;
         }
         if (empty($errors)) {
             try {
                 $post->save();
                 $editor = new PhabricatorEdgeEditor();
                 $edge_type = PhabricatorEdgeConfig::TYPE_POST_HAS_BLOG;
                 $editor->setUser($user);
                 foreach ($blogs_to_publish as $phid) {
                     $editor->addEdge($post->getPHID(), $edge_type, $phid);
                 }
                 foreach ($blogs_to_depublish as $phid) {
                     $editor->removeEdge($post->getPHID(), $edge_type, $phid);
                 }
                 $editor->save();
             } catch (AphrontQueryDuplicateKeyException $e) {
                 $saved = false;
                 $e_phame_title = 'Not Unique';
                 $errors[] = 'Another post already uses this slug. ' . 'Each post must have a unique slug.';
             }
         } else {
             $saved = false;
         }
         if ($saved) {
             $uri = new PhutilURI($post->getViewURI($user->getUsername()));
             $uri->setQueryParam('saved', true);
             return id(new AphrontRedirectResponse())->setURI($uri);
         }
     }
     $panel = new AphrontPanelView();
     $panel->setHeader($page_title);
     $panel->setWidth(AphrontPanelView::WIDTH_FULL);
     if ($delete_button) {
         $panel->addButton($delete_button);
     }
     $form = id(new AphrontFormView())->setUser($user)->appendChild(id(new AphrontFormTextControl())->setLabel('Title')->setName('title')->setValue($post->getTitle())->setID('post-title')->setError($e_title))->appendChild(id(new AphrontFormTextControl())->setLabel('Phame Title')->setName('phame_title')->setValue(rtrim($post->getPhameTitle(), '/'))->setID('post-phame-title')->setCaption('Up to 64 alphanumeric characters ' . 'with underscores for spaces. ' . 'Formatting is enforced.')->setError($e_phame_title))->appendChild(id(new PhabricatorRemarkupControl())->setLabel('Body')->setName('body')->setValue($post->getBody())->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)->setID('post-body'))->appendChild(id(new AphrontFormSelectControl())->setLabel('Visibility')->setName('visibility')->setValue($post->getVisibility())->setOptions(PhamePost::getVisibilityOptionsForSelect())->setID('post-visibility'))->appendChild($this->getBlogCheckboxControl($post))->appendChild(id(new AphrontFormSelectControl())->setLabel('Comments Widget')->setName('comments_widget')->setvalue($post->getCommentsWidget())->setOptions($post->getCommentsWidgetOptionsForSelect()))->appendChild(id(new AphrontFormSubmitControl())->addCancelButton($cancel_uri)->setValue($submit_button));
     $panel->appendChild($form);
     $preview_panel = '<div class="aphront-panel-preview ">
      <div class="phame-post-preview-header">
        Post Preview
      </div>
      <div id="post-preview">
        <div class="aphront-panel-preview-loading-text">
          Loading preview...
        </div>
      </div>
    </div>';
     Javelin::initBehavior('phame-post-preview', array('preview' => 'post-preview', 'body' => 'post-body', 'title' => 'post-title', 'phame_title' => 'post-phame-title', 'uri' => '/phame/post/preview/'));
     $visibility_data = array('select_id' => 'post-visibility', 'current' => $post->getVisibility(), 'published' => PhamePost::VISIBILITY_PUBLISHED, 'draft' => PhamePost::VISIBILITY_DRAFT, 'change_uri' => $post->getChangeVisibilityURI());
     $blogs_data = array('checkbox_id' => 'post-blogs', 'have_published' => (bool) count($this->getPostBlogs()));
     Javelin::initBehavior('phame-post-blogs', array('blogs' => $blogs_data, 'visibility' => $visibility_data));
     if ($errors) {
         $error_view = id(new AphrontErrorView())->setTitle('Errors saving post.')->setErrors($errors);
     } else {
         $error_view = null;
     }
     $this->setShowSideNav(true);
     return $this->buildStandardPageResponse(array($error_view, $panel, $preview_panel), array('title' => $page_title));
 }
 public function applyTransactions(array $transactions)
 {
     assert_instances_of($transactions, 'PhabricatorProjectTransaction');
     if (!$this->user) {
         throw new Exception('Call setUser() before save()!');
     }
     $user = $this->user;
     $project = $this->project;
     $is_new = !$project->getID();
     if ($is_new) {
         $project->setAuthorPHID($user->getPHID());
     }
     foreach ($transactions as $key => $xaction) {
         $this->setTransactionOldValue($project, $xaction);
         if (!$this->transactionHasEffect($xaction)) {
             unset($transactions[$key]);
             continue;
         }
     }
     if (!$is_new) {
         // You must be able to view a project in order to edit it in any capacity.
         PhabricatorPolicyFilter::requireCapability($user, $project, PhabricatorPolicyCapability::CAN_VIEW);
         $need_edit = false;
         $need_join = false;
         foreach ($transactions as $key => $xaction) {
             if ($this->getTransactionRequiresEditCapability($xaction)) {
                 $need_edit = true;
             }
             if ($this->getTransactionRequiresJoinCapability($xaction)) {
                 $need_join = true;
             }
         }
         if ($need_edit) {
             PhabricatorPolicyFilter::requireCapability($user, $project, PhabricatorPolicyCapability::CAN_EDIT);
         }
         if ($need_join) {
             PhabricatorPolicyFilter::requireCapability($user, $project, PhabricatorPolicyCapability::CAN_JOIN);
         }
     }
     if (!$transactions) {
         return $this;
     }
     foreach ($transactions as $xaction) {
         $this->applyTransactionEffect($project, $xaction);
     }
     try {
         $project->openTransaction();
         $project->save();
         $edge_type = PhabricatorEdgeConfig::TYPE_PROJ_MEMBER;
         $editor = new PhabricatorEdgeEditor();
         $editor->setUser($this->user);
         foreach ($this->remEdges as $phid) {
             $editor->removeEdge($project->getPHID(), $edge_type, $phid);
         }
         foreach ($this->addEdges as $phid) {
             $editor->addEdge($project->getPHID(), $edge_type, $phid);
         }
         $editor->save();
         foreach ($transactions as $xaction) {
             $xaction->setAuthorPHID($user->getPHID());
             $xaction->setProjectID($project->getID());
             $xaction->save();
         }
         $project->saveTransaction();
         foreach ($transactions as $xaction) {
             $this->publishTransactionStory($project, $xaction);
         }
     } catch (AphrontQueryDuplicateKeyException $ex) {
         // We already validated the slug, but might race. Try again to see if
         // that's the issue. If it is, we'll throw a more specific exception. If
         // not, throw the original exception.
         $this->validateName($project);
         throw $ex;
     }
     // TODO: If we rename a project, we should move its Phriction page. Do
     // that once Phriction supports document moves.
     return $this;
 }