diff --git a/src/applications/phame/controller/blog/PhameBlogManageController.php b/src/applications/phame/controller/blog/PhameBlogManageController.php index 4085d3ef6b..2bdcbf7635 100644 --- a/src/applications/phame/controller/blog/PhameBlogManageController.php +++ b/src/applications/phame/controller/blog/PhameBlogManageController.php @@ -1,241 +1,252 @@ getViewer(); $id = $request->getURIData('id'); $blog = id(new PhameBlogQuery()) ->setViewer($viewer) ->withIDs(array($id)) ->needProfileImage(true) ->needHeaderImage(true) ->executeOne(); if (!$blog) { return new Aphront404Response(); } if ($blog->isArchived()) { $header_icon = 'fa-ban'; $header_name = pht('Archived'); $header_color = 'dark'; } else { $header_icon = 'fa-check'; $header_name = pht('Active'); $header_color = 'bluegrey'; } $picture = $blog->getProfileImageURI(); $view = id(new PHUIButtonView()) ->setTag('a') ->setText(pht('View Live')) ->setIcon('fa-external-link') - ->setHref($blog->getLiveURI()); + ->setHref($blog->getLiveURI()) + ->setDisabled($blog->isArchived()); $header = id(new PHUIHeaderView()) ->setHeader($blog->getName()) ->setUser($viewer) ->setPolicyObject($blog) ->setImage($picture) ->setStatus($header_icon, $header_color, $header_name) ->addActionLink($view); + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $blog, + PhabricatorPolicyCapability::CAN_EDIT); + + if ($can_edit) { + $header->setImageEditURL( + $this->getApplicationURI('blog/picture/'.$blog->getID().'/')); + } + $curtain = $this->buildCurtain($blog); $properties = $this->buildPropertyView($blog); $file = $this->buildFileView($blog); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb( pht('Blogs'), $this->getApplicationURI('blog/')); $crumbs->addTextCrumb( $blog->getName(), $this->getApplicationURI('blog/view/'.$id)); $crumbs->addTextCrumb(pht('Manage Blog')); $crumbs->setBorder(true); $object_box = id(new PHUIObjectBoxView()) ->setHeader($header) ->addPropertyList($properties); $timeline = $this->buildTransactionTimeline( $blog, new PhameBlogTransactionQuery()); $timeline->setShouldTerminate(true); $view = id(new PHUITwoColumnView()) ->setHeader($header) ->setCurtain($curtain) ->addPropertySection(pht('Details'), $properties) ->addPropertySection(pht('Header'), $file) ->setMainColumn( array( $timeline, )); return $this->newPage() ->setTitle($blog->getName()) ->setCrumbs($crumbs) ->appendChild( array( $view, )); } private function buildPropertyView(PhameBlog $blog) { $viewer = $this->getViewer(); require_celerity_resource('aphront-tooltip-css'); Javelin::initBehavior('phabricator-tooltips'); $properties = id(new PHUIPropertyListView()) ->setUser($viewer); $full_domain = $blog->getDomainFullURI(); if (!$full_domain) { $full_domain = phutil_tag('em', array(), pht('No external domain')); } $properties->addProperty(pht('Full Domain'), $full_domain); $parent_site = $blog->getParentSite(); if (!$parent_site) { $parent_site = phutil_tag('em', array(), pht('No parent site')); } $properties->addProperty(pht('Parent Site'), $parent_site); $parent_domain = $blog->getParentDomain(); if (!$parent_domain) { $parent_domain = phutil_tag('em', array(), pht('No parent domain')); } $properties->addProperty(pht('Parent Domain'), $parent_domain); $feed_uri = PhabricatorEnv::getProductionURI( $this->getApplicationURI('blog/feed/'.$blog->getID().'/')); $properties->addProperty( pht('Atom URI'), javelin_tag('a', array( 'href' => $feed_uri, 'sigil' => 'has-tooltip', 'meta' => array( 'tip' => pht('Atom URI does not support custom domains.'), 'size' => 320, ), ), $feed_uri)); $descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions( $viewer, $blog); $properties->addProperty( pht('Editable By'), $descriptions[PhabricatorPolicyCapability::CAN_EDIT]); $engine = id(new PhabricatorMarkupEngine()) ->setViewer($viewer) ->addObject($blog, PhameBlog::MARKUP_FIELD_DESCRIPTION) ->process(); $description = $blog->getDescription(); if (strlen($description)) { $description = new PHUIRemarkupView($viewer, $description); $properties->addSectionHeader( pht('Description'), PHUIPropertyListView::ICON_SUMMARY); $properties->addTextContent($description); } return $properties; } private function buildCurtain(PhameBlog $blog) { $viewer = $this->getViewer(); $curtain = $this->newCurtainView($blog); $actions = id(new PhabricatorActionListView()) ->setObject($blog) ->setUser($viewer); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, $blog, PhabricatorPolicyCapability::CAN_EDIT); $curtain->addAction( id(new PhabricatorActionView()) ->setIcon('fa-pencil') ->setHref($this->getApplicationURI('blog/edit/'.$blog->getID().'/')) ->setName(pht('Edit Blog')) ->setDisabled(!$can_edit) ->setWorkflow(!$can_edit)); $curtain->addAction( id(new PhabricatorActionView()) ->setIcon('fa-camera') ->setHref($this->getApplicationURI('blog/header/'.$blog->getID().'/')) ->setName(pht('Edit Blog Header')) ->setDisabled(!$can_edit) ->setWorkflow(!$can_edit)); $curtain->addAction( id(new PhabricatorActionView()) ->setIcon('fa-picture-o') ->setHref($this->getApplicationURI('blog/picture/'.$blog->getID().'/')) ->setName(pht('Edit Blog Picture')) ->setDisabled(!$can_edit) ->setWorkflow(!$can_edit)); if ($blog->isArchived()) { $curtain->addAction( id(new PhabricatorActionView()) ->setName(pht('Activate Blog')) ->setIcon('fa-check') ->setHref( $this->getApplicationURI('blog/archive/'.$blog->getID().'/')) ->setDisabled(!$can_edit) ->setWorkflow(true)); } else { $curtain->addAction( id(new PhabricatorActionView()) ->setName(pht('Archive Blog')) ->setIcon('fa-ban') ->setHref( $this->getApplicationURI('blog/archive/'.$blog->getID().'/')) ->setDisabled(!$can_edit) ->setWorkflow(true)); } return $curtain; } private function buildFileView( PhameBlog $blog) { $viewer = $this->getViewer(); $view = id(new PHUIPropertyListView()) ->setUser($viewer); if ($blog->getHeaderImagePHID()) { $view->addImageContent( phutil_tag( 'img', array( 'src' => $blog->getHeaderImageURI(), 'class' => 'phabricator-image-macro-hero', ))); return $view; } return null; } } diff --git a/src/applications/phame/controller/post/PhamePostViewController.php b/src/applications/phame/controller/post/PhamePostViewController.php index d28f1b5150..f7dddebe53 100644 --- a/src/applications/phame/controller/post/PhamePostViewController.php +++ b/src/applications/phame/controller/post/PhamePostViewController.php @@ -1,309 +1,313 @@ setupLiveEnvironment(); if ($response) { return $response; } $viewer = $request->getViewer(); $moved = $request->getStr('moved'); $post = $this->getPost(); $blog = $this->getBlog(); $is_live = $this->getIsLive(); $is_external = $this->getIsExternal(); $header = id(new PHUIHeaderView()) ->setHeader($post->getTitle()) ->setUser($viewer); if (!$is_external) { $actions = $this->renderActions($post); $header->setPolicyObject($post); $header->setActionList($actions); } $document = id(new PHUIDocumentViewPro()) ->setHeader($header); if ($moved) { $document->appendChild( id(new PHUIInfoView()) ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) ->appendChild(pht('Post moved successfully.'))); } if ($post->isDraft()) { $document->appendChild( id(new PHUIInfoView()) ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) ->setTitle(pht('Draft Post')) ->appendChild( pht('Only you can see this draft until you publish it. '. 'Use "Publish" to publish this post.'))); } if ($post->isArchived()) { $document->appendChild( id(new PHUIInfoView()) ->setSeverity(PHUIInfoView::SEVERITY_ERROR) ->setTitle(pht('Archived Post')) ->appendChild( pht('Only you can see this archived post until you publish it. '. 'Use "Publish" to publish this post.'))); } if (!$post->getBlog()) { $document->appendChild( id(new PHUIInfoView()) ->setSeverity(PHUIInfoView::SEVERITY_WARNING) ->setTitle(pht('Not On A Blog')) ->appendChild( pht('This post is not associated with a blog (the blog may have '. 'been deleted). Use "Move Post" to move it to a new blog.'))); } $engine = id(new PhabricatorMarkupEngine()) ->setViewer($viewer) ->addObject($post, PhamePost::MARKUP_FIELD_BODY) ->process(); $document->appendChild( phutil_tag( 'div', array( 'class' => 'phabricator-remarkup', ), $engine->getOutput($post, PhamePost::MARKUP_FIELD_BODY))); $blogger = id(new PhabricatorPeopleQuery()) ->setViewer($viewer) ->withPHIDs(array($post->getBloggerPHID())) ->needProfileImage(true) ->executeOne(); $blogger_profile = $blogger->loadUserProfile(); $author_uri = '/p/'.$blogger->getUsername().'/'; $author_uri = PhabricatorEnv::getURI($author_uri); $author = phutil_tag( 'a', array( 'href' => $author_uri, ), $blogger->getUsername()); $date = phabricator_datetime($post->getDatePublished(), $viewer); if ($post->isDraft()) { $subtitle = pht('Unpublished draft by %s.', $author); } else if ($post->isArchived()) { $subtitle = pht('Archived post by %s.', $author); } else { $subtitle = pht('Written by %s on %s.', $author, $date); } $user_icon = $blogger_profile->getIcon(); $user_icon = PhabricatorPeopleIconSet::getIconIcon($user_icon); $user_icon = id(new PHUIIconView())->setIcon($user_icon); $about = id(new PhameDescriptionView()) ->setTitle($subtitle) ->setDescription( array( $user_icon, ' ', - $blogger_profile->getTitle(), + $blogger_profile->getDisplayTitle(), )) ->setImage($blogger->getProfileImageURI()) ->setImageHref($author_uri); $timeline = $this->buildTransactionTimeline( $post, id(new PhamePostTransactionQuery()) ->withTransactionTypes(array(PhabricatorTransactions::TYPE_COMMENT))); $timeline = phutil_tag_div('phui-document-view-pro-box', $timeline); if ($is_external) { $add_comment = null; } else { $add_comment = $this->buildCommentForm($post); $add_comment = phutil_tag_div('mlb mlt', $add_comment); } list($prev, $next) = $this->loadAdjacentPosts($post); $properties = id(new PHUIPropertyListView()) ->setUser($viewer) ->setObject($post); + $is_live = $this->getIsLive(); + $is_external = $this->getIsExternal(); $next_view = new PhameNextPostView(); if ($next) { - $next_view->setNext($next->getTitle(), $next->getLiveURI()); + $next_view->setNext($next->getTitle(), + $next->getBestURI($is_live, $is_external)); } if ($prev) { - $next_view->setPrevious($prev->getTitle(), $prev->getLiveURI()); + $next_view->setPrevious($prev->getTitle(), + $prev->getBestURI($is_live, $is_external)); } $document->setFoot($next_view); $crumbs = $this->buildApplicationCrumbs(); $properties = phutil_tag_div('phui-document-view-pro-box', $properties); $page = $this->newPage() ->setTitle($post->getTitle()) ->setPageObjectPHIDs(array($post->getPHID())) ->setCrumbs($crumbs) ->appendChild( array( $document, $about, $properties, $timeline, $add_comment, )); if ($is_live) { $page ->setShowChrome(false) ->setShowFooter(false); } return $page; } private function renderActions(PhamePost $post) { $viewer = $this->getViewer(); $actions = id(new PhabricatorActionListView()) ->setObject($post) ->setUser($viewer); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, $post, PhabricatorPolicyCapability::CAN_EDIT); $id = $post->getID(); $actions->addAction( id(new PhabricatorActionView()) ->setIcon('fa-pencil') ->setHref($this->getApplicationURI('post/edit/'.$id.'/')) ->setName(pht('Edit Post')) ->setDisabled(!$can_edit)); $actions->addAction( id(new PhabricatorActionView()) ->setIcon('fa-arrows') ->setHref($this->getApplicationURI('post/move/'.$id.'/')) ->setName(pht('Move Post')) ->setDisabled(!$can_edit) ->setWorkflow(true)); $actions->addAction( id(new PhabricatorActionView()) ->setIcon('fa-history') ->setHref($this->getApplicationURI('post/history/'.$id.'/')) ->setName(pht('View History'))); if ($post->isDraft()) { $actions->addAction( id(new PhabricatorActionView()) ->setIcon('fa-eye') ->setHref($this->getApplicationURI('post/publish/'.$id.'/')) ->setName(pht('Publish')) ->setDisabled(!$can_edit) ->setWorkflow(true)); $actions->addAction( id(new PhabricatorActionView()) ->setIcon('fa-ban') ->setHref($this->getApplicationURI('post/archive/'.$id.'/')) ->setName(pht('Archive')) ->setDisabled(!$can_edit) ->setWorkflow(true)); } else if ($post->isArchived()) { $actions->addAction( id(new PhabricatorActionView()) ->setIcon('fa-eye') ->setHref($this->getApplicationURI('post/publish/'.$id.'/')) ->setName(pht('Publish')) ->setDisabled(!$can_edit) ->setWorkflow(true)); } else { $actions->addAction( id(new PhabricatorActionView()) ->setIcon('fa-eye-slash') ->setHref($this->getApplicationURI('post/unpublish/'.$id.'/')) ->setName(pht('Unpublish')) ->setDisabled(!$can_edit) ->setWorkflow(true)); $actions->addAction( id(new PhabricatorActionView()) ->setIcon('fa-ban') ->setHref($this->getApplicationURI('post/archive/'.$id.'/')) ->setName(pht('Archive')) ->setDisabled(!$can_edit) ->setWorkflow(true)); } if ($post->isDraft()) { $live_name = pht('Preview'); } else { $live_name = pht('View Live'); } if (!$post->isArchived()) { $actions->addAction( id(new PhabricatorActionView()) ->setUser($viewer) ->setIcon('fa-globe') ->setHref($post->getLiveURI()) ->setName($live_name)); } return $actions; } private function buildCommentForm(PhamePost $post) { $viewer = $this->getViewer(); $draft = PhabricatorDraft::newFromUserAndKey( $viewer, $post->getPHID()); $box = id(new PhabricatorApplicationTransactionCommentView()) ->setUser($viewer) ->setObjectPHID($post->getPHID()) ->setDraft($draft) ->setHeaderText(pht('Add Comment')) ->setAction($this->getApplicationURI('post/comment/'.$post->getID().'/')) ->setSubmitButtonName(pht('Add Comment')); return phutil_tag_div('phui-document-view-pro-box', $box); } private function loadAdjacentPosts(PhamePost $post) { $viewer = $this->getViewer(); $query = id(new PhamePostQuery()) ->setViewer($viewer) ->withVisibility(array(PhameConstants::VISIBILITY_PUBLISHED)) ->withBlogPHIDs(array($post->getBlog()->getPHID())) ->setLimit(1); $prev = id(clone $query) ->setAfterID($post->getID()) ->execute(); $next = id(clone $query) ->setBeforeID($post->getID()) ->execute(); return array(head($prev), head($next)); } } diff --git a/src/applications/phame/editor/PhameBlogEditEngine.php b/src/applications/phame/editor/PhameBlogEditEngine.php index 5f96309e8b..7d6511d55c 100644 --- a/src/applications/phame/editor/PhameBlogEditEngine.php +++ b/src/applications/phame/editor/PhameBlogEditEngine.php @@ -1,133 +1,137 @@ getViewer()); } protected function newObjectQuery() { return id(new PhameBlogQuery()) ->needProfileImage(true); } protected function getObjectCreateTitleText($object) { return pht('Create New Blog'); } protected function getObjectEditTitleText($object) { return pht('Edit %s', $object->getName()); } protected function getObjectEditShortText($object) { return $object->getName(); } protected function getObjectCreateShortText() { return pht('Create Blog'); } protected function getObjectName() { return pht('Blog'); } protected function getObjectCreateCancelURI($object) { return $this->getApplication()->getApplicationURI('blog/'); } protected function getEditorURI() { return $this->getApplication()->getApplicationURI('blog/edit/'); } protected function getObjectViewURI($object) { return $object->getManageURI(); } protected function getCreateNewObjectPolicy() { return $this->getApplication()->getPolicy( PhameBlogCreateCapability::CAPABILITY); } protected function buildCustomEditFields($object) { return array( id(new PhabricatorTextEditField()) ->setKey('name') ->setLabel(pht('Name')) ->setDescription(pht('Blog name.')) ->setConduitDescription(pht('Retitle the blog.')) ->setConduitTypeDescription(pht('New blog title.')) ->setTransactionType(PhameBlogTransaction::TYPE_NAME) ->setValue($object->getName()), id(new PhabricatorTextEditField()) ->setKey('subtitle') ->setLabel(pht('Subtitle')) ->setDescription(pht('Blog subtitle.')) ->setConduitDescription(pht('Change the blog subtitle.')) ->setConduitTypeDescription(pht('New blog subtitle.')) ->setTransactionType(PhameBlogTransaction::TYPE_SUBTITLE) ->setValue($object->getSubtitle()), id(new PhabricatorRemarkupEditField()) ->setKey('description') ->setLabel(pht('Description')) ->setDescription(pht('Blog description.')) ->setConduitDescription(pht('Change the blog description.')) ->setConduitTypeDescription(pht('New blog description.')) ->setTransactionType(PhameBlogTransaction::TYPE_DESCRIPTION) ->setValue($object->getDescription()), id(new PhabricatorTextEditField()) ->setKey('domainFullURI') ->setLabel(pht('Full Domain URI')) + ->setControlInstructions(pht('Set Full Domain URI if you plan to '. + 'serve this blog on another hosted domain. Parent Site Name and '. + 'Parent Site URI are optional but helpful since they provide '. + 'a link from the blog back to your parent site.')) ->setDescription(pht('Blog full domain URI.')) ->setConduitDescription(pht('Change the blog full domain URI.')) ->setConduitTypeDescription(pht('New blog full domain URI.')) ->setValue($object->getDomainFullURI()) ->setTransactionType(PhameBlogTransaction::TYPE_FULLDOMAIN), id(new PhabricatorTextEditField()) ->setKey('parentSite') - ->setLabel(pht('Parent Site')) + ->setLabel(pht('Parent Site Name')) ->setDescription(pht('Blog parent site name.')) ->setConduitDescription(pht('Change the blog parent site name.')) ->setConduitTypeDescription(pht('New blog parent site name.')) ->setValue($object->getParentSite()) ->setTransactionType(PhameBlogTransaction::TYPE_PARENTSITE), id(new PhabricatorTextEditField()) ->setKey('parentDomain') - ->setLabel(pht('Parent Domain')) + ->setLabel(pht('Parent Site URI')) ->setDescription(pht('Blog parent domain name.')) ->setConduitDescription(pht('Change the blog parent domain.')) ->setConduitTypeDescription(pht('New blog parent domain.')) ->setValue($object->getParentDomain()) ->setTransactionType(PhameBlogTransaction::TYPE_PARENTDOMAIN), id(new PhabricatorSelectEditField()) ->setKey('status') ->setLabel(pht('Status')) ->setTransactionType(PhameBlogTransaction::TYPE_STATUS) ->setIsConduitOnly(true) ->setOptions(PhameBlog::getStatusNameMap()) ->setDescription(pht('Active or archived status.')) ->setConduitDescription(pht('Active or archive the blog.')) ->setConduitTypeDescription(pht('New blog status constant.')) ->setValue($object->getStatus()), ); } } diff --git a/src/applications/phame/storage/PhamePost.php b/src/applications/phame/storage/PhamePost.php index 8078c5055c..4c4acf4dc1 100644 --- a/src/applications/phame/storage/PhamePost.php +++ b/src/applications/phame/storage/PhamePost.php @@ -1,355 +1,367 @@ setBloggerPHID($blogger->getPHID()) ->setBlogPHID($blog->getPHID()) ->attachBlog($blog) ->setDatePublished(PhabricatorTime::getNow()) ->setVisibility(PhameConstants::VISIBILITY_PUBLISHED); return $post; } public function attachBlog(PhameBlog $blog) { $this->blog = $blog; return $this; } public function getBlog() { return $this->assertAttached($this->blog); } public function getLiveURI() { $blog = $this->getBlog(); $is_draft = $this->isDraft(); $is_archived = $this->isArchived(); if (strlen($blog->getDomain()) && !$is_draft && !$is_archived) { return $this->getExternalLiveURI(); } else { return $this->getInternalLiveURI(); } } public function getExternalLiveURI() { $id = $this->getID(); $slug = $this->getSlug(); $path = "/post/{$id}/{$slug}/"; $domain = $this->getBlog()->getDomain(); return (string)id(new PhutilURI('http://'.$domain)) ->setPath($path); } public function getInternalLiveURI() { $id = $this->getID(); $slug = $this->getSlug(); $blog_id = $this->getBlog()->getID(); return "/phame/live/{$blog_id}/post/{$id}/{$slug}/"; } public function getViewURI() { $id = $this->getID(); $slug = $this->getSlug(); return "/phame/post/view/{$id}/{$slug}/"; } + public function getBestURI($is_live, $is_external) { + if ($is_live) { + if ($is_external) { + return $this->getExternalLiveURI(); + } else { + return $this->getInternalLiveURI(); + } + } else { + return $this->getViewURI(); + } + } + public function getEditURI() { return '/phame/post/edit/'.$this->getID().'/'; } public function isDraft() { return ($this->getVisibility() == PhameConstants::VISIBILITY_DRAFT); } public function isArchived() { return ($this->getVisibility() == PhameConstants::VISIBILITY_ARCHIVED); } protected function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_SERIALIZATION => array( 'configData' => self::SERIALIZATION_JSON, ), self::CONFIG_COLUMN_SCHEMA => array( 'title' => 'text255', 'phameTitle' => 'sort64?', 'visibility' => 'uint32', 'mailKey' => 'bytes20', // T6203/NULLABILITY // These seem like they should always be non-null? 'blogPHID' => 'phid?', 'body' => 'text?', 'configData' => 'text?', // T6203/NULLABILITY // This one probably should be nullable? 'datePublished' => 'epoch', ), self::CONFIG_KEY_SCHEMA => array( 'key_phid' => null, 'phid' => array( 'columns' => array('phid'), 'unique' => true, ), 'bloggerPosts' => array( 'columns' => array( 'bloggerPHID', 'visibility', 'datePublished', 'id', ), ), ), ) + parent::getConfiguration(); } public function save() { if (!$this->getMailKey()) { $this->setMailKey(Filesystem::readRandomCharacters(20)); } return parent::save(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( PhabricatorPhamePostPHIDType::TYPECONST); } public function getSlug() { return PhabricatorSlug::normalizeProjectSlug($this->getTitle(), true); } /* -( PhabricatorPolicyInterface Implementation )-------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { // Draft posts are visible only to the author. Published posts are visible // to whoever the blog is visible to. switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: if (!$this->isDraft() && !$this->isArchived() && $this->getBlog()) { return $this->getBlog()->getViewPolicy(); } else if ($this->getBlog()) { return $this->getBlog()->getEditPolicy(); } else { return PhabricatorPolicies::POLICY_NOONE; } break; case PhabricatorPolicyCapability::CAN_EDIT: if ($this->getBlog()) { return $this->getBlog()->getEditPolicy(); } else { return PhabricatorPolicies::POLICY_NOONE; } } } public function hasAutomaticCapability($capability, PhabricatorUser $user) { // A blog post's author can always view it. switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: case PhabricatorPolicyCapability::CAN_EDIT: return ($user->getPHID() == $this->getBloggerPHID()); } } public function describeAutomaticCapability($capability) { return pht('The author of a blog post can always view and edit it.'); } /* -( PhabricatorMarkupInterface Implementation )-------------------------- */ public function getMarkupFieldKey($field) { $hash = PhabricatorHash::digest($this->getMarkupText($field)); return $this->getPHID().':'.$field.':'.$hash; } public function newMarkupEngine($field) { return PhabricatorMarkupEngine::newPhameMarkupEngine(); } public function getMarkupText($field) { switch ($field) { case self::MARKUP_FIELD_BODY: return $this->getBody(); case self::MARKUP_FIELD_SUMMARY: return PhabricatorMarkupEngine::summarize($this->getBody()); } } public function didMarkupText( $field, $output, PhutilMarkupEngine $engine) { return $output; } public function shouldUseMarkupCache($field) { return (bool)$this->getPHID(); } /* -( PhabricatorApplicationTransactionInterface )------------------------- */ public function getApplicationTransactionEditor() { return new PhamePostEditor(); } public function getApplicationTransactionObject() { return $this; } public function getApplicationTransactionTemplate() { return new PhamePostTransaction(); } public function willRenderTimeline( PhabricatorApplicationTransactionView $timeline, AphrontRequest $request) { return $timeline; } /* -( PhabricatorDestructibleInterface )----------------------------------- */ public function destroyObjectPermanently( PhabricatorDestructionEngine $engine) { $this->openTransaction(); $this->delete(); $this->saveTransaction(); } /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ public function getUsersToNotifyOfTokenGiven() { return array( $this->getBloggerPHID(), ); } /* -( PhabricatorSubscribableInterface Implementation )-------------------- */ public function isAutomaticallySubscribed($phid) { return ($this->bloggerPHID == $phid); } /* -( PhabricatorConduitResultInterface )---------------------------------- */ public function getFieldSpecificationsForConduit() { return array( id(new PhabricatorConduitSearchFieldSpecification()) ->setKey('title') ->setType('string') ->setDescription(pht('Title of the post.')), id(new PhabricatorConduitSearchFieldSpecification()) ->setKey('slug') ->setType('string') ->setDescription(pht('Slug for the post.')), id(new PhabricatorConduitSearchFieldSpecification()) ->setKey('blogPHID') ->setType('phid') ->setDescription(pht('PHID of the blog that the post belongs to.')), id(new PhabricatorConduitSearchFieldSpecification()) ->setKey('authorPHID') ->setType('phid') ->setDescription(pht('PHID of the author of the post.')), id(new PhabricatorConduitSearchFieldSpecification()) ->setKey('body') ->setType('string') ->setDescription(pht('Body of the post.')), id(new PhabricatorConduitSearchFieldSpecification()) ->setKey('datePublished') ->setType('epoch?') ->setDescription(pht('Publish date, if the post has been published.')), ); } public function getFieldValuesForConduit() { if ($this->isDraft()) { $date_published = null; } else if ($this->isArchived()) { $date_published = null; } else { $date_published = (int)$this->getDatePublished(); } return array( 'title' => $this->getTitle(), 'slug' => $this->getSlug(), 'blogPHID' => $this->getBlogPHID(), 'authorPHID' => $this->getBloggerPHID(), 'body' => $this->getBody(), 'datePublished' => $date_published, ); } public function getConduitSearchAttachments() { return array(); } /* -( PhabricatorFulltextInterface )--------------------------------------- */ public function newFulltextEngine() { return new PhamePostFulltextEngine(); } }