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; }