The official, canonical postActiv repository. http://www.postactiv.com

rsd.php 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. <?php
  2. /* ============================================================================
  3. * Title: RSD
  4. * Really Simple Discovery (RSD) for API access
  5. *
  6. * postActiv:
  7. * the micro-blogging software
  8. *
  9. * Copyright:
  10. * Copyright (C) 2016-2018, Maiyannah Bishop
  11. *
  12. * Derived from code copyright various sources:
  13. * o GNU Social (C) 2013-2016, Free Software Foundation, Inc
  14. * o StatusNet (C) 2008-2012, StatusNet, Inc
  15. * ----------------------------------------------------------------------------
  16. * License:
  17. * This program is free software: you can redistribute it and/or modify
  18. * it under the terms of the GNU Affero General Public License as published by
  19. * the Free Software Foundation, either version 3 of the License, or
  20. * (at your option) any later version.
  21. *
  22. * This program is distributed in the hope that it will be useful,
  23. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  25. * GNU Affero General Public License for more details.
  26. *
  27. * You should have received a copy of the GNU Affero General Public License
  28. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  29. *
  30. * <https://www.gnu.org/licenses/agpl.html>
  31. * ----------------------------------------------------------------------------
  32. * About:
  33. * Really Simple Discovery (RSD) is a simple (to a fault, maybe) discovery tool
  34. * for blog APIs.
  35. *
  36. * http://tales.phrasewise.com/rfc/rsd
  37. *
  38. * Anil Dash suggested that RSD be used for services that implement
  39. * the Twitter API:
  40. *
  41. * http://dashes.com/anil/2009/12/the-twitter-api-is-finished.html
  42. *
  43. * It's in use now for WordPress.com blogs:
  44. *
  45. * http://matt.wordpress.com/xmlrpc.php?rsd
  46. *
  47. * I (evan@status.net) have tried to stay faithful to the premise of RSD,
  48. * while adding information useful to StatusNet client developers.
  49. *
  50. * In particular:
  51. *
  52. * - There is a link from each user's profile page to their personal
  53. * RSD feed. A personal rsd.xml includes a 'blogID' element that is
  54. * their username.
  55. * - There is a link from the public root to '/rsd.xml', a public RSD
  56. * feed. It's identical to the personal rsd except it doesn't include
  57. * a blogId.
  58. * - I've added a setting to the API to indicate that OAuth support is
  59. * available.
  60. *
  61. * PHP version:
  62. * Tested with PHP 7.0
  63. * ----------------------------------------------------------------------------
  64. * File Authors:
  65. * o Evan Prodromou
  66. * o Siebrand Mazeland <s.mazeland@xs4all.nl>
  67. * o Mikael Nordfeldth <mmn@hethane.se>
  68. * o chimo <chimo@chromic.org>
  69. * o Maiyannah Bishop <maiyannah.bishop@postactiv.com>
  70. *
  71. * Web:
  72. * o postActiv <http://www.postactiv.com>
  73. * o GNU social <https://www.gnu.org/s/social/>
  74. * ============================================================================
  75. */
  76. // This file is formatted so that it provides useful documentation output in
  77. // NaturalDocs. Please be considerate of this before changing formatting.
  78. if (!defined('POSTACTIV')) { exit(1); }
  79. /**
  80. * RSD action class
  81. */
  82. class RsdAction extends Action
  83. {
  84. /**
  85. * Optional attribute for the personal rsd.xml file.
  86. */
  87. var $user = null;
  88. /**
  89. * Prepare the action for use.
  90. *
  91. * Check for a nickname; redirect if non-canonical; if
  92. * not provided, assume public rsd.xml.
  93. *
  94. * @param array $args GET, POST, and URI arguments.
  95. *
  96. * @return boolean success flag
  97. */
  98. function prepare(array $args = array())
  99. {
  100. parent::prepare($args);
  101. // optional argument
  102. $nickname_arg = $this->arg('nickname');
  103. if (empty($nickname_arg)) {
  104. $this->user = null;
  105. } else {
  106. $nickname = common_canonical_nickname($nickname_arg);
  107. // Permanent redirect on non-canonical nickname
  108. if ($nickname_arg != $nickname) {
  109. common_redirect(common_local_url('rsd', array('nickname' => $nickname)), 301);
  110. }
  111. $this->user = User::getKV('nickname', $nickname);
  112. if (empty($this->user)) {
  113. // TRANS: Client error.
  114. $this->clientError(_('No such user.'), 404);
  115. }
  116. }
  117. return true;
  118. }
  119. /**
  120. * Action handler.
  121. *
  122. * Outputs the XML format for an RSD file. May include
  123. * personal information if this is a personal file
  124. * (based on whether $user attribute is set).
  125. *
  126. * @return nothing
  127. */
  128. function handle()
  129. {
  130. header('Content-Type: application/rsd+xml');
  131. $this->startXML();
  132. $rsdNS = 'http://archipelago.phrasewise.com/rsd';
  133. $this->elementStart('rsd', array('version' => '1.0',
  134. 'xmlns' => $rsdNS));
  135. $this->elementStart('service');
  136. // TRANS: Engine name for RSD.
  137. $this->element('engineName', null, _('StatusNet'));
  138. $this->element('engineLink', null, 'http://status.net/');
  139. $this->elementStart('apis');
  140. if (Event::handle('StartRsdListApis', array($this, $this->user))) {
  141. $blogID = (empty($this->user)) ? '' : $this->user->nickname;
  142. $apiAttrs = array('name' => 'Twitter',
  143. 'preferred' => 'true',
  144. 'apiLink' => $this->_apiRoot(),
  145. 'blogID' => $blogID);
  146. $this->elementStart('api', $apiAttrs);
  147. $this->elementStart('settings');
  148. $this->element('docs', null,
  149. common_local_url('doc', array('title' => 'api')));
  150. $this->element('setting', array('name' => 'OAuth'),
  151. 'true');
  152. $this->elementEnd('settings');
  153. $this->elementEnd('api');
  154. // Atom API
  155. if (empty($this->user)) {
  156. $service = common_local_url('ApiAtomService');
  157. } else {
  158. $service = common_local_url('ApiAtomService', array('id' => $this->user->nickname));
  159. }
  160. $this->element('api', array('name' => 'Atom',
  161. 'preferred' => 'false',
  162. 'apiLink' => $service,
  163. 'blogID' => $blogID));
  164. Event::handle('EndRsdListApis', array($this, $this->user));
  165. }
  166. $this->elementEnd('apis');
  167. $this->elementEnd('service');
  168. $this->elementEnd('rsd');
  169. $this->endXML();
  170. return true;
  171. }
  172. /**
  173. * Returns last-modified date for use in caching
  174. *
  175. * Per-user rsd.xml is dated to last change of user
  176. * (in case of nickname change); public has no date.
  177. *
  178. * @return string date of last change of this page
  179. */
  180. function lastModified()
  181. {
  182. if (!empty($this->user)) {
  183. return $this->user->modified;
  184. } else {
  185. return null;
  186. }
  187. }
  188. /**
  189. * Flag to indicate if this action is read-only
  190. *
  191. * It is; it doesn't change the DB.
  192. *
  193. * @param array $args ignored
  194. *
  195. * @return boolean true
  196. */
  197. function isReadOnly($args)
  198. {
  199. return true;
  200. }
  201. /**
  202. * Return current site's API root
  203. *
  204. * Varies based on URL parameters, like if fancy URLs are
  205. * turned on.
  206. *
  207. * @return string API root URI for this site
  208. */
  209. private function _apiRoot()
  210. {
  211. if (common_config('site', 'fancy')) {
  212. return common_path('api/', true);
  213. } else {
  214. return common_path('index.php/api/', true);
  215. }
  216. }
  217. }
  218. // END OF FILE
  219. // ============================================================================
  220. ?>