diff --git a/src/applications/phame/controller/blog/PhameBlogEditController.php b/src/applications/phame/controller/blog/PhameBlogEditController.php index 659f33ae3d..b59e5e01a2 100644 --- a/src/applications/phame/controller/blog/PhameBlogEditController.php +++ b/src/applications/phame/controller/blog/PhameBlogEditController.php @@ -1,209 +1,223 @@ getViewer(); $id = $request->getURIData('id'); if ($id) { $blog = id(new PhameBlogQuery()) ->setViewer($viewer) ->withIDs(array($id)) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_EDIT, )) ->executeOne(); if (!$blog) { return new Aphront404Response(); } $submit_button = pht('Save Changes'); $page_title = pht('Edit Blog'); $cancel_uri = $this->getApplicationURI('blog/view/'.$blog->getID().'/'); $v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs( $blog->getPHID(), PhabricatorProjectObjectHasProjectEdgeType::EDGECONST); $v_projects = array_reverse($v_projects); + $v_cc = PhabricatorSubscribersQuery::loadSubscribersForPHID( + $blog->getPHID()); } else { $this->requireApplicationCapability( PhameBlogCreateCapability::CAPABILITY); $blog = PhameBlog::initializeNewBlog($viewer); $submit_button = pht('Create Blog'); $page_title = pht('Create Blog'); $cancel_uri = $this->getApplicationURI(); $v_projects = array(); + $v_cc = array(); } - $name = $blog->getName(); - $description = $blog->getDescription(); + $name = $blog->getName(); + $description = $blog->getDescription(); $custom_domain = $blog->getDomain(); - $skin = $blog->getSkin(); - $can_view = $blog->getViewPolicy(); - $can_edit = $blog->getEditPolicy(); - $can_join = $blog->getJoinPolicy(); + $skin = $blog->getSkin(); + $can_view = $blog->getViewPolicy(); + $can_edit = $blog->getEditPolicy(); + $can_join = $blog->getJoinPolicy(); $e_name = true; $e_custom_domain = null; $e_view_policy = null; $validation_exception = null; if ($request->isFormPost()) { - $name = $request->getStr('name'); - $description = $request->getStr('description'); + $name = $request->getStr('name'); + $description = $request->getStr('description'); $custom_domain = nonempty($request->getStr('custom_domain'), null); - $skin = $request->getStr('skin'); - $can_view = $request->getStr('can_view'); - $can_edit = $request->getStr('can_edit'); - $can_join = $request->getStr('can_join'); - $v_projects = $request->getArr('projects'); + $skin = $request->getStr('skin'); + $can_view = $request->getStr('can_view'); + $can_edit = $request->getStr('can_edit'); + $can_join = $request->getStr('can_join'); + $v_projects = $request->getArr('projects'); + $v_cc = $request->getArr('cc'); $xactions = array( id(new PhameBlogTransaction()) ->setTransactionType(PhameBlogTransaction::TYPE_NAME) ->setNewValue($name), id(new PhameBlogTransaction()) ->setTransactionType(PhameBlogTransaction::TYPE_DESCRIPTION) ->setNewValue($description), id(new PhameBlogTransaction()) ->setTransactionType(PhameBlogTransaction::TYPE_DOMAIN) ->setNewValue($custom_domain), id(new PhameBlogTransaction()) ->setTransactionType(PhameBlogTransaction::TYPE_SKIN) ->setNewValue($skin), id(new PhameBlogTransaction()) ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY) ->setNewValue($can_view), id(new PhameBlogTransaction()) ->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY) ->setNewValue($can_edit), id(new PhameBlogTransaction()) ->setTransactionType(PhabricatorTransactions::TYPE_JOIN_POLICY) ->setNewValue($can_join), + id(new PhameBlogTransaction()) + ->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS) + ->setNewValue(array('=' => $v_cc)), ); $proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST; $xactions[] = id(new PhameBlogTransaction()) ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) ->setMetadataValue('edge:type', $proj_edge_type) ->setNewValue(array('=' => array_fuse($v_projects))); $editor = id(new PhameBlogEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true); try { $editor->applyTransactions($blog, $xactions); return id(new AphrontRedirectResponse()) ->setURI($this->getApplicationURI('blog/view/'.$blog->getID().'/')); } catch (PhabricatorApplicationTransactionValidationException $ex) { $validation_exception = $ex; $e_name = $validation_exception->getShortMessage( PhameBlogTransaction::TYPE_NAME); $e_custom_domain = $validation_exception->getShortMessage( PhameBlogTransaction::TYPE_DOMAIN); $e_view_policy = $validation_exception->getShortMessage( PhabricatorTransactions::TYPE_VIEW_POLICY); } } $policies = id(new PhabricatorPolicyQuery()) ->setViewer($viewer) ->setObject($blog) ->execute(); $skins = PhameSkinSpecification::loadAllSkinSpecifications(); $skins = mpull($skins, 'getName'); $form = id(new AphrontFormView()) ->setUser($viewer) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Name')) ->setName('name') ->setValue($name) ->setID('blog-name') ->setError($e_name)) ->appendChild( id(new PhabricatorRemarkupControl()) ->setUser($viewer) ->setLabel(pht('Description')) ->setName('description') ->setValue($description) ->setID('blog-description') ->setUser($viewer) ->setDisableMacros(true)) + ->appendControl( + id(new AphrontFormTokenizerControl()) + ->setLabel(pht('Subscribers')) + ->setName('cc') + ->setValue($v_cc) + ->setUser($viewer) + ->setDatasource(new PhabricatorMetaMTAMailableDatasource())) ->appendChild( id(new AphrontFormPolicyControl()) ->setUser($viewer) ->setCapability(PhabricatorPolicyCapability::CAN_VIEW) ->setPolicyObject($blog) ->setPolicies($policies) ->setError($e_view_policy) ->setValue($can_view) ->setName('can_view')) ->appendChild( id(new AphrontFormPolicyControl()) ->setUser($viewer) ->setCapability(PhabricatorPolicyCapability::CAN_EDIT) ->setPolicyObject($blog) ->setPolicies($policies) ->setValue($can_edit) ->setName('can_edit')) ->appendChild( id(new AphrontFormPolicyControl()) ->setUser($viewer) ->setCapability(PhabricatorPolicyCapability::CAN_JOIN) ->setPolicyObject($blog) ->setPolicies($policies) ->setValue($can_join) ->setName('can_join')) ->appendControl( id(new AphrontFormTokenizerControl()) ->setLabel(pht('Projects')) ->setName('projects') ->setValue($v_projects) ->setDatasource(new PhabricatorProjectDatasource())) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Custom Domain')) ->setName('custom_domain') ->setValue($custom_domain) ->setCaption( pht('Must include at least one dot (.), e.g. %s', 'blog.example.com')) ->setError($e_custom_domain)) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel(pht('Skin')) ->setName('skin') ->setValue($skin) ->setOptions($skins)) ->appendChild( id(new AphrontFormSubmitControl()) ->addCancelButton($cancel_uri) ->setValue($submit_button)); $form_box = id(new PHUIObjectBoxView()) ->setHeaderText($page_title) ->setValidationException($validation_exception) ->setForm($form); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Blogs'), $this->getApplicationURI('blog/')); $crumbs->addTextCrumb($page_title, $this->getApplicationURI('blog/new')); return $this->newPage() ->setTitle($page_title) ->setCrumbs($crumbs) ->appendChild( array( $form_box, )); } } diff --git a/src/applications/phame/controller/post/PhamePostEditController.php b/src/applications/phame/controller/post/PhamePostEditController.php index 44368b3207..99e6df390e 100644 --- a/src/applications/phame/controller/post/PhamePostEditController.php +++ b/src/applications/phame/controller/post/PhamePostEditController.php @@ -1,217 +1,232 @@ getViewer(); $id = $request->getURIData('id'); if ($id) { $post = id(new PhamePostQuery()) ->setViewer($viewer) ->withIDs(array($id)) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_EDIT, )) ->executeOne(); if (!$post) { return new Aphront404Response(); } $cancel_uri = $this->getApplicationURI('/post/view/'.$id.'/'); $submit_button = pht('Save Changes'); $page_title = pht('Edit Post'); $v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs( $post->getPHID(), PhabricatorProjectObjectHasProjectEdgeType::EDGECONST); $v_projects = array_reverse($v_projects); + $v_cc = PhabricatorSubscribersQuery::loadSubscribersForPHID( + $post->getPHID()); } else { $blog = id(new PhameBlogQuery()) ->setViewer($viewer) ->withIDs(array($request->getInt('blog'))) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_JOIN, )) ->executeOne(); if (!$blog) { return new Aphront404Response(); } $v_projects = array(); + $v_cc = array(); $post = PhamePost::initializePost($viewer, $blog); $cancel_uri = $this->getApplicationURI('/blog/view/'.$blog->getID().'/'); $submit_button = pht('Create Post'); $page_title = pht('Create Post'); } $title = $post->getTitle(); $phame_title = $post->getPhameTitle(); $body = $post->getBody(); $comments_widget = $post->getCommentsWidget(); $visibility = $post->getVisibility(); $e_title = true; $e_phame_title = true; $validation_exception = null; if ($request->isFormPost()) { $title = $request->getStr('title'); $phame_title = $request->getStr('phame_title'); $phame_title = PhabricatorSlug::normalize($phame_title); $body = $request->getStr('body'); $comments_widget = $request->getStr('comments_widget'); $v_projects = $request->getArr('projects'); + $v_cc = $request->getArr('cc'); $visibility = $request->getInt('visibility'); $xactions = array( id(new PhamePostTransaction()) ->setTransactionType(PhamePostTransaction::TYPE_TITLE) ->setNewValue($title), id(new PhamePostTransaction()) ->setTransactionType(PhamePostTransaction::TYPE_PHAME_TITLE) ->setNewValue($phame_title), id(new PhamePostTransaction()) ->setTransactionType(PhamePostTransaction::TYPE_BODY) ->setNewValue($body), id(new PhamePostTransaction()) ->setTransactionType(PhamePostTransaction::TYPE_VISIBILITY) ->setNewValue($visibility), id(new PhamePostTransaction()) ->setTransactionType(PhamePostTransaction::TYPE_COMMENTS_WIDGET) ->setNewValue($comments_widget), + id(new PhamePostTransaction()) + ->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS) + ->setNewValue(array('=' => $v_cc)), + ); $proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST; $xactions[] = id(new PhamePostTransaction()) ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) ->setMetadataValue('edge:type', $proj_edge_type) ->setNewValue(array('=' => array_fuse($v_projects))); $editor = id(new PhamePostEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true); try { $editor->applyTransactions($post, $xactions); $uri = $this->getApplicationURI('/post/view/'.$post->getID().'/'); return id(new AphrontRedirectResponse())->setURI($uri); } catch (PhabricatorApplicationTransactionValidationException $ex) { $validation_exception = $ex; $e_title = $validation_exception->getShortMessage( PhamePostTransaction::TYPE_TITLE); $e_phame_title = $validation_exception->getShortMessage( PhamePostTransaction::TYPE_PHAME_TITLE); } } $handle = id(new PhabricatorHandleQuery()) ->setViewer($viewer) ->withPHIDs(array($post->getBlogPHID())) ->executeOne(); $form = id(new AphrontFormView()) ->setUser($viewer) ->addHiddenInput('blog', $request->getInt('blog')) ->appendChild( id(new AphrontFormMarkupControl()) ->setLabel(pht('Blog')) ->setValue($handle->renderLink())) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Title')) ->setName('title') ->setValue($title) ->setID('post-title') ->setError($e_title)) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Phame Title')) ->setName('phame_title') ->setValue(rtrim($phame_title, '/')) ->setID('post-phame-title') ->setCaption(pht('Up to 64 alphanumeric characters '. 'with underscores for spaces. '. 'Formatting is enforced.')) ->setError($e_phame_title)) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel(pht('Visibility')) ->setName('visibility') ->setvalue($visibility) ->setOptions(PhameConstants::getPhamePostStatusMap())) ->appendChild( id(new PhabricatorRemarkupControl()) ->setLabel(pht('Body')) ->setName('body') ->setValue($body) ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL) ->setID('post-body') ->setUser($viewer) ->setDisableMacros(true)) + ->appendControl( + id(new AphrontFormTokenizerControl()) + ->setLabel(pht('Subscribers')) + ->setName('cc') + ->setValue($v_cc) + ->setUser($viewer) + ->setDatasource(new PhabricatorMetaMTAMailableDatasource())) ->appendControl( id(new AphrontFormTokenizerControl()) ->setLabel(pht('Projects')) ->setName('projects') ->setValue($v_projects) ->setDatasource(new PhabricatorProjectDatasource())) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel(pht('Comments Widget')) ->setName('comments_widget') ->setvalue($comments_widget) ->setOptions($post->getCommentsWidgetOptionsForSelect())) ->appendChild( id(new AphrontFormSubmitControl()) ->addCancelButton($cancel_uri) ->setValue($submit_button)); $header = id(new PHUIHeaderView()) ->setHeader(pht('%s (Post Preview)', $title)); $container = id(new PHUIBoxView()) ->setID('post-preview'); $document = id(new PHUIDocumentViewPro()) ->setHeader($header) ->appendChild($container); $preview_panel = id(new PHUIObjectBoxView()) ->appendChild($document); Javelin::initBehavior( 'phame-post-preview', array( 'preview' => 'post-preview', 'body' => 'post-body', 'title' => 'post-title', 'phame_title' => 'post-phame-title', 'uri' => '/phame/post/preview/', )); $form_box = id(new PHUIObjectBoxView()) ->setHeaderText($page_title) ->setValidationException($validation_exception) ->setForm($form); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb( $page_title, $this->getApplicationURI('/post/view/'.$id.'/')); return $this->newPage() ->setTitle($page_title) ->setCrumbs($crumbs) ->appendChild( array( $form_box, $preview_panel, )); } } diff --git a/src/applications/phame/controller/post/PhamePostPublishController.php b/src/applications/phame/controller/post/PhamePostPublishController.php index 0d612d193e..9b593b1313 100644 --- a/src/applications/phame/controller/post/PhamePostPublishController.php +++ b/src/applications/phame/controller/post/PhamePostPublishController.php @@ -1,90 +1,84 @@ getViewer(); $id = $request->getURIData('id'); $post = id(new PhamePostQuery()) ->setViewer($viewer) ->withIDs(array($id)) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_EDIT, )) ->executeOne(); if (!$post) { return new Aphront404Response(); } $view_uri = $this->getApplicationURI('/post/view/'.$post->getID().'/'); if ($request->isFormPost()) { $xactions = array(); - $xactions[] = id(new PhamePostTransaction()) - ->setTransactionType(PhamePostTransaction::TYPE_TITLE) - ->setNewValue($post->getTitle()); - $xactions[] = id(new PhamePostTransaction()) - ->setTransactionType(PhamePostTransaction::TYPE_PHAME_TITLE) - ->setNewValue($post->getPhameTitle()); $xactions[] = id(new PhamePostTransaction()) ->setTransactionType(PhamePostTransaction::TYPE_VISIBILITY) ->setNewValue(PhameConstants::VISIBILITY_PUBLISHED); id(new PhamePostEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true) ->setContinueOnMissingFields(true) ->applyTransactions($post, $xactions); return id(new AphrontRedirectResponse())->setURI($view_uri); } $form = id(new AphrontFormView()) ->setUser($viewer) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue(pht('Publish Post')) ->addCancelButton($view_uri)); $frame = $this->renderPreviewFrame($post); $form_box = id(new PHUIObjectBoxView()) ->setHeaderText(pht('Preview Post')) ->setForm($form); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Preview'), $view_uri); return $this->newPage() ->setTitle(pht('Preview Post')) ->setCrumbs($crumbs) ->appendChild( array( $form_box, $frame, )); } private function renderPreviewFrame(PhamePost $post) { return phutil_tag( 'div', array( 'style' => 'text-align: center; padding: 16px;', ), phutil_tag( 'iframe', array( 'style' => 'width: 100%; height: 600px; '. 'border: 1px solid #BFCFDA; '. 'background-color: #fff; '. 'border-radius: 3px; ', 'src' => $this->getApplicationURI('/post/framed/'.$post->getID().'/'), ), '')); } } diff --git a/src/applications/phame/controller/post/PhamePostUnpublishController.php b/src/applications/phame/controller/post/PhamePostUnpublishController.php index 8e95cfe75b..ca09ef8879 100644 --- a/src/applications/phame/controller/post/PhamePostUnpublishController.php +++ b/src/applications/phame/controller/post/PhamePostUnpublishController.php @@ -1,60 +1,54 @@ getViewer(); $id = $request->getURIData('id'); $post = id(new PhamePostQuery()) ->setViewer($viewer) ->withIDs(array($id)) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_EDIT, )) ->executeOne(); if (!$post) { return new Aphront404Response(); } if ($request->isFormPost()) { $xactions = array(); - $xactions[] = id(new PhamePostTransaction()) - ->setTransactionType(PhamePostTransaction::TYPE_TITLE) - ->setNewValue($post->getTitle()); - $xactions[] = id(new PhamePostTransaction()) - ->setTransactionType(PhamePostTransaction::TYPE_PHAME_TITLE) - ->setNewValue($post->getPhameTitle()); $xactions[] = id(new PhamePostTransaction()) ->setTransactionType(PhamePostTransaction::TYPE_VISIBILITY) ->setNewValue(PhameConstants::VISIBILITY_DRAFT); id(new PhamePostEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true) ->setContinueOnMissingFields(true) ->applyTransactions($post, $xactions); return id(new AphrontRedirectResponse()) ->setURI($this->getApplicationURI('/post/view/'.$post->getID().'/')); } $cancel_uri = $this->getApplicationURI('/post/view/'.$post->getID().'/'); $dialog = id(new AphrontDialogView()) ->setUser($viewer) ->setTitle(pht('Unpublish Post?')) ->appendChild( pht( 'The post "%s" will no longer be visible to other users until you '. 'republish it.', $post->getTitle())) ->addSubmitButton(pht('Unpublish')) ->addCancelButton($cancel_uri); return id(new AphrontDialogResponse())->setDialog($dialog); } } diff --git a/src/applications/phame/editor/PhameBlogEditor.php b/src/applications/phame/editor/PhameBlogEditor.php index d665d92541..a44bec422b 100644 --- a/src/applications/phame/editor/PhameBlogEditor.php +++ b/src/applications/phame/editor/PhameBlogEditor.php @@ -1,174 +1,178 @@ getTransactionType()) { case PhameBlogTransaction::TYPE_NAME: return $object->getName(); case PhameBlogTransaction::TYPE_DESCRIPTION: return $object->getDescription(); case PhameBlogTransaction::TYPE_DOMAIN: return $object->getDomain(); case PhameBlogTransaction::TYPE_SKIN: return $object->getSkin(); } } protected function getCustomTransactionNewValue( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case PhameBlogTransaction::TYPE_NAME: case PhameBlogTransaction::TYPE_DESCRIPTION: case PhameBlogTransaction::TYPE_DOMAIN: case PhameBlogTransaction::TYPE_SKIN: return $xaction->getNewValue(); } } protected function applyCustomInternalTransaction( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case PhameBlogTransaction::TYPE_NAME: return $object->setName($xaction->getNewValue()); case PhameBlogTransaction::TYPE_DESCRIPTION: return $object->setDescription($xaction->getNewValue()); case PhameBlogTransaction::TYPE_DOMAIN: return $object->setDomain($xaction->getNewValue()); case PhameBlogTransaction::TYPE_SKIN: return $object->setSkin($xaction->getNewValue()); } return parent::applyCustomInternalTransaction($object, $xaction); } protected function applyCustomExternalTransaction( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case PhameBlogTransaction::TYPE_NAME: case PhameBlogTransaction::TYPE_DESCRIPTION: case PhameBlogTransaction::TYPE_DOMAIN: case PhameBlogTransaction::TYPE_SKIN: return; } return parent::applyCustomExternalTransaction($object, $xaction); } protected function validateTransaction( PhabricatorLiskDAO $object, $type, array $xactions) { $errors = parent::validateTransaction($object, $type, $xactions); + switch ($type) { case PhameBlogTransaction::TYPE_NAME: $missing = $this->validateIsEmptyTextField( $object->getName(), $xactions); if ($missing) { $error = new PhabricatorApplicationTransactionValidationError( $type, pht('Required'), pht('Name is required.'), nonempty(last($xactions), null)); $error->setIsMissingFieldError(true); $errors[] = $error; } break; case PhameBlogTransaction::TYPE_DOMAIN: + if (!$xactions) { + continue; + } $custom_domain = last($xactions)->getNewValue(); if (empty($custom_domain)) { continue; } list($error_label, $error_text) = $object->validateCustomDomain($custom_domain); if ($error_label) { $error = new PhabricatorApplicationTransactionValidationError( $type, $error_label, $error_text, nonempty(last($xactions), null)); $errors[] = $error; } if ($object->getViewPolicy() != PhabricatorPolicies::POLICY_PUBLIC) { $error_text = pht( 'For custom domains to work, the blog must have a view policy of '. 'public.'); $error = new PhabricatorApplicationTransactionValidationError( PhabricatorTransactions::TYPE_VIEW_POLICY, pht('Invalid Policy'), $error_text, nonempty(last($xactions), null)); $errors[] = $error; } $duplicate_blog = id(new PhameBlogQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withDomain($custom_domain) ->executeOne(); if ($duplicate_blog && $duplicate_blog->getID() != $object->getID()) { $error = new PhabricatorApplicationTransactionValidationError( $type, pht('Not Unique'), pht('Domain must be unique; another blog already has this domain.'), nonempty(last($xactions), null)); $errors[] = $error; } break; } return $errors; } protected function shouldSendMail( PhabricatorLiskDAO $object, array $xactions) { return false; } protected function shouldPublishFeedStory( PhabricatorLiskDAO $object, array $xactions) { return false; } protected function supportsSearch() { return false; } } diff --git a/src/applications/phame/editor/PhamePostEditor.php b/src/applications/phame/editor/PhamePostEditor.php index 4cf0a0c60d..0009ccaea5 100644 --- a/src/applications/phame/editor/PhamePostEditor.php +++ b/src/applications/phame/editor/PhamePostEditor.php @@ -1,239 +1,245 @@ getTransactionType()) { case PhamePostTransaction::TYPE_TITLE: return $object->getTitle(); case PhamePostTransaction::TYPE_PHAME_TITLE: return $object->getPhameTitle(); case PhamePostTransaction::TYPE_BODY: return $object->getBody(); case PhamePostTransaction::TYPE_VISIBILITY: return $object->getVisibility(); case PhamePostTransaction::TYPE_COMMENTS_WIDGET: return $object->getCommentsWidget(); } } protected function getCustomTransactionNewValue( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case PhamePostTransaction::TYPE_TITLE: case PhamePostTransaction::TYPE_PHAME_TITLE: case PhamePostTransaction::TYPE_BODY: case PhamePostTransaction::TYPE_VISIBILITY: case PhamePostTransaction::TYPE_COMMENTS_WIDGET: return $xaction->getNewValue(); } } protected function applyCustomInternalTransaction( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case PhamePostTransaction::TYPE_TITLE: return $object->setTitle($xaction->getNewValue()); case PhamePostTransaction::TYPE_PHAME_TITLE: return $object->setPhameTitle($xaction->getNewValue()); case PhamePostTransaction::TYPE_BODY: return $object->setBody($xaction->getNewValue()); case PhamePostTransaction::TYPE_VISIBILITY: if ($xaction->getNewValue() == PhameConstants::VISIBILITY_DRAFT) { $object->setDatePublished(time()); } else { $object->setDatePublished(0); } return $object->setVisibility($xaction->getNewValue()); case PhamePostTransaction::TYPE_COMMENTS_WIDGET: return $object->setCommentsWidget($xaction->getNewValue()); } return parent::applyCustomInternalTransaction($object, $xaction); } protected function applyCustomExternalTransaction( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case PhamePostTransaction::TYPE_TITLE: case PhamePostTransaction::TYPE_PHAME_TITLE: case PhamePostTransaction::TYPE_BODY: case PhamePostTransaction::TYPE_VISIBILITY: case PhamePostTransaction::TYPE_COMMENTS_WIDGET: return; } return parent::applyCustomExternalTransaction($object, $xaction); } protected function validateTransaction( PhabricatorLiskDAO $object, $type, array $xactions) { $errors = parent::validateTransaction($object, $type, $xactions); switch ($type) { case PhamePostTransaction::TYPE_TITLE: $missing = $this->validateIsEmptyTextField( $object->getTitle(), $xactions); if ($missing) { $error = new PhabricatorApplicationTransactionValidationError( $type, pht('Required'), pht('Title is required.'), nonempty(last($xactions), null)); $error->setIsMissingFieldError(true); $errors[] = $error; } break; case PhamePostTransaction::TYPE_PHAME_TITLE: + if (!$xactions) { + continue; + } $missing = $this->validateIsEmptyTextField( $object->getPhameTitle(), $xactions); $phame_title = last($xactions)->getNewValue(); if ($missing || $phame_title == '/') { $error = new PhabricatorApplicationTransactionValidationError( $type, pht('Required'), pht('Phame title is required.'), nonempty(last($xactions), null)); $error->setIsMissingFieldError(true); $errors[] = $error; } $duplicate_post = id(new PhamePostQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withPhameTitles(array($phame_title)) ->executeOne(); if ($duplicate_post && $duplicate_post->getID() != $object->getID()) { $error_text = pht( 'Phame title must be unique; another post already has this phame '. 'title.'); $error = new PhabricatorApplicationTransactionValidationError( $type, pht('Not Unique'), $error_text, nonempty(last($xactions), null)); $errors[] = $error; } break; } return $errors; } protected function shouldSendMail( PhabricatorLiskDAO $object, array $xactions) { if ($object->isDraft()) { return false; } return true; } protected function shouldPublishFeedStory( PhabricatorLiskDAO $object, array $xactions) { if ($object->isDraft()) { return false; } return true; } protected function getMailTo(PhabricatorLiskDAO $object) { $phids = array(); $phids[] = $object->getBloggerPHID(); $phids[] = $this->requireActor()->getPHID(); $blog_phid = $object->getBlogPHID(); if ($blog_phid) { - $phids[] = PhabricatorSubscribersQuery::loadSubscribersForPHID( + $cc_phids = PhabricatorSubscribersQuery::loadSubscribersForPHID( $blog_phid); + foreach ($cc_phids as $cc) { + $phids[] = $cc; + } } return $phids; } protected function buildMailTemplate(PhabricatorLiskDAO $object) { $phid = $object->getPHID(); $title = $object->getTitle(); return id(new PhabricatorMetaMTAMail()) ->setSubject($title) ->addHeader('Thread-Topic', $phid); } protected function buildReplyHandler(PhabricatorLiskDAO $object) { return id(new PhamePostReplyHandler()) ->setMailReceiver($object); } protected function buildMailBody( PhabricatorLiskDAO $object, array $xactions) { $body = parent::buildMailBody($object, $xactions); $body->addRemarkupSection(null, $object->getBody()); $body->addLinkSection( pht('POST DETAIL'), PhabricatorEnv::getProductionURI($object->getViewURI())); return $body; } public function getMailTagsMap() { return array( PhamePostTransaction::MAILTAG_CONTENT => pht("A post's content changes."), PhamePostTransaction::MAILTAG_COMMENT => pht('Someone comments on a post.'), PhamePostTransaction::MAILTAG_OTHER => pht('Other post activity not listed above occurs.'), ); } protected function getMailSubjectPrefix() { return '[Phame]'; } protected function supportsSearch() { return false; } }