PageRenderTime 43ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/src/applications/phame/storage/PhamePost.php

http://github.com/facebook/phabricator
PHP | 388 lines | 291 code | 80 blank | 17 comment | 28 complexity | 90967c2d2ccd60f43a9f7afba867e3ac MD5 | raw file
Possible License(s): JSON, MPL-2.0-no-copyleft-exception, Apache-2.0, BSD-3-Clause, LGPL-2.0, MIT, LGPL-2.1, LGPL-3.0
  1. <?php
  2. final class PhamePost extends PhameDAO
  3. implements
  4. PhabricatorPolicyInterface,
  5. PhabricatorMarkupInterface,
  6. PhabricatorFlaggableInterface,
  7. PhabricatorProjectInterface,
  8. PhabricatorApplicationTransactionInterface,
  9. PhabricatorSubscribableInterface,
  10. PhabricatorDestructibleInterface,
  11. PhabricatorTokenReceiverInterface,
  12. PhabricatorConduitResultInterface,
  13. PhabricatorFulltextInterface,
  14. PhabricatorFerretInterface {
  15. const MARKUP_FIELD_BODY = 'markup:body';
  16. const MARKUP_FIELD_SUMMARY = 'markup:summary';
  17. protected $bloggerPHID;
  18. protected $title;
  19. protected $subtitle;
  20. protected $phameTitle;
  21. protected $body;
  22. protected $visibility;
  23. protected $configData;
  24. protected $datePublished;
  25. protected $blogPHID;
  26. protected $mailKey;
  27. protected $headerImagePHID;
  28. private $blog = self::ATTACHABLE;
  29. private $headerImageFile = self::ATTACHABLE;
  30. public static function initializePost(
  31. PhabricatorUser $blogger,
  32. PhameBlog $blog) {
  33. $post = id(new PhamePost())
  34. ->setBloggerPHID($blogger->getPHID())
  35. ->setBlogPHID($blog->getPHID())
  36. ->attachBlog($blog)
  37. ->setDatePublished(PhabricatorTime::getNow())
  38. ->setVisibility(PhameConstants::VISIBILITY_PUBLISHED);
  39. return $post;
  40. }
  41. public function attachBlog(PhameBlog $blog) {
  42. $this->blog = $blog;
  43. return $this;
  44. }
  45. public function getBlog() {
  46. return $this->assertAttached($this->blog);
  47. }
  48. public function getMonogram() {
  49. return 'J'.$this->getID();
  50. }
  51. public function getLiveURI() {
  52. $blog = $this->getBlog();
  53. $is_draft = $this->isDraft();
  54. $is_archived = $this->isArchived();
  55. if (strlen($blog->getDomain()) && !$is_draft && !$is_archived) {
  56. return $this->getExternalLiveURI();
  57. } else {
  58. return $this->getInternalLiveURI();
  59. }
  60. }
  61. public function getExternalLiveURI() {
  62. $id = $this->getID();
  63. $slug = $this->getSlug();
  64. $path = "/post/{$id}/{$slug}/";
  65. $domain = $this->getBlog()->getDomain();
  66. return (string)id(new PhutilURI('http://'.$domain))
  67. ->setPath($path);
  68. }
  69. public function getInternalLiveURI() {
  70. $id = $this->getID();
  71. $slug = $this->getSlug();
  72. $blog_id = $this->getBlog()->getID();
  73. return "/phame/live/{$blog_id}/post/{$id}/{$slug}/";
  74. }
  75. public function getViewURI() {
  76. $id = $this->getID();
  77. $slug = $this->getSlug();
  78. return "/phame/post/view/{$id}/{$slug}/";
  79. }
  80. public function getBestURI($is_live, $is_external) {
  81. if ($is_live) {
  82. if ($is_external) {
  83. return $this->getExternalLiveURI();
  84. } else {
  85. return $this->getInternalLiveURI();
  86. }
  87. } else {
  88. return $this->getViewURI();
  89. }
  90. }
  91. public function getEditURI() {
  92. return '/phame/post/edit/'.$this->getID().'/';
  93. }
  94. public function isDraft() {
  95. return ($this->getVisibility() == PhameConstants::VISIBILITY_DRAFT);
  96. }
  97. public function isArchived() {
  98. return ($this->getVisibility() == PhameConstants::VISIBILITY_ARCHIVED);
  99. }
  100. protected function getConfiguration() {
  101. return array(
  102. self::CONFIG_AUX_PHID => true,
  103. self::CONFIG_SERIALIZATION => array(
  104. 'configData' => self::SERIALIZATION_JSON,
  105. ),
  106. self::CONFIG_COLUMN_SCHEMA => array(
  107. 'title' => 'text255',
  108. 'subtitle' => 'text64',
  109. 'phameTitle' => 'sort64?',
  110. 'visibility' => 'uint32',
  111. 'mailKey' => 'bytes20',
  112. 'headerImagePHID' => 'phid?',
  113. // T6203/NULLABILITY
  114. // These seem like they should always be non-null?
  115. 'blogPHID' => 'phid?',
  116. 'body' => 'text?',
  117. 'configData' => 'text?',
  118. // T6203/NULLABILITY
  119. // This one probably should be nullable?
  120. 'datePublished' => 'epoch',
  121. ),
  122. self::CONFIG_KEY_SCHEMA => array(
  123. 'key_phid' => null,
  124. 'phid' => array(
  125. 'columns' => array('phid'),
  126. 'unique' => true,
  127. ),
  128. 'bloggerPosts' => array(
  129. 'columns' => array(
  130. 'bloggerPHID',
  131. 'visibility',
  132. 'datePublished',
  133. 'id',
  134. ),
  135. ),
  136. ),
  137. ) + parent::getConfiguration();
  138. }
  139. public function save() {
  140. if (!$this->getMailKey()) {
  141. $this->setMailKey(Filesystem::readRandomCharacters(20));
  142. }
  143. return parent::save();
  144. }
  145. public function generatePHID() {
  146. return PhabricatorPHID::generateNewPHID(
  147. PhabricatorPhamePostPHIDType::TYPECONST);
  148. }
  149. public function getSlug() {
  150. return PhabricatorSlug::normalizeProjectSlug($this->getTitle());
  151. }
  152. public function getHeaderImageURI() {
  153. return $this->getHeaderImageFile()->getBestURI();
  154. }
  155. public function attachHeaderImageFile(PhabricatorFile $file) {
  156. $this->headerImageFile = $file;
  157. return $this;
  158. }
  159. public function getHeaderImageFile() {
  160. return $this->assertAttached($this->headerImageFile);
  161. }
  162. /* -( PhabricatorPolicyInterface Implementation )-------------------------- */
  163. public function getCapabilities() {
  164. return array(
  165. PhabricatorPolicyCapability::CAN_VIEW,
  166. PhabricatorPolicyCapability::CAN_EDIT,
  167. );
  168. }
  169. public function getPolicy($capability) {
  170. // Draft and archived posts are visible only to the author and other
  171. // users who can edit the blog. Published posts are visible to whoever
  172. // the blog is visible to.
  173. switch ($capability) {
  174. case PhabricatorPolicyCapability::CAN_VIEW:
  175. if (!$this->isDraft() && !$this->isArchived() && $this->getBlog()) {
  176. return $this->getBlog()->getViewPolicy();
  177. } else if ($this->getBlog()) {
  178. return $this->getBlog()->getEditPolicy();
  179. } else {
  180. return PhabricatorPolicies::POLICY_NOONE;
  181. }
  182. break;
  183. case PhabricatorPolicyCapability::CAN_EDIT:
  184. if ($this->getBlog()) {
  185. return $this->getBlog()->getEditPolicy();
  186. } else {
  187. return PhabricatorPolicies::POLICY_NOONE;
  188. }
  189. }
  190. }
  191. public function hasAutomaticCapability($capability, PhabricatorUser $user) {
  192. // A blog post's author can always view it.
  193. switch ($capability) {
  194. case PhabricatorPolicyCapability::CAN_VIEW:
  195. case PhabricatorPolicyCapability::CAN_EDIT:
  196. return ($user->getPHID() == $this->getBloggerPHID());
  197. }
  198. }
  199. public function describeAutomaticCapability($capability) {
  200. return pht('The author of a blog post can always view and edit it.');
  201. }
  202. /* -( PhabricatorMarkupInterface Implementation )-------------------------- */
  203. public function getMarkupFieldKey($field) {
  204. $content = $this->getMarkupText($field);
  205. return PhabricatorMarkupEngine::digestRemarkupContent($this, $content);
  206. }
  207. public function newMarkupEngine($field) {
  208. return PhabricatorMarkupEngine::newPhameMarkupEngine();
  209. }
  210. public function getMarkupText($field) {
  211. switch ($field) {
  212. case self::MARKUP_FIELD_BODY:
  213. return $this->getBody();
  214. case self::MARKUP_FIELD_SUMMARY:
  215. return PhabricatorMarkupEngine::summarize($this->getBody());
  216. }
  217. }
  218. public function didMarkupText(
  219. $field,
  220. $output,
  221. PhutilMarkupEngine $engine) {
  222. return $output;
  223. }
  224. public function shouldUseMarkupCache($field) {
  225. return (bool)$this->getPHID();
  226. }
  227. /* -( PhabricatorApplicationTransactionInterface )------------------------- */
  228. public function getApplicationTransactionEditor() {
  229. return new PhamePostEditor();
  230. }
  231. public function getApplicationTransactionTemplate() {
  232. return new PhamePostTransaction();
  233. }
  234. /* -( PhabricatorDestructibleInterface )----------------------------------- */
  235. public function destroyObjectPermanently(
  236. PhabricatorDestructionEngine $engine) {
  237. $this->openTransaction();
  238. $this->delete();
  239. $this->saveTransaction();
  240. }
  241. /* -( PhabricatorTokenReceiverInterface )---------------------------------- */
  242. public function getUsersToNotifyOfTokenGiven() {
  243. return array(
  244. $this->getBloggerPHID(),
  245. );
  246. }
  247. /* -( PhabricatorSubscribableInterface Implementation )-------------------- */
  248. public function isAutomaticallySubscribed($phid) {
  249. return ($this->bloggerPHID == $phid);
  250. }
  251. /* -( PhabricatorConduitResultInterface )---------------------------------- */
  252. public function getFieldSpecificationsForConduit() {
  253. return array(
  254. id(new PhabricatorConduitSearchFieldSpecification())
  255. ->setKey('title')
  256. ->setType('string')
  257. ->setDescription(pht('Title of the post.')),
  258. id(new PhabricatorConduitSearchFieldSpecification())
  259. ->setKey('slug')
  260. ->setType('string')
  261. ->setDescription(pht('Slug for the post.')),
  262. id(new PhabricatorConduitSearchFieldSpecification())
  263. ->setKey('blogPHID')
  264. ->setType('phid')
  265. ->setDescription(pht('PHID of the blog that the post belongs to.')),
  266. id(new PhabricatorConduitSearchFieldSpecification())
  267. ->setKey('authorPHID')
  268. ->setType('phid')
  269. ->setDescription(pht('PHID of the author of the post.')),
  270. id(new PhabricatorConduitSearchFieldSpecification())
  271. ->setKey('body')
  272. ->setType('string')
  273. ->setDescription(pht('Body of the post.')),
  274. id(new PhabricatorConduitSearchFieldSpecification())
  275. ->setKey('datePublished')
  276. ->setType('epoch?')
  277. ->setDescription(pht('Publish date, if the post has been published.')),
  278. );
  279. }
  280. public function getFieldValuesForConduit() {
  281. if ($this->isDraft()) {
  282. $date_published = null;
  283. } else if ($this->isArchived()) {
  284. $date_published = null;
  285. } else {
  286. $date_published = (int)$this->getDatePublished();
  287. }
  288. return array(
  289. 'title' => $this->getTitle(),
  290. 'slug' => $this->getSlug(),
  291. 'blogPHID' => $this->getBlogPHID(),
  292. 'authorPHID' => $this->getBloggerPHID(),
  293. 'body' => $this->getBody(),
  294. 'datePublished' => $date_published,
  295. );
  296. }
  297. public function getConduitSearchAttachments() {
  298. return array();
  299. }
  300. /* -( PhabricatorFulltextInterface )--------------------------------------- */
  301. public function newFulltextEngine() {
  302. return new PhamePostFulltextEngine();
  303. }
  304. /* -( PhabricatorFerretInterface )----------------------------------------- */
  305. public function newFerretEngine() {
  306. return new PhamePostFerretEngine();
  307. }
  308. }