PageRenderTime 57ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/services/blog.php

https://github.com/altatof/altashop
PHP | 1782 lines | 815 code | 282 blank | 685 comment | 269 complexity | 73cc6027bc788a25d29c9f1aca66bc2f MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * process remote blog calls
  4. *
  5. * @todo use https to secure blogging, as asked for at http://www.dscoduc.com/post/2008/03/Insecure-blogging.aspx
  6. * @todo implement Wordpress API, as in http://trac.wordpress.org/browser/trunk/xmlrpc.php
  7. * @todo improve support of Windows Live Writer as in http://www.andrewgrant.org/keyword-tags
  8. * @todo implement WLW manifest as described in http://msdn2.microsoft.com/en-us/library/bb463266.aspx
  9. *
  10. * This script interfaces YACS with popular weblog client software.
  11. *
  12. * Yacs does support effectively the XML-RPC API.
  13. * Keep in mind that metaWeblog' blogs are YACS sections.
  14. *
  15. * @link http://www.xmlrpc.com/spec XML-RPC specification
  16. *
  17. * At the moment YACS supports following XML-RPC flavors:
  18. * - the Movable Type API
  19. * - the MetaWeblog API
  20. * - the Blogger API
  21. *
  22. * Actually, all three of those API's build on each other.
  23. * Blogger is the most basic. MetaWeblog "embraces and extends" it. The
  24. * Movable Type API does the same to MetaWeblog.
  25. *
  26. *
  27. * [title]Error codes[/title]
  28. *
  29. * YACS uses standard error codes, as specified in [link=Specification for Fault Code Interoperability]http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php[/link]:
  30. * &quot;As the number of xml-rpc server implementations has proliferated, so has the number of error codes and descriptions.
  31. * The charter of this specification is to define a small set of error codes that are common across most server implementations
  32. * so that clients can programmatically handle common errors such as "method not found" or "parse error".&quot;
  33. *
  34. * Here are the error codes and their meaning:
  35. * - -32700 ---> parse error. not well formed
  36. * - -32701 ---> parse error. unsupported encoding
  37. * - -32702 ---> parse error. invalid character for encoding
  38. * - -32600 ---> server error. invalid xml-rpc. not conforming to spec.
  39. * - -32601 ---> server error. requested method not found
  40. * - -32602 ---> server error. invalid method parameters (bad login, etc.)
  41. * - -32603 ---> server error. internal xml-rpc error (no response)
  42. * - -32500 ---> application error (database error)
  43. * - -32400 ---> system error
  44. * - -32300 ---> transport error
  45. *
  46. * @link http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php Specification for Fault Code Interoperability
  47. *
  48. *
  49. * [title]The Movable Type API[/title]
  50. *
  51. * @link http://msdn2.microsoft.com/en-us/library/bb259697.aspx MetaWeblog API Reference, according to Microsoft
  52. * @link http://blog.ustc.edu.cn/mts/docs/mtmanual_programmatic.html
  53. *
  54. *
  55. * [subtitle]mt.getRecentPostTitles[/subtitle]
  56. *
  57. * Returns a bandwidth-friendly list of the most recent posts in the system.
  58. *
  59. * Syntax: mt.getRecentPostTitles(blogid, username, password, numberOfPosts) returns struct
  60. *
  61. * Following components of the struct are correctly processed:
  62. * - dateCreated - ISO 8601
  63. * - userid
  64. * - postid
  65. * - title
  66. *
  67. *
  68. * [subtitle]mt.getCategoryList[/subtitle]
  69. *
  70. * List all categories defined in the weblog.
  71. *
  72. * Syntax: mt.getCategoryList(blogid, username, password) returns struct
  73. *
  74. * In YACS categories are shared at the system level, therefore the blogid parameter is not used.
  75. * Returns up to 30 YACS categories.
  76. *
  77. * Returns following components:
  78. * - categoryId - id of the category
  79. * - categoryName - the name of the category
  80. *
  81. *
  82. * [subtitle]mt.getPostCategories[/subtitle]
  83. *
  84. * List all categories to which the post is assigned.
  85. *
  86. * Syntax: mt.getPostCategories(postid, username, password) returns struct
  87. *
  88. * Returns following components:
  89. * - categoryId - id of the category
  90. * - categoryName - the name of the category
  91. * - isPrimary - 1 if true, 0 otherwise
  92. *
  93. *
  94. * [subtitle]mt.getTrackbackPings[/subtitle]
  95. *
  96. * List pages linked to this post.
  97. *
  98. * Syntax: mt.getTrackbackPings(postid) returns struct
  99. *
  100. * Returns following components:
  101. * - pingTitle - title of the entry sent in the ping
  102. * - pingUrl - the URL of the entry
  103. * - pingIP - the IP address of the host that sent the ping
  104. *
  105. *
  106. * [subtitle]mt.publishPost[/subtitle]
  107. *
  108. * Publish (rebuild) all of the static files related to an entry from your weblog. Equivalent to saving an entry in the system (but without the ping).
  109. *
  110. * Syntax: mt.publishPost(postid, username, password) returns boolean
  111. *
  112. *
  113. * [subtitle]mt.setPostCategories[/subtitle]
  114. *
  115. * Assign categories to a post.
  116. *
  117. * Syntax: mt.setPostCategories(postid, username, password, struct) returns boolean
  118. *
  119. * The struct has following components:
  120. * - categoryId - id of the category
  121. * - isPrimary - 1 if true, 0 otherwise (option)
  122. *
  123. *
  124. * [subtitle]mt.supportedMethods[/subtitle]
  125. *
  126. * Retrieve information about the XML-RPC methods supported by the server.
  127. *
  128. * Syntax: mt.supportedMethods() returns array of strings
  129. *
  130. *
  131. * [title]The MetaWeblog API[/title]
  132. *
  133. * The MetaWeblog API is a programming interface that allows external programs
  134. * to get and set the text and attributes of weblog posts. It builds on the
  135. * popular XML-RPC communication protocol, with implementations available
  136. * in many popular programming environments.
  137. *
  138. * @link http://www.xmlrpc.com/metaWeblogApi The MetaWeblog API
  139. *
  140. * The MetaWeblog API uses an XML-RPC struct to represent a weblog post. Rather
  141. * than invent a new vocabulary for the metadata of a weblog post, this uses the
  142. * vocabulary for an item in RSS 2.0. So you can refer to a post's title, link
  143. * and description; or its author, comments, enclosure, guid, etc using the
  144. * already-familiar names given to those elements in RSS 2.0.
  145. *
  146. * @link http://blogs.law.harvard.edu/tech/rss RSS 2.0 Specification
  147. *
  148. *
  149. * [subtitle]metaWeblog.editPost[/subtitle]
  150. *
  151. * Modify or publish an existing post.
  152. *
  153. * Syntax: metaWeblog.editPost(postid, username, password, struct, publish) returns true
  154. *
  155. * Following components of the struct are correctly processed:
  156. * - title - set the page title
  157. * - source (a sub-component of the 'description' field) - set the page source, usually, an originating URL
  158. * - introduction (a sub-component of the 'description' field) - set the page introduction
  159. * - description - set the actual page content
  160. * - category - link this page to listed categories
  161. *
  162. * If the publish field is set to TRUE, the publication mechanism of YACS applies.
  163. *
  164. *
  165. * [subtitle]metaWeblog.deletePost[/subtitle]
  166. *
  167. * An alias for blogger.deletePost
  168. *
  169. * @link http://www.xmlrpc.com/stories/storyReader$2460 Rounding out the MetaWeblog API
  170. *
  171. *
  172. * [subtitle]metaWeblog.getCategories[/subtitle]
  173. *
  174. * List categories for a given blog.
  175. *
  176. * Syntax: metaWeblog.getCategories(blogid, username, password) returns struct
  177. *
  178. * In YACS categories are shared at the system level, therefore the blogid parameter is not used.
  179. * Returns up to 30 YACS categories.
  180. *
  181. * Returns following components:
  182. * - categoryId - id of the category
  183. * - categoryName - the name of the category
  184. * - description - category description
  185. * - rssUrl - reference of the RSS feed for the category
  186. * - htmlUrl - reference of the category web page
  187. *
  188. *
  189. * [subtitle]metaWeblog.getPost[/subtitle]
  190. *
  191. * Read one post. Returns the post if successful, or a fault otherwise.
  192. *
  193. * Syntax: metaWeblog.getPost(postid, username, password) returns struct
  194. *
  195. * Returns following components:
  196. * - title - page title
  197. * - link - the web address to get the original page
  198. * - permaLink - the web address to get the original page
  199. * - description - the actual page content - with 'introduction' and 'source' sub components
  200. * - author - mail address of the page creator
  201. * - comments - the web address to comment the page
  202. * - dateCreated - date of last edition (ISO 8601)
  203. * - userid - id of last editor
  204. * - postid - page id
  205. *
  206. * Six Apart extensions:
  207. * String mt_excerpt, String mt_text_more, int mt_allow_comments, int mt_allow_pings, String mt_convert_breaks, String mt_keywords;
  208. *
  209. * [subtitle]metaWeblog.getRecentPosts[/subtitle]
  210. *
  211. * List most recent posts at a given blog.
  212. *
  213. * Syntax: metaWeblog.getRecentPosts(blogid, username, password, numberOfPosts) returns array of structs
  214. *
  215. * Each post has following components:
  216. * - dateCreated - date of last edition
  217. * - userid - id of last editor
  218. * - postid - page id
  219. * - title - page title
  220. * - link - the web address to get the original page
  221. * - permaLink - the web address to get the original page
  222. * - description - the actual page content - with 'introduction' and 'source' sub components
  223. * - author - mail address of the page creator
  224. * - comments - the web address to comment the page
  225. * - pubDate - publication date, if any
  226. * - category - list of related categories, if any
  227. *
  228. * Returns up to 30 posts from the target blog.
  229. *
  230. * [subtitle]metaWeblog.getUsersBlogs[/subtitle]
  231. *
  232. * An alias for blogger.getUsersBlogs
  233. *
  234. * @link http://www.xmlrpc.com/stories/storyReader$2460 Rounding out the MetaWeblog API
  235. *
  236. * [subtitle]metaWeblog.getTemplate[/subtitle]
  237. *
  238. * An alias for blogger.getTemplate
  239. *
  240. * @link http://www.xmlrpc.com/stories/storyReader$2460 Rounding out the MetaWeblog API
  241. *
  242. * [subtitle]metaWeblog.newMediaObject[/subtitle]
  243. *
  244. * Upload some file to a blog. If successful, the method will return a URL to
  245. * the newly created file. Otherwise, a fault will be returned.
  246. *
  247. * Please note that the data model with this API is to attach
  248. * files to the blog, where YACS offers to attach files to final pages.
  249. *
  250. * Syntax: metaWeblog.newMediaObject(blogid, username, password, struct) returns struct
  251. *
  252. * The submitted struct has following attributes:
  253. * - name - file name
  254. * - type - media type of the file (e.g., text/html) - can be safely ignored
  255. * - bits - the base64-encoded contents of the file
  256. *
  257. * The returned structure has only one attribute:
  258. * - url (to be used to access uploaded file)
  259. *
  260. *
  261. * [subtitle]metaWeblog.newPost[/subtitle]
  262. *
  263. * Create a new post, and optionally publishes it. If the post is successful,
  264. * this method will return the id assigned to the post by the server.
  265. * Otherwise, it will return a fault.
  266. *
  267. * Syntax: metaWeblog.newPost(blogid, username, password, struct, publish) returns string
  268. *
  269. * Following components of the struct are processed:
  270. * - title - set the page title
  271. * - source (a sub-component of the 'description' field) - set the page source, usually, an originating URL
  272. * - introduction (a sub-component of the 'description' field) - set the page introduction
  273. * - description - set the actual page content
  274. * - categories - link this page to listed categories
  275. *
  276. * If the publish field is set to TRUE, the publication mechanism of YACS applies.
  277. *
  278. * [subtitle]metaWeblog.setTemplate[/subtitle]
  279. *
  280. * An alias for blogger.setTemplate
  281. *
  282. * @link http://www.xmlrpc.com/stories/storyReader$2460 Rounding out the MetaWeblog API
  283. *
  284. *
  285. * [title]The Blogger API[/title]
  286. *
  287. * @link http://www.sixapart.com/developers/xmlrpc/blogger_api/ Six Apart definition of the Blogger API
  288. * [subtitle]blogger.deletePost[/subtitle]
  289. *
  290. * Definitely suppress an existing post. Method will return true if successful
  291. * or a fault otherwise.
  292. *
  293. * Syntax: blogger.deletePost(ignored_appkey, postid, username, password) returns boolean
  294. *
  295. *
  296. * [subtitle]blogger.editPost[/subtitle]
  297. *
  298. * Modify or publish an existing post. If the request is successful then the
  299. * method will return true, otherwise it will return a fault.
  300. *
  301. * Syntax: blogger.editPost(ignored_appkey, postid, username, password, content, publish) returns boolean
  302. *
  303. * The content field can include following HTML tags:
  304. * - source - set the page source, usually, an originating URL
  305. * - introduction - set the page introduction
  306. *
  307. * If the publish field is set to TRUE, the publication mechanism YACS is correctly used
  308. *
  309. * @link http://www.blogger.com/developers/api/1_docs/xmlrpc_editPost.html blogger.editPost, from Blogger API 1.0
  310. *
  311. *
  312. * [subtitle]blogger.getPost[/subtitle]
  313. *
  314. * Read one post.
  315. *
  316. * Syntax: blogger.getPost(ignored_appkey, postid, username, password) returns struct
  317. *
  318. * Returns following components:
  319. * - dateCreated - date of last edition
  320. * - userid - id of last editor
  321. * - postid - page id
  322. * - content - the actual page content - with 'introduction' and 'source' sub components
  323. *
  324. *
  325. * [subtitle]blogger.getRecentPosts[/subtitle]
  326. *
  327. * Retrieves a list of posts that were created recently in a blog. The results
  328. * are returned in descending chronolocial order with the most recent post
  329. * first in the list.
  330. *
  331. * Syntax: blogger.getRecentPosts(ignored_appkey, blogid, username, password, numberOfPosts) returns array of structs
  332. *
  333. * Returns up to 30 posts of the mentioned blog.
  334. *
  335. * Each returned post has following components:
  336. * - dateCreated - date of last edition
  337. * - userid - id of last editor
  338. * - postid - page id
  339. * - content - the actual page content - with 'introduction' and 'source' sub components
  340. *
  341. *
  342. * [subtitle]blogger.getTemplate[/subtitle]
  343. *
  344. * Read one template.
  345. *
  346. * Syntax: blogger.getTemplate(ignored_appkey, blogid, username, password, template_type) returns string
  347. *
  348. * Template type can be either 'main' or 'archiveIndex'.
  349. *
  350. * If the target section does have a template attribute, it is returned to caller.
  351. * Else a bare and simple template is returned instead.
  352. *
  353. * @link http://www.blogger.com/developers/api/1_docs/xmlrpc_getTemplate.html blogger.getTemplate from Blogger API 1.0
  354. *
  355. *
  356. * [subtitle]blogger.getUserInfo[/subtitle]
  357. *
  358. * If the user specified by the supplied username and password is found, then
  359. * the method returns information about that user, specifically: the user’s id,
  360. * first name, last name, nickname, e-mail address and URL. If the user is not
  361. * found, or their is an error processing the request then the method will
  362. * return a fault.
  363. *
  364. * Syntax: blogger.getUserInfo(ignored_appkey, username, password) returns an array
  365. *
  366. * Returns following attributes:
  367. * - userid
  368. * - nickname - the nick name
  369. * - firstname - actually, the nick name
  370. * - lastname - actually, the full name
  371. * - email - the email address
  372. * - url - the web address
  373. *
  374. * @link http://www.blogger.com/developers/api/1_docs/xmlrpc_getUserInfo.html blogger.getUserInfo from Blogger API 1.0
  375. *
  376. *
  377. * [subtitle]blogger.getUsersBlogs[/subtitle]
  378. *
  379. * List blogs allowed for one user profile.
  380. * Assigned sections are listed first, as a convenient mean to access areas with
  381. * explicit editorial responsibilities. Then up to 9 top-level sections are
  382. * listed, with up to 9 sub-sections for each of them.
  383. * This provide a hierarchical view of the site map through XML-RPC.
  384. * Also, items are numbered to ensure proper sorting of items in w.bloggar.
  385. *
  386. * Syntax: blogger.getUsersBlogs(ignored_appkey, username, password) returns an array
  387. *
  388. * On success this function returns an array of struct containing following
  389. * attributes:
  390. * - url (of the blog/section)
  391. * - blogid
  392. * - blogName (actually, the section title)
  393. *
  394. * @link http://www.blogger.com/developers/api/1_docs/xmlrpc_getUsersBlogs.html blogger.getUsersBlogs from Blogger API 1.0
  395. *
  396. *
  397. * [subtitle]blogger.newPost[/subtitle]
  398. *
  399. * Creates a new post on the designated blog. If the publish parameter is set to
  400. * true then the post will be published on the weblog as well, otherwise the
  401. * post will be created and be kept in draft mode, except at auto_publish web
  402. * spaces. If the post is successfully created, the method will return the id
  403. * of the newly created post. Otherwise, the method will return a fault.
  404. *
  405. * Syntax: blogger.newPost(ignored_appkey, blogid, username, password, content, publish) returns string
  406. *
  407. * The content field can include following HTML tags:
  408. * - source - set the page source, usually, an originating URL
  409. * - introduction - set the page introduction
  410. *
  411. * If the publish field is set to TRUE, the publication mechanism of YACS is correctly used.
  412. *
  413. * @link http://www.blogger.com/developers/api/1_docs/xmlrpc_newPost.html blogger.newPost, from Blogger API 1.0
  414. *
  415. *
  416. * [subtitle]blogger.setTemplate[/subtitle]
  417. *
  418. * Change one template.
  419. *
  420. * Syntax: blogger.setTemplate(ignored_appkey, blogid, username, password, template_content, template_type) returns true or false
  421. *
  422. * Template type can be either 'main' or 'archiveIndex'.
  423. *
  424. * YACS only supports the type 'index'. Other types are silently ignored.
  425. *
  426. * The template is translated as a PHP YACS skin (i.e., [code]template.php[/code] and [code]skin.php[/code])
  427. * and the skin name is [code]section_&lt;blogid&gt;[/code].
  428. *
  429. * The provided template text is saved as a section attribute, for later retrieval
  430. * through calls to [code]blogger.getTemplate[/code].
  431. *
  432. * @link http://www.blogger.com/developers/api/1_docs/xmlrpc_setTemplate.html blogger.setTemplate from Blogger API 1.0
  433. *
  434. *
  435. *
  436. * @author Bernard Paques
  437. * @tester Marcelo L. L. Cabral
  438. * @tester Pat
  439. * @reference
  440. * @license http://www.gnu.org/copyleft/lesser.txt GNU Lesser General Public License
  441. *
  442. * @see services/blog_test.php
  443. * @see services/configure.php
  444. *
  445. */
  446. include_once '../shared/global.php';
  447. include_once '../articles/article.php';
  448. include_once '../links/links.php';
  449. include_once '../sections/section.php';
  450. include_once '../versions/versions.php';
  451. // at the moment, do not send utf-8 to w.bloggar -- keep unicode entities as-is
  452. if(preg_match('/w\.bloggar/', $_SERVER['HTTP_USER_AGENT']))
  453. $context['charset'] = 'iso-8859-15';
  454. // load a skin engine
  455. load_skin('services');
  456. // process raw content
  457. $raw_data = file_get_contents("php://input");
  458. // save the raw request if debug mode
  459. if(isset($context['debug_blog']) && ($context['debug_blog'] == 'Y'))
  460. Logger::remember('services/blog.php', 'blog request', rawurldecode($raw_data), 'debug');
  461. // load the adequate codec
  462. include_once 'codec.php';
  463. include_once 'xml_rpc_codec.php';
  464. $codec = new xml_rpc_Codec();
  465. // regular decoding
  466. if(isset($raw_data) && $raw_data) {
  467. // parse xml parameters -- use rawurldecode() instead urldecode(), else you will loose + signs
  468. $result = $codec->import_request(rawurldecode($raw_data));
  469. $status = @$result[0];
  470. $parameters = @$result[1];
  471. // we also accept REST calls, at least for debugging
  472. } else {
  473. $status = TRUE;
  474. $parameters = $_REQUEST;
  475. }
  476. // nothing to do on HEAD --see scripts/validate.php
  477. if(isset($_SERVER['REQUEST_METHOD']) && ($_SERVER['REQUEST_METHOD'] == 'HEAD'))
  478. return;
  479. // nothing to parse
  480. if(!isset($parameters) || !is_array($parameters) || !count($parameters) || !isset($parameters['methodName']) || !$parameters['methodName']) {
  481. if(isset($context['debug_blog']) && ($context['debug_blog'] == 'Y'))
  482. Logger::remember('services/blog.php', 'blog request', 'nothing to process', 'debug');
  483. $response = array('faultCode' => -32700, 'faultString' => 'Empty request, please retry');
  484. // parse has failed
  485. } elseif(!$status)
  486. $response = array('faultCode' => -32700, 'faultString' => 'Impossible to parse parameters');
  487. // dispatch the request
  488. else {
  489. // remember parameters if debug mode
  490. if(isset($context['debug_blog']) && ($context['debug_blog'] == 'Y'))
  491. Logger::remember('services/blog.php', 'blog '.$parameters['methodName'], isset($parameters['params'])?$parameters['params']:'', 'debug');
  492. // depending on method name
  493. switch($parameters['methodName']) {
  494. // delete a post
  495. case 'blogger.deletePost':
  496. case 'metaWeblog.deletePost':
  497. list($ignored_appkey, $postid, $username, $password) = $parameters['params'];
  498. // get items from the database
  499. if($item =& Articles::get($postid))
  500. $anchor =& Anchors::get($item['anchor']);
  501. // check user
  502. $user = Users::login($username, $password);
  503. if(!isset($user['id']))
  504. $response = array( 'faultCode' => -32602, 'faultString' => sprintf(i18n::c('Please register at %s before blogging'), $context['url_to_home']) );
  505. // check if article exists
  506. elseif(!isset($item['id']))
  507. $response = array( 'faultCode' => -32602, 'faultString' => sprintf(i18n::c('Unknown postid %s at %s'), $postid, $context['url_to_home']) );
  508. else {
  509. // surfer may be an associate
  510. Surfer::empower($user['capability']);
  511. // surfer is a section editor
  512. if(Surfer::is_member($user['capability']) && is_object($anchor) && $anchor->is_assigned($user['id']))
  513. Surfer::empower();
  514. // surfer is a page editor
  515. elseif(Articles::is_owned($item, $anchor))
  516. Surfer::empower();
  517. // operation is restricted
  518. if(!Surfer::is_empowered())
  519. $response = array( 'faultCode' => -32602, 'faultString' => i18n::c('You are not allowed to perform this operation.') );
  520. // delete the article
  521. elseif(!Articles::delete($item['id']))
  522. $response = array( 'faultCode' => -32500, 'faultString' => sprintf(i18n::c('Impossible to delete record of postid %s'), $postid) );
  523. else {
  524. Cache::clear();
  525. $response = TRUE;
  526. }
  527. }
  528. break;
  529. // update the information about an existing post
  530. case 'blogger.editPost':
  531. list($ignored_appkey, $postid, $username, $password, $content, $publish) = $parameters['params'];
  532. // get items from the database
  533. if($item =& Articles::get($postid))
  534. $anchor =& Anchors::get($item['anchor']);
  535. // check user
  536. $user = Users::login($username, $password);
  537. if(!isset($user['id']))
  538. $response = array( 'faultCode' => -32602, 'faultString' => sprintf(i18n::c('Please register at %s before blogging'), $context['url_to_home']) );
  539. // ensure the article actually exists
  540. elseif(!isset($item['id']))
  541. $response = array( 'faultCode' => -32602, 'faultString' => sprintf(i18n::c('Unknown postid %s at %s'), $postid, $context['url_to_home']) );
  542. else {
  543. // remember this surfer
  544. Surfer::set($user);
  545. // surfer may be an associate
  546. Surfer::empower($user['capability']);
  547. // surfer is a section editor
  548. if(Surfer::is_member($user['capability']) && is_object($anchor) && $anchor->is_assigned($user['id']))
  549. Surfer::empower();
  550. // surfer is a page editor
  551. elseif(Articles::is_assigned($item['id'], $user['id']))
  552. Surfer::empower();
  553. // operation is restricted
  554. if(!Surfer::is_empowered())
  555. $response = array( 'faultCode' => -32602, 'faultString' => i18n::c('You are not allowed to perform this operation.') );
  556. else {
  557. // remember the previous version
  558. Versions::save($item, 'article:'.$item['id']);
  559. // parse article content
  560. $article = new Article();
  561. $fields = $article->parse($content, $item);
  562. // publish if in wiki mode, or if section is configured for auto-publishing,
  563. // or if the surfer asks for it and add sufficient rights
  564. if( ($context['users_with_auto_publish'] == 'Y')
  565. || (is_object($anchor) && $anchor->has_option('auto_publish'))
  566. || ($publish && Articles::allow_publication($anchor, $item)) ) {
  567. $fields['publish_name'] = $user['nick_name'];
  568. $fields['publish_id'] = $user['id'];
  569. $fields['publish_address'] = $user['email'];
  570. $fields['publish_date'] = gmstrftime('%Y-%m-%d %H:%M:%S');
  571. }
  572. $fields['edit_name'] = $user['nick_name'];
  573. $fields['edit_id'] = $user['id'];
  574. $fields['edit_address'] = $user['email'];
  575. $fields['edit_date'] = gmstrftime('%Y-%m-%d %H:%M:%S');
  576. // update the article
  577. if(!Articles::put($fields))
  578. $response = array( 'faultCode' => -32500, 'faultString' => sprintf(i18n::c('Impossible to update record of postid %s'), $postid) );
  579. else {
  580. $response = TRUE;
  581. // if the page has been published
  582. if($fields['publish_date'] > NULL_DATE) {
  583. // advertise public pages
  584. if(($section['active'] == 'Y') && ($item['active'] == 'Y')) {
  585. // pingback, if any
  586. Links::ping($fields['introduction'].' '.$fields['source'].' '.$fields['description'], 'article:'.$postid);
  587. }
  588. // 'publish' hook
  589. if(is_callable(array('Hooks', 'include_scripts')))
  590. Hooks::include_scripts('publish', $item['id']);
  591. }
  592. // list the article in categories
  593. $keywords = '';
  594. if(isset($fields['tags']))
  595. $keywords = $fields['tags'];
  596. if(isset($content['mt_keywords']))
  597. $keywords .= ', '.$content['mt_keywords'];
  598. $keywords = trim($keywords, ', ');
  599. Categories::remember('article:'.$item['id'], isset($fields['publish_date']) ? $fields['publish_date'] : NULL_DATE, $keywords);
  600. }
  601. }
  602. }
  603. break;
  604. // get a single post
  605. case 'blogger.getPost':
  606. list($ignored_appkey, $postid, $username, $password) = $parameters['params'];
  607. // get item from the database
  608. if($item =& Articles::get($postid))
  609. $anchor =& Anchors::get($item['anchor']);
  610. // check user
  611. $user = Users::login($username, $password);
  612. if(!isset($user['id']))
  613. $response = array( 'faultCode' => -32602, 'faultString' => sprintf(i18n::c('Please register at %s before blogging'), $context['url_to_home']) );
  614. // check the article actually exists
  615. elseif(!isset($item['id']))
  616. $response = array( 'faultCode' => -32602, 'faultString' => sprintf(i18n::c('Unknown postid %s at %s'), $postid, $context['url_to_home']) );
  617. // unknown anchor
  618. elseif(!is_object($anchor))
  619. $response = array( 'faultCode' => -32602, 'faultString' => i18n::c('You are not allowed to perform this operation.') );
  620. else {
  621. // surfer may be an associate
  622. Surfer::empower($user['capability']);
  623. // surfer is an associate
  624. if($user['capability'] == 'A')
  625. $permitted = TRUE;
  626. // public page
  627. elseif(($item['active'] == 'Y') && $anchor->is_viewable($user['id']))
  628. $permitted = TRUE;
  629. // restricted page
  630. elseif(($item['active'] == 'R') && $anchor->is_viewable($user['id']))
  631. $permitted = TRUE;
  632. // hidden page
  633. elseif(($item['active'] == 'N') && $anchor->is_assigned($user['id']))
  634. $permitted = TRUE;
  635. // assigned page
  636. elseif(Articles::is_assigned($item['id'], $user['id']))
  637. $permitted = TRUE;
  638. // sorry
  639. else
  640. $permitted = FALSE;
  641. // restrict gets in protected section
  642. if(!$permitted)
  643. $response = array( 'faultCode' => -32602, 'faultString' => i18n::c('You are not allowed to perform this operation.') );
  644. else {
  645. // page title - don't put a carriage return at the end, w.bloggar will keep it
  646. $content = '<title>'.$item['title'].'</title>';
  647. // edit the introduction if one exists
  648. if($item['introduction'])
  649. $content .= '<introduction>'.$item['introduction']."</introduction>\n";
  650. // edit the source if one exists
  651. if($item['source'])
  652. $content .= '<source>'.$item['source']."</source>\n";
  653. // page content
  654. $content .= $item['description'];
  655. // build the complete response
  656. $response = array(
  657. 'dateCreated' => $codec->encode($item['edit_date'], 'date'),
  658. 'userid' => $codec->encode($item['edit_id'], 'string'),
  659. 'postid' => $codec->encode((string)$item['id'], 'string'),
  660. 'content' => $codec->encode($content, 'string')
  661. );
  662. }
  663. }
  664. break;
  665. // return a list of the most recent posts in a blog
  666. case 'blogger.getRecentPosts':
  667. list($ignored_appkey, $blogid, $username, $password, $numberOfPosts) = $parameters['params'];
  668. // get item from the database
  669. if($item =& Sections::get($blogid)) {
  670. $section = new Section();
  671. $section->load_by_content($item);
  672. }
  673. // check user
  674. $user = Users::login($username, $password);
  675. if(!isset($user['id']))
  676. $response = array( 'faultCode' => -32602, 'faultString' => sprintf(i18n::c('Please register at %s before blogging'), $context['url_to_home']) );
  677. // check the section id
  678. elseif(!isset($item['id']))
  679. $response = array( 'faultCode' => -32602, 'faultString' => sprintf(i18n::c('Unknown blog %s at %s'), $blogid, $context['url_to_home']) );
  680. // not accessible
  681. elseif(($user['capability'] != 'A') && !$section->is_viewable($user['id']))
  682. $response = array( 'faultCode' => -32602, 'faultString' => i18n::c('You are not allowed to perform this operation.') );
  683. // list articles
  684. else {
  685. // surfer may be an associate
  686. Surfer::empower($user['capability']);
  687. // surfer is a section editor
  688. if(Surfer::is_member($user['capability']) && is_object($section) && $section->is_assigned($user['id']))
  689. Surfer::empower();
  690. // surfer is a page editor
  691. elseif(Articles::is_assigned($item['id'], $user['id']))
  692. Surfer::empower();
  693. $response = array();
  694. $items =& Articles::list_for_anchor_by('edition', 'section:'.$blogid, 0, min($numberOfPosts, 30), 'raw');
  695. if(is_array($items)) {
  696. foreach($items as $id => $item) {
  697. // page title - don't put a carriage return at the end, w.bloggar will keep it
  698. $content = '<title>'.$item['title'].'</title>';
  699. // edit the introduction if one exists
  700. if($item['introduction'])
  701. $content .= '<introduction>'.$item['introduction']."</introduction>\n";
  702. // edit the source if one exists
  703. if($item['source'])
  704. $content .= '<source>'.$item['source']."</source>\n";
  705. // page content
  706. $content .= $item['description'];
  707. // build the complete response
  708. $response[] = array(
  709. 'dateCreated' => $codec->encode($item['edit_date'], 'date'),
  710. 'userid' => $codec->encode($item['edit_id'], 'string'),
  711. 'postid' => $codec->encode((string)$id, 'string'),
  712. 'content' => $codec->encode($content, 'string')
  713. );
  714. }
  715. }
  716. }
  717. break;
  718. // return the template attached to a blog
  719. case 'blogger.getTemplate':
  720. case 'metaWeblog.getTemplate':
  721. list($ignored_appkey, $blogid, $username, $password, $type) = $parameters['params'];
  722. // get item from the database
  723. if($item =& Sections::get($blogid)) {
  724. $section = new Section();
  725. $section->load_by_content($item);
  726. }
  727. // check user
  728. $user = Users::login($username, $password);
  729. if(!isset($user['id']))
  730. $response = array( 'faultCode' => -32602, 'faultString' => sprintf(i18n::c('Please register at %s before blogging'), $context['url_to_home']) );
  731. // check the section id
  732. elseif(!isset($item['id']))
  733. $response = array( 'faultCode' => -32602, 'faultString' => sprintf(i18n::c('Unknown blog %s at %s'), $blogid, $context['url_to_home']) );
  734. // restrict access to associates and editors
  735. elseif(($user['capability'] != 'A') && !$section->is_assigned($user['id']))
  736. $response = array( 'faultCode' => -32602, 'faultString' => i18n::c('You are not allowed to perform this operation.') );
  737. // provide the existing template
  738. elseif($section['template'])
  739. $response = $section['template'];
  740. // create a dummy template
  741. else
  742. $response = '<html><head><title><$BlogTitle$></title></head><body><Blogger><BlogDateHeader><h1><$BlogDateHeaderDate$></h1></BlogDateHeader><$BlogItemBody$><br></Blogger></body></html>';
  743. // strip DOCTYPE, etc.
  744. if(preg_match('/<html>.+<\/html>/si', $response, $matches))
  745. $response = $matches[0];
  746. break;
  747. // return information about an author in the system
  748. case 'blogger.getUserInfo':
  749. list($ignored_appkey, $username, $password) = $parameters['params'];
  750. // check user
  751. $user = Users::login($username, $password);
  752. if(!isset($user['id']))
  753. $response = array( 'faultCode' => -32602, 'faultString' => sprintf(i18n::c('Please register at %s before blogging'), $context['url_to_home']) );
  754. else {
  755. $item =& Users::get($username);
  756. if($item['id'])
  757. $response = array(
  758. 'userid' => (string)$item['id'],
  759. 'nickname' => $item['nick_name'],
  760. 'firstname' => $item['nick_name'],
  761. 'lastname' => $item['full_name'],
  762. 'email' => $item['email'],
  763. 'url' => ''.$context['url_to_home']
  764. );
  765. else
  766. $response = array( 'faultCode' => -32602, 'faultString' => i18n::s('Unknown user name'));
  767. }
  768. break;
  769. // return a list of weblogs to which an author has posting privileges
  770. case 'blogger.getUsersBlogs':
  771. case 'metaWeblog.getUsersBlogs':
  772. if(isset($parameters['params']) && is_array($parameters['params']))
  773. list($ignored_appkey, $username, $password) = $parameters['params'];
  774. else {
  775. $username = isset($parameters['user'])?$parameters['user']:'';
  776. $password = isset($parameters['password'])?$parameters['password']:'';
  777. }
  778. // check user
  779. $user = Users::login($username, $password);
  780. if(!isset($user['id']))
  781. $response = array( 'faultCode' => -32602, 'faultString' => sprintf(i18n::c('Please register at %s before blogging'), $context['url_to_home']) );
  782. // list blogs
  783. else {
  784. $response = array();
  785. // prefix to ensure proper ordering
  786. $index = 1;
  787. // list assigned sections, if any
  788. if(($assigned = Surfer::assigned_sections($user['id'], 9)) && count($assigned)) {
  789. foreach($assigned as $assigned_id) {
  790. if($section =& Anchors::get('section:'.$assigned_id)) {
  791. $response[] = array(
  792. 'isAdmin' => '<boolean>1</boolean>',
  793. 'url' => '<string>'.$context['url_to_home'].$context['url_to_root'].$section->get_url().'</string>',
  794. 'blogid' => '<string>'.(string)$assigned_id.'</string>',
  795. 'blogName' => $codec->encode(strip_tags($section->get_title()), 'string')
  796. );
  797. $index++;
  798. }
  799. }
  800. }
  801. // provide default section
  802. if($default_id = Sections::get_default()) {
  803. if($section =& Anchors::get('section:'.$default_id)) {
  804. $response[] = array(
  805. 'isAdmin' => '<boolean>0</boolean>',
  806. 'url' => '<string>'.$context['url_to_home'].$context['url_to_root'].$section->get_url().'</string>',
  807. 'blogid' => '<string>'.(string)$default_id.'</string>',
  808. 'blogName' => $codec->encode(strip_tags($section->get_title()), 'string')
  809. );
  810. $index++;
  811. }
  812. }
  813. }
  814. break;
  815. // create a new post, and optionally publish it
  816. case 'blogger.newPost':
  817. list($ignored_appkey, $blogid, $username, $password, $content, $publish) = $parameters['params'];
  818. // get item from the database
  819. if($item =& Sections::get($blogid)) {
  820. $section = new Section();
  821. $section->load_by_content($item);
  822. }
  823. // check user
  824. $user = Users::login($username, $password);
  825. if(!isset($user['id']))
  826. $response = array( 'faultCode' => -32602, 'faultString' => sprintf(i18n::c('Please register at %s before blogging'), $context['url_to_home']) );
  827. // check the section id
  828. elseif(!isset($item['id']))
  829. $response = array( 'faultCode' => -32602, 'faultString' => sprintf(i18n::c('Unknown blog %s at %s'), $blogid, $context['url_to_home']) );
  830. // not accessible
  831. elseif(($user['capability'] != 'A') && !$section->is_viewable($user['id']))
  832. $response = array( 'faultCode' => -32602, 'faultString' => i18n::c('You are not allowed to perform this operation.') );
  833. // hidden section
  834. elseif(($user['capability'] != 'A') && ($item['active'] == 'N') && !$section->is_assigned($user['id']))
  835. $response = array( 'faultCode' => -32602, 'faultString' => i18n::c('You are not allowed to perform this operation.') );
  836. // locked section
  837. elseif(($item['locked'] == 'Y') && ($user['capability'] != 'A') && !$section->is_assigned($user['id']))
  838. $response = array( 'faultCode' => -32602, 'faultString' => i18n::c('You are not allowed to perform this operation.') );
  839. else {
  840. Surfer::set($user);
  841. // parse article content
  842. $article = new Article();
  843. $fields = $article->parse($content, $content);
  844. // build fields
  845. $fields['anchor'] = 'section:'.$item['id'];
  846. $fields['source'] = 'blog';
  847. $fields['create_name'] = $user['nick_name'];
  848. $fields['create_id'] = $user['id'];
  849. $fields['create_address'] = $user['email'];
  850. $fields['create_date'] = gmstrftime('%Y-%m-%d %H:%M:%S');
  851. // publish if in wiki mode, or if section is configured for auto-publishing,
  852. // or if the surfer asks for it and add sufficient rights
  853. if( ($context['users_with_auto_publish'] == 'Y')
  854. || (is_object($section) && $section->has_option('auto_publish'))
  855. || ($publish && Articles::allow_publication($anchor, $item)) ) {
  856. $fields['publish_name'] = $user['nick_name'];
  857. $fields['publish_id'] = $user['id'];
  858. $fields['publish_address'] = $user['email'];
  859. $fields['publish_date'] = gmstrftime('%Y-%m-%d %H:%M:%S');
  860. }
  861. $fields['edit_name'] = $user['nick_name'];
  862. $fields['edit_id'] = $user['id'];
  863. $fields['edit_address'] = $user['email'];
  864. $fields['edit_date'] = gmstrftime('%Y-%m-%d %H:%M:%S');
  865. // post the article
  866. if(!$fields['id'] = Articles::post($fields))
  867. $response = array( 'faultCode' => -32500, 'faultString' => Logger::error_pop());
  868. else {
  869. $response = '<string>'.$fields['id'].'</string>';
  870. // one post more for this user
  871. Users::increment_posts($user['id']);
  872. // if the page has been published
  873. if($fields['publish_date'] > NULL_DATE) {
  874. // advertise public pages
  875. if($section->is_public()) {
  876. // pingback, if any
  877. Links::ping($fields['introduction'].' '.$fields['source'].' '.$fields['description'], 'article:'.$fields['id']);
  878. }
  879. // 'publish' hook
  880. if(is_callable(array('Hooks', 'include_scripts')))
  881. Hooks::include_scripts('publish', $fields['id']);
  882. }
  883. // list the article in categories
  884. $keywords = '';
  885. if(isset($fields['tags']))
  886. $keywords = $fields['tags'];
  887. if(isset($content['mt_keywords']))
  888. $keywords .= ', '.$content['mt_keywords'];
  889. $keywords = trim($keywords, ', ');
  890. Categories::remember('article:'.$fields['id'], isset($fields['publish_date']) ? $fields['publish_date'] : NULL_DATE, $keywords);
  891. }
  892. }
  893. break;
  894. // set a section template
  895. case 'blogger.setTemplate':
  896. case 'metaWeblog.setTemplate':
  897. list($ignored_appkey, $blogid, $username, $password, $template, $type) = $parameters['params'];
  898. // get item from the database
  899. if($item =& Sections::get($blogid)) {
  900. $section = new Section();
  901. $section->load_by_content($item);
  902. }
  903. // check user
  904. $user = Users::login($username, $password);
  905. if(!isset($user['id']))
  906. $response = array( 'faultCode' => -32602, 'faultString' => sprintf(i18n::c('Please register at %s before blogging'), $context['url_to_home']) );
  907. // check the section id
  908. elseif(!isset($item['id']))
  909. $response = array( 'faultCode' => -32602, 'faultString' => sprintf(i18n::c('Unknown blog %s at %s'), $blogid, $context['url_to_home']) );
  910. // restrict access to associates and editors
  911. elseif(($user['capability'] != 'A') && !$section->is_assigned($user['id']))
  912. $response = array( 'faultCode' => -32602, 'faultString' => i18n::c('You are not allowed to perform this operation.') );
  913. // we actually process only 'main' type
  914. elseif($type != 'main')
  915. $response = array( 'faultCode' => -32602, 'faultString' => i18n::c('You are not allowed to perform this operation.'));
  916. // do the update
  917. elseif($response = Sections::put_template($blogid, $template))
  918. $response = array( 'faultCode' => -32602, 'faultString' => $response);
  919. else
  920. $response = TRUE;
  921. break;
  922. // update the information about an existing post
  923. case 'metaWeblog.editPost':
  924. list($postid, $username, $password, $content, $publish) = $parameters['params'];
  925. // get items from the database
  926. if($item =& Articles::get($postid))
  927. $anchor =& Anchors::get($item['anchor']);
  928. // check user
  929. $user = Users::login($username, $password);
  930. if(!isset($user['id']))
  931. $response = array( 'faultCode' => -32602, 'faultString' => sprintf(i18n::c('Please register at %s before blogging'), $context['url_to_home']) );
  932. // check the article actually exists
  933. elseif(!isset($item['id']))
  934. $response = array( 'faultCode' => -32602, 'faultString' => sprintf(i18n::c('Unknown postid %s at %s'), $postid, $context['url_to_home']) );
  935. else {
  936. // remember surfer
  937. Surfer::set($user);
  938. // surfer may be an associate
  939. Surfer::empower($user['capability']);
  940. // surfer is a section editor
  941. if(Surfer::is_member($user['capability']) && is_object($anchor) && $anchor->is_assigned($user['id']))
  942. Surfer::empower();
  943. // surfer is a page editor
  944. elseif(Articles::is_assigned($item['id'], $user['id']))
  945. Surfer::empower();
  946. // operation is restricted
  947. if(!Surfer::is_empowered())
  948. $response = array( 'faultCode' => -32602, 'faultString' => i18n::c('You are not allowed to perform this operation.') );
  949. else {
  950. // remember the previous page version
  951. Versions::save($item, 'article:'.$item['id']);
  952. // parse article content
  953. $article = new Article();
  954. $fields = $article->parse($content['description'], $item);
  955. if($content['title'])
  956. $fields['title'] = $content['title'];
  957. // publish if in wiki mode, or if section is configured for auto-publishing,
  958. // or if the surfer asks for it and add sufficient rights
  959. if( ($context['users_with_auto_publish'] == 'Y')
  960. || (is_object($anchor) && $anchor->has_option('auto_publish'))
  961. || ($publish && Articles::allow_publication($anchor, $item)) ) {
  962. $fields['publish_name'] = $user['nick_name'];
  963. $fields['publish_id'] = $user['id'];
  964. $fields['publish_address'] = $user['email'];
  965. $fields['publish_date'] = gmstrftime('%Y-%m-%d %H:%M:%S');
  966. }
  967. $fields['edit_name'] = $user['nick_name'];
  968. $fields['edit_id'] = $user['id'];
  969. $fields['edit_address'] = $user['email'];
  970. $fields['edit_date'] = gmstrftime('%Y-%m-%d %H:%M:%S');
  971. // update the article
  972. if(!Articles::put($fields))
  973. $response = array( 'faultCode' => -32500, 'faultString' => sprintf(i18n::c('Impossible to update record of postid %s'), $postid) );
  974. else {
  975. $response = TRUE;
  976. // if the page has been published
  977. if($fields['publish_date'] > NULL_DATE) {
  978. // advertise public pages
  979. if($anchor->is_public() && ($item['active'] == 'Y')) {
  980. // pingback, if any
  981. Links::ping($fields['introduction'].' '.$fields['source'].' '.$fields['description'], 'article:'.$postid);
  982. }
  983. // 'publish' hook
  984. if(is_callable(array('Hooks', 'include_scripts')))
  985. Hooks::include_scripts('publish', $item['id']);
  986. }
  987. // list the article in categories
  988. $keywords = '';
  989. if(isset($fields['tags']))
  990. $keywords = $fields['tags'];
  991. if(isset($content['mt_keywords']))
  992. $keywords .= ', '.$content['mt_keywords'];
  993. $keywords = trim($keywords, ', ');
  994. Categories::remember('article:'.$item['id'], isset($fields['publish_date']) ? $fields['publish_date'] : NULL_DATE, $keywords);
  995. }
  996. }
  997. }
  998. break;
  999. // return a list of categories for this blog
  1000. case 'metaWeblog.getCategories':
  1001. list($blogid, $username, $password) = $parameters['params'];
  1002. // check user
  1003. $user = Users::login($username, $password);
  1004. if(!isset($user['id']))
  1005. $response = array( 'faultCode' => -32602, 'faultString' => sprintf(i18n::c('Please register at %s before blogging'), $context['url_to_home']) );
  1006. // list categories
  1007. else {
  1008. $response = array();
  1009. $items = Categories::list_by_path(0, 50, 'raw');
  1010. if(is_array($items)) {
  1011. // one entry per category
  1012. foreach($items as $id => $attributes) {
  1013. // the category for a human being
  1014. $htmlUrl = $context['url_to_home'].$context['url_to_root'].Categories::get_permalink($attributes);
  1015. // the category for a robot
  1016. $rssUrl = $context['url_to_home'].$context['url_to_root'].Categories::get_url($id, 'feed');
  1017. // format the response
  1018. $response[] = array(
  1019. 'categoryId' => $codec->encode((string)$id, 'string'),
  1020. 'categoryName' => $codec->encode(strip_tags($attributes['title']), 'string'),
  1021. 'description' => $codec->encode(strip_tags($attributes['title']), 'string'),
  1022. 'htmlUrl' => $codec->encode($htmlUrl, 'string'),
  1023. 'rssUrl' => $codec->encode($rssUrl, 'string')
  1024. );
  1025. }
  1026. }
  1027. }
  1028. break;
  1029. // get a single post
  1030. case 'metaWeblog.getPost':
  1031. list($postid, $username, $password) = $parameters['params'];
  1032. // get items from the database
  1033. if($item =& Articles::get($postid))
  1034. $anchor =& Anchors::get($item['anchor']);
  1035. // check user
  1036. $user = Users::login($username, $password);
  1037. if(!isset($user['id']))
  1038. $response = array( 'faultCode' => -32602, 'faultString' => sprintf(i18n::c('Please register at %s before blogging'), $context['url_to_home']) );
  1039. // check the article actually exists
  1040. elseif(!isset($item['id']))
  1041. $response = array( 'faultCode' => -32602, 'faultString' => sprintf(i18n::c('Unknown postid %s at %s'), $postid, $context['url_to_home']) );
  1042. // unknown anchor
  1043. elseif(!is_object($anchor))
  1044. $response = array( 'faultCode' => -32602, 'faultString' => i18n::c('You are not allowed to perform this operation.') );
  1045. else {
  1046. // surfer may be an associate
  1047. Surfer::empower($user['capability']);
  1048. // surfer is an associate
  1049. if($user['capability'] == 'A')
  1050. $permitted = TRUE;
  1051. // public page
  1052. elseif(($item['active'] == 'Y') && $anchor->is_viewable($user['id']))
  1053. $permitted = TRUE;
  1054. // restricted page
  1055. elseif(($item['active'] == 'R') && $anchor->is_viewable($user['id']))
  1056. $permitted = TRUE;
  1057. // hidden page
  1058. elseif(($item['active'] == 'N') && $anchor->is_assigned($user['id']))
  1059. $permitted = TRUE;
  1060. // assigned page
  1061. elseif(Articles::is_assigned($item['id'], $user['id']))
  1062. $permitted = TRUE;
  1063. // sorry
  1064. else
  1065. $permitted = FALSE;
  1066. // restrict gets in protected section
  1067. if(!$permitted)
  1068. $response = array( 'faultCode' => -32602, 'faultString' => i18n::c('You are not allowed to perform this operation.') );
  1069. // fetch the page
  1070. else {
  1071. $response = array(
  1072. 'title' => $codec->encode($item['title'], 'string'),
  1073. 'link' => $context['url_to_home'].$context['url_to_root'].Articles::get_permalink($item),
  1074. 'permaLink' => $context['url_to_home'].$context['url_to_root'].Articles::get_permalink($item),
  1075. 'description' => $codec->encode('<introduction>'.$item['introduction']."</introduction>\n"
  1076. .'<source>'.$item['source']."</source>\n"
  1077. .$item['description'], 'string'),
  1078. 'author' => $codec->encode($item['create_address']),
  1079. 'comments' => $context['url_to_home'].$context['url_to_root'].'comments/edit.php?anchor='.urlencode('article:'.$postid),
  1080. 'dateCreated' => $codec->encode($item['edit_date'], 'date'),
  1081. 'userid' => (string)$item['edit_id'],
  1082. 'postid' => (string)$postid
  1083. );
  1084. }
  1085. }
  1086. break;
  1087. // return a list of the most recent posts in the system
  1088. case 'metaWeblog.getRecentPosts':
  1089. list($blogid, $username, $password, $numberOfPosts) = $parameters['params'];
  1090. // get item from the database
  1091. if($item =& Sections::get($blogid)) {
  1092. $section = new Section();
  1093. $section->load_by_content($item);
  1094. }
  1095. // check user
  1096. $user = Users::login($username, $password);
  1097. if(!isset($user['id']))
  1098. $response = array( 'faultCode' => -32602, 'faultString' => sprintf(i18n::c('Please register at %s before blogging'), $context['url_to_home']) );
  1099. // check the section id
  1100. elseif(!isset($item['id']))
  1101. $response = array( 'faultCode' => -32602, 'faultString' => sprintf(i18n::c('Unknown blog %s at %s'), $blogid, $context['url_to_home']) );
  1102. // not accessible
  1103. elseif(($user['capability'] != 'A') && !$section->is_viewable($user['id']))
  1104. $response = array( 'faultCode' => -32602, 'faultString' => i18n::c('You are not allowed to perform this operation.') );
  1105. // lists posts
  1106. else {
  1107. // surfer may be an associate
  1108. Surfer::empower($user['capability']);
  1109. // surfer is a section editor
  1110. if(Surfer::is_member($user['capability']) && is_object($section) && $section->is_assigned($user['id']))
  1111. Surfer::empower();
  1112. // surfer is a page editor
  1113. elseif(Articles::is_assigned($item['id'], $user['id']))
  1114. Surfer::empower();
  1115. $response = array();
  1116. $items =& Articles::list_for_anchor_by('edition', 'section:'.$blogid, 0, min($numberOfPosts, 30), 'raw');
  1117. if(is_array($items)) {
  1118. foreach($items as $id => $item) {
  1119. // post content
  1120. $entry = array();
  1121. $entry['dateCreated'] = $codec->encode($item['edit_date'], 'date');
  1122. $entry['userid'] = (string)$item['edit_id'];
  1123. $entry['postid'] = (string)$id;
  1124. $entry['title'] = $codec->encode($item['title'], 'string');
  1125. $entry['link'] = $context['url_to_home'].$context['url_to_root'].Articles::get_permalink($item);
  1126. $entry['permaLink'] = $context['url_to_home'].$context['url_to_root'].Articles::get_permalink($item);
  1127. $entry['description'] = '';
  1128. if(isset($item['introduction']))
  1129. $entry['description'] .= '<introduction>'.$item['introduction']."</introduction>\n";
  1130. if(isset($item['source']))
  1131. $entry['description'] .= '<source>'.$item['source']."</source>\n";
  1132. if(isset($item['description']))
  1133. $entry['description'] .= $item['description'];
  1134. $entry['description'] = $codec->encode($item['description'], 'string'); // various optimizations
  1135. $entry['author'] = $codec->encode($item['create_address']);
  1136. $entry['comments'] = $context['url_to_home'].$context['url_to_root'].'comments/edit.php?anchor='.urlencode('article:'.$id);
  1137. if(isset($item['publish_date']) && ($item['publish_date'] > NULL_DATE))
  1138. $entry['pubDate'] = $codec->encode($item['publish_date'], 'date');
  1139. // attached categories
  1140. $categories =& Members::list_categories_by_title_for_member('article:'.$id, 0, 10, 'raw');
  1141. foreach($categories as $id => $attributes)
  1142. $entry['categories'][] = strip_tags($attributes['title']);
  1143. // append to the list
  1144. $response[] = $entry;
  1145. }
  1146. }
  1147. }
  1148. break;
  1149. // upload a file
  1150. case 'metaWeblog.newMediaObject':
  1151. list($blogid, $username, $password, $content) = $parameters['params'];
  1152. // get item from the database
  1153. if($item =& Sections::get($blogid)) {
  1154. $section = new Section();
  1155. $section->load_by_content($item);
  1156. }
  1157. // check user
  1158. $user = Users::login($username, $password);
  1159. if(!isset($user['id']))
  1160. $response = array( 'faultCode' => -32602, 'faultString' => sprintf(i18n::c('Please register at %s before blogging'), $context['url_to_home']) );
  1161. // ensure uploads are allowed
  1162. elseif(!Surfer::may_upload($user['capability']))
  1163. $response = array( 'faultCode' => -32602, 'faultString' => i18n::c('You are not allowed to perform this operation.') );
  1164. // we need some actual content
  1165. elseif(!isset($content['name']) || !$content['name'] || !isset($content['bits']) || !$content['bits'])
  1166. $response = array( 'faultCode' => -32602, 'faultString' => i18n::c('No file data has been received.') );
  1167. // check the section id
  1168. elseif(!isset($item['id']))
  1169. $response = array( 'faultCode' => -32602, 'faultString' => sprintf(i18n::c('Unknown blog %s at %s'), $blogid, $context['url_to_home']) );
  1170. // not accessib…

Large files files are truncated, but you can click here to view the full file