3 final class PhamePost
extends PhameDAO
5 PhabricatorPolicyInterface
,
6 PhabricatorMarkupInterface
,
7 PhabricatorFlaggableInterface
,
8 PhabricatorProjectInterface
,
9 PhabricatorApplicationTransactionInterface
,
10 PhabricatorSubscribableInterface
,
11 PhabricatorDestructibleInterface
,
12 PhabricatorTokenReceiverInterface
,
13 PhabricatorConduitResultInterface
,
14 PhabricatorEditEngineLockableInterface
,
15 PhabricatorFulltextInterface
,
16 PhabricatorFerretInterface
{
18 const MARKUP_FIELD_BODY
= 'markup:body';
20 protected $bloggerPHID;
23 protected $phameTitle;
25 protected $visibility;
26 protected $configData;
27 protected $datePublished;
30 protected $headerImagePHID;
31 protected $interactPolicy;
33 private $blog = self
::ATTACHABLE
;
34 private $headerImageFile = self
::ATTACHABLE
;
36 public static function initializePost(
37 PhabricatorUser
$blogger,
40 $post = id(new PhamePost())
41 ->setBloggerPHID($blogger->getPHID())
42 ->setBlogPHID($blog->getPHID())
44 ->setDatePublished(PhabricatorTime
::getNow())
45 ->setVisibility(PhameConstants
::VISIBILITY_PUBLISHED
)
47 id(new PhameInheritBlogPolicyRule())
48 ->getObjectPolicyFullKey());
53 public function attachBlog(PhameBlog
$blog) {
58 public function getBlog() {
59 return $this->assertAttached($this->blog
);
62 public function getMonogram() {
63 return 'J'.$this->getID();
66 public function getLiveURI() {
67 $blog = $this->getBlog();
68 $is_draft = $this->isDraft();
69 $is_archived = $this->isArchived();
70 $is_external = $blog->getDomain() !== null && strlen($blog->getDomain());
71 if ($is_external && !$is_draft && !$is_archived) {
72 return $this->getExternalLiveURI();
74 return $this->getInternalLiveURI();
78 public function getExternalLiveURI() {
80 $slug = $this->getSlug();
81 $path = "/post/{$id}/{$slug}/";
83 $domain = $this->getBlog()->getDomain();
85 return (string)id(new PhutilURI('http://'.$domain))
89 public function getInternalLiveURI() {
91 $slug = $this->getSlug();
92 $blog_id = $this->getBlog()->getID();
93 return "/phame/live/{$blog_id}/post/{$id}/{$slug}/";
96 public function getViewURI() {
98 $slug = $this->getSlug();
99 return "/phame/post/view/{$id}/{$slug}/";
102 public function getBestURI($is_live, $is_external) {
105 return $this->getExternalLiveURI();
107 return $this->getInternalLiveURI();
110 return $this->getViewURI();
114 public function getEditURI() {
115 return '/phame/post/edit/'.$this->getID().'/';
118 public function isDraft() {
119 return ($this->getVisibility() == PhameConstants
::VISIBILITY_DRAFT
);
122 public function isArchived() {
123 return ($this->getVisibility() == PhameConstants
::VISIBILITY_ARCHIVED
);
126 protected function getConfiguration() {
128 self
::CONFIG_AUX_PHID
=> true,
129 self
::CONFIG_SERIALIZATION
=> array(
130 'configData' => self
::SERIALIZATION_JSON
,
132 self
::CONFIG_COLUMN_SCHEMA
=> array(
133 'title' => 'text255',
134 'subtitle' => 'text64',
135 'phameTitle' => 'sort64?',
136 'visibility' => 'uint32',
137 'mailKey' => 'bytes20',
138 'headerImagePHID' => 'phid?',
141 // These seem like they should always be non-null?
142 'blogPHID' => 'phid?',
144 'configData' => 'text?',
147 // This one probably should be nullable?
148 'datePublished' => 'epoch',
150 'interactPolicy' => 'policy',
152 self
::CONFIG_KEY_SCHEMA
=> array(
155 'columns' => array('phid'),
158 'bloggerPosts' => array(
167 ) + parent
::getConfiguration();
170 public function save() {
171 if (!$this->getMailKey()) {
172 $this->setMailKey(Filesystem
::readRandomCharacters(20));
174 return parent
::save();
177 public function generatePHID() {
178 return PhabricatorPHID
::generateNewPHID(
179 PhabricatorPhamePostPHIDType
::TYPECONST
);
182 public function getSlug() {
183 return PhabricatorSlug
::normalizeProjectSlug($this->getTitle());
186 public function getHeaderImageURI() {
187 return $this->getHeaderImageFile()->getBestURI();
190 public function attachHeaderImageFile(PhabricatorFile
$file) {
191 $this->headerImageFile
= $file;
195 public function getHeaderImageFile() {
196 return $this->assertAttached($this->headerImageFile
);
200 /* -( PhabricatorPolicyInterface Implementation )-------------------------- */
203 public function getCapabilities() {
205 PhabricatorPolicyCapability
::CAN_VIEW
,
206 PhabricatorPolicyCapability
::CAN_EDIT
,
207 PhabricatorPolicyCapability
::CAN_INTERACT
,
211 public function getPolicy($capability) {
212 // Draft and archived posts are visible only to the author and other
213 // users who can edit the blog. Published posts are visible to whoever
214 // the blog is visible to.
216 switch ($capability) {
217 case PhabricatorPolicyCapability
::CAN_VIEW
:
218 if (!$this->isDraft() && !$this->isArchived() && $this->getBlog()) {
219 return $this->getBlog()->getViewPolicy();
220 } else if ($this->getBlog()) {
221 return $this->getBlog()->getEditPolicy();
223 return PhabricatorPolicies
::POLICY_NOONE
;
226 case PhabricatorPolicyCapability
::CAN_EDIT
:
227 if ($this->getBlog()) {
228 return $this->getBlog()->getEditPolicy();
230 return PhabricatorPolicies
::POLICY_NOONE
;
232 case PhabricatorPolicyCapability
::CAN_INTERACT
:
233 return $this->getInteractPolicy();
237 public function hasAutomaticCapability($capability, PhabricatorUser
$user) {
238 // A blog post's author can always view it.
240 switch ($capability) {
241 case PhabricatorPolicyCapability
::CAN_VIEW
:
242 case PhabricatorPolicyCapability
::CAN_EDIT
:
243 return ($user->getPHID() == $this->getBloggerPHID());
244 case PhabricatorPolicyCapability
::CAN_INTERACT
:
249 public function describeAutomaticCapability($capability) {
250 return pht('The author of a blog post can always view and edit it.');
254 /* -( PhabricatorMarkupInterface Implementation )-------------------------- */
257 public function getMarkupFieldKey($field) {
258 $content = $this->getMarkupText($field);
259 return PhabricatorMarkupEngine
::digestRemarkupContent($this, $content);
262 public function newMarkupEngine($field) {
263 return PhabricatorMarkupEngine
::newPhameMarkupEngine();
266 public function getMarkupText($field) {
268 case self
::MARKUP_FIELD_BODY
:
269 return $this->getBody();
273 public function didMarkupText(
276 PhutilMarkupEngine
$engine) {
280 public function shouldUseMarkupCache($field) {
281 return (bool)$this->getPHID();
285 /* -( PhabricatorApplicationTransactionInterface )------------------------- */
288 public function getApplicationTransactionEditor() {
289 return new PhamePostEditor();
292 public function getApplicationTransactionTemplate() {
293 return new PhamePostTransaction();
297 /* -( PhabricatorDestructibleInterface )----------------------------------- */
300 public function destroyObjectPermanently(
301 PhabricatorDestructionEngine
$engine) {
303 $this->openTransaction();
305 $this->saveTransaction();
309 /* -( PhabricatorTokenReceiverInterface )---------------------------------- */
312 public function getUsersToNotifyOfTokenGiven() {
314 $this->getBloggerPHID(),
319 /* -( PhabricatorSubscribableInterface Implementation )-------------------- */
322 public function isAutomaticallySubscribed($phid) {
323 return ($this->bloggerPHID
== $phid);
327 /* -( PhabricatorConduitResultInterface )---------------------------------- */
330 public function getFieldSpecificationsForConduit() {
332 id(new PhabricatorConduitSearchFieldSpecification())
335 ->setDescription(pht('Title of the post.')),
336 id(new PhabricatorConduitSearchFieldSpecification())
339 ->setDescription(pht('Slug for the post.')),
340 id(new PhabricatorConduitSearchFieldSpecification())
343 ->setDescription(pht('PHID of the blog that the post belongs to.')),
344 id(new PhabricatorConduitSearchFieldSpecification())
345 ->setKey('authorPHID')
347 ->setDescription(pht('PHID of the author of the post.')),
348 id(new PhabricatorConduitSearchFieldSpecification())
351 ->setDescription(pht('Body of the post.')),
352 id(new PhabricatorConduitSearchFieldSpecification())
353 ->setKey('datePublished')
355 ->setDescription(pht('Publish date, if the post has been published.')),
360 public function getFieldValuesForConduit() {
361 if ($this->isDraft()) {
362 $date_published = null;
363 } else if ($this->isArchived()) {
364 $date_published = null;
366 $date_published = (int)$this->getDatePublished();
370 'title' => $this->getTitle(),
371 'slug' => $this->getSlug(),
372 'blogPHID' => $this->getBlogPHID(),
373 'authorPHID' => $this->getBloggerPHID(),
374 'body' => $this->getBody(),
375 'datePublished' => $date_published,
379 public function getConduitSearchAttachments() {
384 /* -( PhabricatorFulltextInterface )--------------------------------------- */
386 public function newFulltextEngine() {
387 return new PhamePostFulltextEngine();
391 /* -( PhabricatorFerretInterface )----------------------------------------- */
394 public function newFerretEngine() {
395 return new PhamePostFerretEngine();
399 /* -( PhabricatorEditEngineLockableInterface )----------------------------- */
401 public function newEditEngineLock() {
402 return new PhamePostEditEngineLock();