PageRenderTime 50ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/wordpress_consumer/xenforo-api-consumer/includes/sync/subscription.php

https://gitlab.com/billyprice1/bdApi
PHP | 357 lines | 282 code | 50 blank | 25 comment | 66 complexity | a0e50fb8037b21c74e4efb3fa0680694 MD5 | raw file
  1. <?php
  2. // Exit if accessed directly
  3. if (!defined('ABSPATH')) {
  4. exit();
  5. }
  6. function xfac_subscription_handleIntentVerification(array $params)
  7. {
  8. if (empty($params['client_id'])) {
  9. // unable to determine hub authorized client
  10. header('HTTP/1.0 404 Not Found');
  11. return false;
  12. }
  13. $config = xfac_option_getConfig();
  14. if (empty($config['clientId'])) {
  15. // no client configured, should not accept subscription
  16. header('HTTP/1.0 404 Not Found');
  17. return false;
  18. }
  19. if ($config['clientId'] !== $params['client_id']) {
  20. // client mis-matched
  21. header('HTTP/1.0 401 Unauthorized');
  22. return false;
  23. }
  24. // TODO: verify $params['hub_topic']?
  25. echo $params['hub_challenge'];
  26. return true;
  27. }
  28. function xfac_subscription_handleCallback(array $json)
  29. {
  30. $config = xfac_option_getConfig();
  31. if (empty($config['clientId'])) {
  32. return;
  33. }
  34. $xfThreadIds = array();
  35. $xfPostIds = array();
  36. // phrase 1: preparation
  37. foreach ($json as &$pingRef) {
  38. if (empty($pingRef['client_id']) OR $pingRef['client_id'] != $config['clientId']) {
  39. continue;
  40. }
  41. if (empty($pingRef['topic'])) {
  42. continue;
  43. }
  44. $parts = explode('_', $pingRef['topic']);
  45. $pingRef['topic_id'] = array_pop($parts);
  46. $pingRef['topic_type'] = implode('_', $parts);
  47. switch ($pingRef['topic_type']) {
  48. case 'thread_post':
  49. $xfThreadIds[] = $pingRef['topic_id'];
  50. $xfPostIds[] = $pingRef['object_data'];
  51. break;
  52. }
  53. }
  54. // phrase 2: fetch sync records
  55. $postSyncRecords = array();
  56. if (!empty($xfPostIds)) {
  57. $postSyncRecords = xfac_sync_getRecordsByProviderTypeAndIds('', 'thread', $xfThreadIds);
  58. }
  59. $commentSyncRecords = array();
  60. if (!empty($xfPostIds)) {
  61. $commentSyncRecords = xfac_sync_getRecordsByProviderTypeAndIds('', 'post', $xfPostIds);
  62. }
  63. // phrase 3: sync data
  64. foreach ($json as &$pingRef) {
  65. if (empty($pingRef['topic_type'])) {
  66. continue;
  67. }
  68. switch ($pingRef['topic_type']) {
  69. case 'thread_post':
  70. $postSyncRecord = null;
  71. $commentSyncRecord = null;
  72. foreach ($postSyncRecords as $_postSyncRecord) {
  73. if ($_postSyncRecord->provider_content_id == $pingRef['topic_id']) {
  74. $postSyncRecord = $_postSyncRecord;
  75. }
  76. }
  77. if (!empty($postSyncRecord)) {
  78. foreach ($commentSyncRecords as $_commentSyncRecord) {
  79. if ($_commentSyncRecord->provider_content_id == $pingRef['object_data']) {
  80. $commentSyncRecord = $_commentSyncRecord;
  81. }
  82. }
  83. $pingRef['result'] = _xfac_subscription_handleCallback_threadPost($config, $pingRef, $postSyncRecord, $commentSyncRecord);
  84. if (!empty($pingRef['result'])) {
  85. xfac_sync_updateRecordDate($postSyncRecord);
  86. if (!empty($commentSyncRecord)) {
  87. xfac_sync_updateRecordDate($commentSyncRecord);
  88. }
  89. }
  90. }
  91. break;
  92. case 'user_notification':
  93. $pingRef['result'] = _xfac_subscription_handleCallback_userNotification($config, $pingRef);
  94. break;
  95. case 'user':
  96. $pingRef['result'] = _xfac_subscription_handleCallback_user($config, $pingRef);
  97. break;
  98. }
  99. }
  100. // phrase 4: output results
  101. $results = array();
  102. foreach ($json as $ping) {
  103. if (!empty($ping['result'])) {
  104. $results[] = $ping;
  105. xfac_log('xfac_subscription_handleCallback %s/%s -> %s', $ping['topic_type'], $ping['topic_id'], $ping['result']);
  106. }
  107. }
  108. echo json_encode($results);
  109. }
  110. function _xfac_subscription_handleCallback_threadPost($config, $ping, $postSyncRecord, $commentSyncRecord)
  111. {
  112. $wpUserData = xfac_user_getUserDataByApiData($config['root'], $postSyncRecord->syncData['thread']['creator_user_id']);
  113. $optionSyncPost = intval(get_option('xfac_sync_post_xf_wp')) > 0;
  114. $optionSyncComment = intval(get_option('xfac_sync_comment_xf_wp')) > 0;
  115. $accessToken = xfac_user_getAccessToken($wpUserData->ID);
  116. $xfPost = xfac_api_getPost($config, $ping['object_data'], $accessToken);
  117. $xfPostIsDeleted = (empty($xfPost['post']) OR !empty($xfPost['post']['post_is_deleted']));
  118. if (empty($commentSyncRecord)) {
  119. if (!$xfPostIsDeleted) {
  120. if (empty($xfPost['post']['post_is_first_post'])) {
  121. // create a new comment
  122. if ($optionSyncComment && xfac_syncComment_pullComment($config, $xfPost['post'], $postSyncRecord->sync_id, 'subscription') > 0) {
  123. return 'created new comment';
  124. }
  125. } else {
  126. $recordPostUpdateDate = 0;
  127. $xfPostUpdateDate = 0;
  128. if (isset($postSyncRecord->syncData['thread']['first_post']['post_update_date'])) {
  129. $recordPostUpdateDate = $postSyncRecord->syncData['thread']['first_post']['post_update_date'];
  130. }
  131. if (isset($xfPost['post']['post_update_date'])) {
  132. $xfPostUpdateDate = $xfPost['post']['post_update_date'];
  133. }
  134. if ($recordPostUpdateDate > 0 && $xfPostUpdateDate > 0) {
  135. if ($xfPostUpdateDate <= $recordPostUpdateDate) {
  136. // the new post is not newer than the post in record
  137. // we used XenForo server time (which uses GMT) so it should be correct
  138. return false;
  139. }
  140. }
  141. // update the WordPress post
  142. $postContent = xfac_api_filterHtmlFromXenForo($xfPost['post']['post_body_html']);
  143. // remove the link back, if any
  144. $wfPostLink = get_permalink($postSyncRecord->sync_id);
  145. $postContent = preg_replace('#<a href="' . preg_quote($wfPostLink, '#') . '"[^>]*>[^<]+</a>$#', '', $postContent);
  146. $XFAC_SKIP_xfac_save_post_before = !empty($GLOBALS['XFAC_SKIP_xfac_save_post']);
  147. $GLOBALS['XFAC_SKIP_xfac_save_post'] = true;
  148. $postUpdated = 0;
  149. if ($optionSyncPost) {
  150. $postUpdated = wp_update_post(array(
  151. 'ID' => $postSyncRecord->sync_id,
  152. 'post_content' => $postContent,
  153. ));
  154. }
  155. $GLOBALS['XFAC_SKIP_xfac_save_post'] = $XFAC_SKIP_xfac_save_post_before;
  156. if (is_int($postUpdated) AND $postUpdated > 0) {
  157. return 'updated post';
  158. }
  159. }
  160. }
  161. } else {
  162. if (!$xfPostIsDeleted) {
  163. // update comment content and approve it automatically
  164. $commentContent = xfac_api_filterHtmlFromXenForo($xfPost['post']['post_body_html']);
  165. $XFAC_SKIP_xfac_save_comment_before = !empty($GLOBALS['XFAC_SKIP_xfac_save_comment']);
  166. $GLOBALS['XFAC_SKIP_xfac_save_comment'] = true;
  167. $commentUpdated = 0;
  168. if ($optionSyncComment) {
  169. $commentUpdated = wp_update_comment(array(
  170. 'comment_ID' => $commentSyncRecord->sync_id,
  171. 'comment_content' => $commentContent,
  172. 'comment_approved' => 1,
  173. ));
  174. }
  175. $GLOBALS['XFAC_SKIP_xfac_save_comment'] = $XFAC_SKIP_xfac_save_comment_before;
  176. if ($commentUpdated > 0) {
  177. return 'updated comment';
  178. }
  179. } else {
  180. // check for comment current status and unapprove it
  181. $wpComment = get_comment($commentSyncRecord->sync_id);
  182. if (!empty($wpComment->comment_approved)) {
  183. $XFAC_SKIP_xfac_save_comment_before = !empty($GLOBALS['XFAC_SKIP_xfac_save_comment']);
  184. $GLOBALS['XFAC_SKIP_xfac_save_comment'] = true;
  185. $commentUpdated = 0;
  186. if ($optionSyncComment) {
  187. $commentUpdated = wp_update_comment(array(
  188. 'comment_ID' => $commentSyncRecord->sync_id,
  189. 'comment_approved' => 0,
  190. ));
  191. }
  192. $GLOBALS['XFAC_SKIP_xfac_save_comment'] = $XFAC_SKIP_xfac_save_comment_before;
  193. if ($commentUpdated > 0) {
  194. return 'unapproved comment';
  195. }
  196. } else {
  197. return 'comment is unapproved';
  198. }
  199. }
  200. }
  201. return false;
  202. }
  203. function _xfac_subscription_handleCallback_userNotification($config, $ping)
  204. {
  205. $accessToken = xfac_user_getSystemAccessToken($config);
  206. if (empty($accessToken)) {
  207. return false;
  208. }
  209. if (empty($ping['object_data']['notification_id'])) {
  210. return false;
  211. }
  212. $notification = $ping['object_data'];
  213. if (empty($notification['notification_type'])) {
  214. return false;
  215. }
  216. if (!preg_match('/^post_(?<postId>\d+)_insert$/', $notification['notification_type'], $matches)
  217. || intval(get_option('xfac_sync_post_xf_wp')) == 0
  218. ) {
  219. // currently we only handle post pull here
  220. return false;
  221. }
  222. $postId = $matches['postId'];
  223. $xfPost = xfac_api_getPost($config, $postId, $accessToken);
  224. if (empty($xfPost['post']['thread_id'])) {
  225. return false;
  226. }
  227. $postSyncRecords = xfac_sync_getRecordsByProviderTypeAndIds('', 'thread', array($xfPost['post']['thread_id']));
  228. if (!empty($postSyncRecords)) {
  229. return false;
  230. }
  231. $xfThread = xfac_api_getThread($config, $xfPost['post']['thread_id'], $accessToken);
  232. if (empty($xfThread['thread'])) {
  233. return false;
  234. }
  235. $wpTags = xfac_syncPost_getMappedTags($xfThread['thread']['forum_id']);
  236. if (empty($wpTags)) {
  237. return false;
  238. }
  239. $wpPostId = xfac_syncPost_pullPost($config, $xfThread['thread'], $wpTags, 'subscription');
  240. if ($wpPostId > 0) {
  241. return 'created new post';
  242. }
  243. return false;
  244. }
  245. function _xfac_subscription_handleCallback_user($config, $ping)
  246. {
  247. $wpUserData = xfac_user_getUserDataByApiData($config['root'], $ping['object_data']);
  248. if (empty($wpUserData)) {
  249. return false;
  250. }
  251. $accessToken = xfac_user_getAccessToken($wpUserData->ID);
  252. if (empty($accessToken)) {
  253. return false;
  254. }
  255. $me = xfac_api_getUsersMe($config, $accessToken, false);
  256. if (empty($me)) {
  257. return false;
  258. }
  259. $xfUser = $me['user'];
  260. $wpUser = new WP_User($wpUserData);
  261. xfac_syncLogin_syncBasic($config, $wpUser, $xfUser);
  262. xfac_syncLogin_syncRole($config, $wpUser, $xfUser);
  263. if (xfac_user_updateRecord($wpUserData->ID, $config['root'], $xfUser['user_id'], $xfUser)) {
  264. return 'updated user record';
  265. } else {
  266. return false;
  267. }
  268. }
  269. function xfac_do_parse_request($bool, $wp, $extra_query_vars)
  270. {
  271. if (empty($extra_query_vars['tb'])) {
  272. // not trackback request, ignore it
  273. return $bool;
  274. }
  275. if (empty($_SERVER['REQUEST_METHOD'])) {
  276. // unable to determine request method, stop working
  277. return $bool;
  278. }
  279. if (strtoupper($_SERVER['REQUEST_METHOD']) === 'GET') {
  280. if (isset($_GET['hub_challenge'])) {
  281. xfac_subscription_handleIntentVerification($_GET);
  282. exit();
  283. }
  284. } elseif (strtoupper($_SERVER['REQUEST_METHOD']) !== 'POST') {
  285. // not a POST request, ignore it
  286. return $bool;
  287. }
  288. if (empty($_SERVER['REQUEST_URI'])) {
  289. // unable to determine request URI, stop working
  290. return $bool;
  291. }
  292. if (strpos($_SERVER['REQUEST_URI'], 'xfac_callback') === false) {
  293. // request to something else, not our callback, bye bye
  294. // we don't check $_REQUEST because PHP parser got confused when
  295. // the POST data is JSON and may work unreliably here
  296. return $bool;
  297. }
  298. $raw = file_get_contents('php://input');
  299. $json = @json_decode($raw, true);
  300. if (!is_array($json)) {
  301. // unable to parse json, do nothing
  302. return $bool;
  303. }
  304. xfac_subscription_handleCallback($json);
  305. exit();
  306. }
  307. add_filter('do_parse_request', 'xfac_do_parse_request', 10, 3);