Correct Aphlict websocket URI construction after PHP8 compatibility changes
[phabricator.git] / src / applications / phame / storage / PhamePost.php
blobea92896a7d60f1564fdc13b371f3e138eebcbe19
1 <?php
3 final class PhamePost extends PhameDAO
4 implements
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;
21 protected $title;
22 protected $subtitle;
23 protected $phameTitle;
24 protected $body;
25 protected $visibility;
26 protected $configData;
27 protected $datePublished;
28 protected $blogPHID;
29 protected $mailKey;
30 protected $headerImagePHID;
31 protected $interactPolicy;
33 private $blog = self::ATTACHABLE;
34 private $headerImageFile = self::ATTACHABLE;
36 public static function initializePost(
37 PhabricatorUser $blogger,
38 PhameBlog $blog) {
40 $post = id(new PhamePost())
41 ->setBloggerPHID($blogger->getPHID())
42 ->setBlogPHID($blog->getPHID())
43 ->attachBlog($blog)
44 ->setDatePublished(PhabricatorTime::getNow())
45 ->setVisibility(PhameConstants::VISIBILITY_PUBLISHED)
46 ->setInteractPolicy(
47 id(new PhameInheritBlogPolicyRule())
48 ->getObjectPolicyFullKey());
50 return $post;
53 public function attachBlog(PhameBlog $blog) {
54 $this->blog = $blog;
55 return $this;
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();
73 } else {
74 return $this->getInternalLiveURI();
78 public function getExternalLiveURI() {
79 $id = $this->getID();
80 $slug = $this->getSlug();
81 $path = "/post/{$id}/{$slug}/";
83 $domain = $this->getBlog()->getDomain();
85 return (string)id(new PhutilURI('http://'.$domain))
86 ->setPath($path);
89 public function getInternalLiveURI() {
90 $id = $this->getID();
91 $slug = $this->getSlug();
92 $blog_id = $this->getBlog()->getID();
93 return "/phame/live/{$blog_id}/post/{$id}/{$slug}/";
96 public function getViewURI() {
97 $id = $this->getID();
98 $slug = $this->getSlug();
99 return "/phame/post/view/{$id}/{$slug}/";
102 public function getBestURI($is_live, $is_external) {
103 if ($is_live) {
104 if ($is_external) {
105 return $this->getExternalLiveURI();
106 } else {
107 return $this->getInternalLiveURI();
109 } else {
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() {
127 return array(
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?',
140 // T6203/NULLABILITY
141 // These seem like they should always be non-null?
142 'blogPHID' => 'phid?',
143 'body' => 'text?',
144 'configData' => 'text?',
146 // T6203/NULLABILITY
147 // This one probably should be nullable?
148 'datePublished' => 'epoch',
150 'interactPolicy' => 'policy',
152 self::CONFIG_KEY_SCHEMA => array(
153 'key_phid' => null,
154 'phid' => array(
155 'columns' => array('phid'),
156 'unique' => true,
158 'bloggerPosts' => array(
159 'columns' => array(
160 'bloggerPHID',
161 'visibility',
162 'datePublished',
163 'id',
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;
192 return $this;
195 public function getHeaderImageFile() {
196 return $this->assertAttached($this->headerImageFile);
200 /* -( PhabricatorPolicyInterface Implementation )-------------------------- */
203 public function getCapabilities() {
204 return array(
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();
222 } else {
223 return PhabricatorPolicies::POLICY_NOONE;
225 break;
226 case PhabricatorPolicyCapability::CAN_EDIT:
227 if ($this->getBlog()) {
228 return $this->getBlog()->getEditPolicy();
229 } else {
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:
245 return false;
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) {
267 switch ($field) {
268 case self::MARKUP_FIELD_BODY:
269 return $this->getBody();
273 public function didMarkupText(
274 $field,
275 $output,
276 PhutilMarkupEngine $engine) {
277 return $output;
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();
304 $this->delete();
305 $this->saveTransaction();
309 /* -( PhabricatorTokenReceiverInterface )---------------------------------- */
312 public function getUsersToNotifyOfTokenGiven() {
313 return array(
314 $this->getBloggerPHID(),
319 /* -( PhabricatorSubscribableInterface Implementation )-------------------- */
322 public function isAutomaticallySubscribed($phid) {
323 return ($this->bloggerPHID == $phid);
327 /* -( PhabricatorConduitResultInterface )---------------------------------- */
330 public function getFieldSpecificationsForConduit() {
331 return array(
332 id(new PhabricatorConduitSearchFieldSpecification())
333 ->setKey('title')
334 ->setType('string')
335 ->setDescription(pht('Title of the post.')),
336 id(new PhabricatorConduitSearchFieldSpecification())
337 ->setKey('slug')
338 ->setType('string')
339 ->setDescription(pht('Slug for the post.')),
340 id(new PhabricatorConduitSearchFieldSpecification())
341 ->setKey('blogPHID')
342 ->setType('phid')
343 ->setDescription(pht('PHID of the blog that the post belongs to.')),
344 id(new PhabricatorConduitSearchFieldSpecification())
345 ->setKey('authorPHID')
346 ->setType('phid')
347 ->setDescription(pht('PHID of the author of the post.')),
348 id(new PhabricatorConduitSearchFieldSpecification())
349 ->setKey('body')
350 ->setType('string')
351 ->setDescription(pht('Body of the post.')),
352 id(new PhabricatorConduitSearchFieldSpecification())
353 ->setKey('datePublished')
354 ->setType('epoch?')
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;
365 } else {
366 $date_published = (int)$this->getDatePublished();
369 return array(
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() {
380 return array();
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();