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 PhabricatorFulltextInterface
,
15 PhabricatorFerretInterface
{
17 const MARKUP_FIELD_BODY
= 'markup:body';
18 const MARKUP_FIELD_SUMMARY
= 'markup:summary';
20 protected $bloggerPHID;
23 protected $phameTitle;
25 protected $visibility;
26 protected $configData;
27 protected $datePublished;
30 protected $headerImagePHID;
32 private $blog = self
::ATTACHABLE
;
33 private $headerImageFile = self
::ATTACHABLE
;
35 public static function initializePost(
36 PhabricatorUser
$blogger,
39 $post = id(new PhamePost())
40 ->setBloggerPHID($blogger->getPHID())
41 ->setBlogPHID($blog->getPHID())
43 ->setDatePublished(PhabricatorTime
::getNow())
44 ->setVisibility(PhameConstants
::VISIBILITY_PUBLISHED
);
49 public function attachBlog(PhameBlog
$blog) {
54 public function getBlog() {
55 return $this->assertAttached($this->blog
);
58 public function getMonogram() {
59 return 'J'.$this->getID();
62 public function getLiveURI() {
63 $blog = $this->getBlog();
64 $is_draft = $this->isDraft();
65 $is_archived = $this->isArchived();
66 if (strlen($blog->getDomain()) && !$is_draft && !$is_archived) {
67 return $this->getExternalLiveURI();
69 return $this->getInternalLiveURI();
73 public function getExternalLiveURI() {
75 $slug = $this->getSlug();
76 $path = "/post/{$id}/{$slug}/";
78 $domain = $this->getBlog()->getDomain();
80 return (string)id(new PhutilURI('http://'.$domain))
84 public function getInternalLiveURI() {
86 $slug = $this->getSlug();
87 $blog_id = $this->getBlog()->getID();
88 return "/phame/live/{$blog_id}/post/{$id}/{$slug}/";
91 public function getViewURI() {
93 $slug = $this->getSlug();
94 return "/phame/post/view/{$id}/{$slug}/";
97 public function getBestURI($is_live, $is_external) {
100 return $this->getExternalLiveURI();
102 return $this->getInternalLiveURI();
105 return $this->getViewURI();
109 public function getEditURI() {
110 return '/phame/post/edit/'.$this->getID().'/';
113 public function isDraft() {
114 return ($this->getVisibility() == PhameConstants
::VISIBILITY_DRAFT
);
117 public function isArchived() {
118 return ($this->getVisibility() == PhameConstants
::VISIBILITY_ARCHIVED
);
121 protected function getConfiguration() {
123 self
::CONFIG_AUX_PHID
=> true,
124 self
::CONFIG_SERIALIZATION
=> array(
125 'configData' => self
::SERIALIZATION_JSON
,
127 self
::CONFIG_COLUMN_SCHEMA
=> array(
128 'title' => 'text255',
129 'subtitle' => 'text64',
130 'phameTitle' => 'sort64?',
131 'visibility' => 'uint32',
132 'mailKey' => 'bytes20',
133 'headerImagePHID' => 'phid?',
136 // These seem like they should always be non-null?
137 'blogPHID' => 'phid?',
139 'configData' => 'text?',
142 // This one probably should be nullable?
143 'datePublished' => 'epoch',
145 self
::CONFIG_KEY_SCHEMA
=> array(
148 'columns' => array('phid'),
151 'bloggerPosts' => array(
160 ) + parent
::getConfiguration();
163 public function save() {
164 if (!$this->getMailKey()) {
165 $this->setMailKey(Filesystem
::readRandomCharacters(20));
167 return parent
::save();
170 public function generatePHID() {
171 return PhabricatorPHID
::generateNewPHID(
172 PhabricatorPhamePostPHIDType
::TYPECONST
);
175 public function getSlug() {
176 return PhabricatorSlug
::normalizeProjectSlug($this->getTitle());
179 public function getHeaderImageURI() {
180 return $this->getHeaderImageFile()->getBestURI();
183 public function attachHeaderImageFile(PhabricatorFile
$file) {
184 $this->headerImageFile
= $file;
188 public function getHeaderImageFile() {
189 return $this->assertAttached($this->headerImageFile
);
193 /* -( PhabricatorPolicyInterface Implementation )-------------------------- */
196 public function getCapabilities() {
198 PhabricatorPolicyCapability
::CAN_VIEW
,
199 PhabricatorPolicyCapability
::CAN_EDIT
,
203 public function getPolicy($capability) {
204 // Draft and archived posts are visible only to the author and other
205 // users who can edit the blog. Published posts are visible to whoever
206 // the blog is visible to.
208 switch ($capability) {
209 case PhabricatorPolicyCapability
::CAN_VIEW
:
210 if (!$this->isDraft() && !$this->isArchived() && $this->getBlog()) {
211 return $this->getBlog()->getViewPolicy();
212 } else if ($this->getBlog()) {
213 return $this->getBlog()->getEditPolicy();
215 return PhabricatorPolicies
::POLICY_NOONE
;
218 case PhabricatorPolicyCapability
::CAN_EDIT
:
219 if ($this->getBlog()) {
220 return $this->getBlog()->getEditPolicy();
222 return PhabricatorPolicies
::POLICY_NOONE
;
227 public function hasAutomaticCapability($capability, PhabricatorUser
$user) {
228 // A blog post's author can always view it.
230 switch ($capability) {
231 case PhabricatorPolicyCapability
::CAN_VIEW
:
232 case PhabricatorPolicyCapability
::CAN_EDIT
:
233 return ($user->getPHID() == $this->getBloggerPHID());
237 public function describeAutomaticCapability($capability) {
238 return pht('The author of a blog post can always view and edit it.');
242 /* -( PhabricatorMarkupInterface Implementation )-------------------------- */
245 public function getMarkupFieldKey($field) {
246 $content = $this->getMarkupText($field);
247 return PhabricatorMarkupEngine
::digestRemarkupContent($this, $content);
250 public function newMarkupEngine($field) {
251 return PhabricatorMarkupEngine
::newPhameMarkupEngine();
254 public function getMarkupText($field) {
256 case self
::MARKUP_FIELD_BODY
:
257 return $this->getBody();
258 case self
::MARKUP_FIELD_SUMMARY
:
259 return PhabricatorMarkupEngine
::summarize($this->getBody());
263 public function didMarkupText(
266 PhutilMarkupEngine
$engine) {
270 public function shouldUseMarkupCache($field) {
271 return (bool)$this->getPHID();
275 /* -( PhabricatorApplicationTransactionInterface )------------------------- */
278 public function getApplicationTransactionEditor() {
279 return new PhamePostEditor();
282 public function getApplicationTransactionTemplate() {
283 return new PhamePostTransaction();
287 /* -( PhabricatorDestructibleInterface )----------------------------------- */
290 public function destroyObjectPermanently(
291 PhabricatorDestructionEngine
$engine) {
293 $this->openTransaction();
295 $this->saveTransaction();
299 /* -( PhabricatorTokenReceiverInterface )---------------------------------- */
302 public function getUsersToNotifyOfTokenGiven() {
304 $this->getBloggerPHID(),
309 /* -( PhabricatorSubscribableInterface Implementation )-------------------- */
312 public function isAutomaticallySubscribed($phid) {
313 return ($this->bloggerPHID
== $phid);
317 /* -( PhabricatorConduitResultInterface )---------------------------------- */
320 public function getFieldSpecificationsForConduit() {
322 id(new PhabricatorConduitSearchFieldSpecification())
325 ->setDescription(pht('Title of the post.')),
326 id(new PhabricatorConduitSearchFieldSpecification())
329 ->setDescription(pht('Slug for the post.')),
330 id(new PhabricatorConduitSearchFieldSpecification())
333 ->setDescription(pht('PHID of the blog that the post belongs to.')),
334 id(new PhabricatorConduitSearchFieldSpecification())
335 ->setKey('authorPHID')
337 ->setDescription(pht('PHID of the author of the post.')),
338 id(new PhabricatorConduitSearchFieldSpecification())
341 ->setDescription(pht('Body of the post.')),
342 id(new PhabricatorConduitSearchFieldSpecification())
343 ->setKey('datePublished')
345 ->setDescription(pht('Publish date, if the post has been published.')),
350 public function getFieldValuesForConduit() {
351 if ($this->isDraft()) {
352 $date_published = null;
353 } else if ($this->isArchived()) {
354 $date_published = null;
356 $date_published = (int)$this->getDatePublished();
360 'title' => $this->getTitle(),
361 'slug' => $this->getSlug(),
362 'blogPHID' => $this->getBlogPHID(),
363 'authorPHID' => $this->getBloggerPHID(),
364 'body' => $this->getBody(),
365 'datePublished' => $date_published,
369 public function getConduitSearchAttachments() {
374 /* -( PhabricatorFulltextInterface )--------------------------------------- */
376 public function newFulltextEngine() {
377 return new PhamePostFulltextEngine();
381 /* -( PhabricatorFerretInterface )----------------------------------------- */
384 public function newFerretEngine() {
385 return new PhamePostFerretEngine();