1<?php 2// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project 3// 4// All Rights Reserved. See copyright.txt for details and a complete list of authors. 5// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details. 6// $Id$ 7 8//this script may only be included - so its better to die if called directly. 9if (strpos($_SERVER["SCRIPT_NAME"], basename(__FILE__)) !== false) { 10 header("location: index.php"); 11 exit; 12} 13 14class RSSLib extends TikiDb_Bridge 15{ 16 private $items; 17 private $feeds; 18 private $modules; 19 20 function __construct() 21 { 22 $this->items = $this->table('tiki_rss_items'); 23 $this->feeds = $this->table('tiki_rss_feeds'); 24 $this->modules = $this->table('tiki_rss_modules'); 25 } 26 27 // ------------------------------------ 28 // functions for rss feeds we syndicate 29 // ------------------------------------ 30 31 /** 32 * Return the feed format name 33 * 34 * @return string feed format name 35 */ 36 function get_current_feed_format_name() 37 { 38 $ver = $this->get_current_feed_format(); 39 40 if ($ver == '2') { 41 $name = 'rss'; 42 } elseif ($ver == '5') { 43 $name = 'atom'; 44 } 45 46 return $name; 47 } 48 49 /** 50 * Return the feed format code (2 for rss and 5 for atom) 51 * we currently use (user param or default value) 52 * 53 * @return int $ver 54 */ 55 function get_current_feed_format() 56 { 57 global $prefs; 58 59 if (isset($_REQUEST['ver'])) { 60 $ver = $_REQUEST['ver']; 61 } else { 62 $ver = $prefs['feed_default_version']; 63 } 64 65 return $ver; 66 } 67 68 /* check for cached rss feed data */ 69 function get_from_cache($uniqueid, $rss_version = "9") 70 { 71 global $tikilib, $user, $prefs; 72 73 $rss_version = $this->get_current_feed_format(); 74 75 $output = []; 76 $output["content-type"] = "application/xml"; 77 $output["encoding"] = "UTF-8"; 78 79 $output["data"] = "EMPTY"; 80 81 // caching rss data for anonymous users only 82 if (isset($user) && $user <> "") { 83 return $output; 84 } 85 86 $res = $this->feeds->fetchFullRow(['name' => $uniqueid, 'rssVer' => $rss_version]); 87 if (! $res) { 88 // nothing found, then insert empty row for this feed+rss_ver 89 $this->feeds->insert( 90 [ 91 'name' => $uniqueid, 92 'rssVer' => $rss_version, 93 'refresh' => (int) $prefs['feed_cache_time'], 94 'lastUpdated' => 1, 95 'cache' => '-', 96 ] 97 ); 98 } else { 99 // entry found in db: 100 $output["data"] = $res["cache"]; 101 // $refresh = $res["refresh"]; // global cache time currently 102 $refresh = $prefs['feed_cache_time']; // global cache time currently 103 $lastUpdated = $res["lastUpdated"]; 104 // up to date? if not, then set trigger to reload data: 105 if ($tikilib->now - $lastUpdated >= $refresh) { 106 $output["data"] = "EMPTY"; 107 } 108 } 109 $output['content-type'] = 'application/xml'; 110 return $output; 111 } 112 113 /* put to cache */ 114 function put_to_cache($uniqueid, $rss_version = "9", $output) 115 { 116 global $user, $tikilib; 117 // caching rss data for anonymous users only 118 if (isset($user) && $user <> "") { 119 return; 120 } 121 if ($output == "" || $output == "EMPTY") { 122 return; 123 } 124 125 $rss_version = $this->get_current_feed_format(); 126 127 // update cache with new generated data if data not empty 128 129 $this->feeds->update( 130 [ 131 'cache' => $output, 132 'lastUpdated' => $tikilib->now, 133 ], 134 [ 135 'name' => $uniqueid, 136 'rssVer' => $rss_version, 137 ] 138 ); 139 } 140 141 /** 142 * Generate a feed (ATOM 1.0 or RSS 2.0 using Zend\Feed\Writer\Feed 143 * 144 * @param string $section Tiki feature the feed is related to 145 * @param string $uniqueid 146 * @param string $feed_version DEPRECATED 147 * @param array $changes the content that will be used to generate the feed 148 * @param string $itemurl base url for items (e.g. "tiki-view_blog_post.php?postId=%s") 149 * @param string $urlparam 150 * @param string $id name of the id field used to identify each feed item (e.g. "postId") 151 * @param string $title title for the feed 152 * @param string $titleId name of the key in the $changes array with the title of each item 153 * @param string $desc description for the feed 154 * @param string $descId name of the key in the $changes array with the description of each item 155 * @param string $dateId name of the key in the $changes array with the date of each item 156 * @param string $authorId name of the key in the $changes array with the author of each item 157 * @param bool $fromcache if true recover the feed from cache 158 * 159 * @return array the generated feed 160 */ 161 function generate_feed($section, $uniqueid, $feed_version, $changes, $itemurl, $urlparam, $id, $title, $titleId, $desc, $descId, $dateId, $authorId, $fromcache = false 162 ) 163 { 164 global $tiki_p_admin, $prefs; 165 $userlib = TikiLib::lib('user'); 166 $tikilib = TikiLib::lib('tiki'); 167 $smarty = TikiLib::lib('smarty'); 168 169 // both title and description fields cannot be null 170 if (empty($title) || empty($desc)) { 171 $msg = tra('The title and description must be entered, to generate a feed.'); 172 if ($tiki_p_admin) { 173 $msg .= ' ' . tra('To fix this error go to Admin -> Feeds.'); 174 } else { 175 $msg .= ' ' . tra('Please contact the site administrator and request this error to be corrected'); 176 } 177 $smarty->assign('msg', $msg); 178 $smarty->display('error.tpl'); 179 die; 180 } 181 182 $feed_format = $this->get_current_feed_format(); 183 $feed_format_name = $this->get_current_feed_format_name(); 184 185 if ($prefs['feed_cache_time'] < 1) { 186 $fromcache = false; 187 } 188 189 // only get cache data if rss cache is enabled 190 if ($fromcache) { 191 $output = $this->get_from_cache($uniqueid, $feed_format); 192 if ($output['data'] != 'EMPTY') { 193 return $output; 194 } 195 } 196 197 $urlarray = parse_url($_SERVER["REQUEST_URI"]); 198 $rawPath = str_replace('\\', '/', dirname($urlarray["path"])); 199 $URLPrefix = $tikilib->httpPrefix() . $rawPath; 200 if ($rawPath != "/") { 201 $URLPrefix .= "/"; // Append a slash unless Tiki is in the document root. dirname() removes a slash except in that case. 202 } 203 204 if (isset($prefs['feed_' . $section . '_index']) && $prefs['feed_' . $section . '_index'] != '') { 205 $feedLink = $prefs['feed_' . $section . '_index']; 206 } else { 207 $feedLink = htmlspecialchars($tikilib->httpPrefix() . $_SERVER["REQUEST_URI"]); 208 } 209 210 $img = htmlspecialchars($URLPrefix . $prefs['feed_img']); 211 212 $title = htmlspecialchars($title); 213 $desc = htmlspecialchars($desc); 214 $read = $URLPrefix . $itemurl; 215 216 $feed = new Zend\Feed\Writer\Feed(); 217 $feed->setTitle($title); 218 $feed->setDescription($desc); 219 220 if (! empty($prefs['feed_language'])) { 221 $feed->setLanguage($prefs['feed_language']); 222 } 223 224 $feed->setLink($tikilib->tikiUrl('')); 225 $feed->setFeedLink($feedLink, $feed_format_name); 226 $feed->setDateModified($tikilib->now); 227 228 if ($feed_format_name == 'atom') { 229 $author = []; 230 231 if (! empty($prefs['feed_atom_author_name'])) { 232 $author['name'] = $prefs['feed_atom_author_name']; 233 } 234 if (! empty($prefs['feed_atom_author_email'])) { 235 $author['email'] = $prefs['feed_atom_author_email']; 236 } 237 if (! empty($prefs['feed_atom_author_url'])) { 238 $author['url'] = $prefs['feed_atom_author_url']; 239 } 240 241 if (! empty($author)) { 242 if (empty($author['name'])) { 243 $msg = tra('If you set feed author email or URL, you must set feed author name.'); 244 $smarty->assign('msg', $msg); 245 $smarty->display('error.tpl'); 246 die; 247 } 248 $feed->addAuthor($author); 249 } 250 } else { 251 $authors = []; 252 253 if (! empty($prefs['feed_rss_editor_email'])) { 254 $authors['name'] = $prefs['feed_rss_editor_email']; 255 } 256 if (! empty($prefs['feed_rss_webmaster_email'])) { 257 $authors['name'] = $prefs['feed_rss_webmaster_email']; 258 } 259 260 if (! empty($authors)) { 261 $feed->addAuthors([$authors]); 262 } 263 } 264 265 if (! empty($prefs['feed_img'])) { 266 $image = []; 267 $image['uri'] = $tikilib->tikiUrl($prefs['feed_img']); 268 $image['title'] = tra('Feed logo'); 269 $image['link'] = $tikilib->tikiUrl(''); 270 $feed->setImage($image); 271 } 272 273 foreach ($changes["data"] as $data) { 274 $item = $feed->createEntry(); 275 $item->setTitle($data[$titleId]); 276 277 if (isset($data['sefurl'])) { 278 $item->setLink($URLPrefix . urlencode($data['sefurl'])); 279 } elseif ($urlparam != '') { // 2 parameters to replace 280 $item->setlink(sprintf($read, urlencode($data["$id"]), urlencode($data["$urlparam"]))); 281 } else { 282 $item->setLink(sprintf($read, urlencode($data["$id"]))); 283 } 284 285 if (isset($data[$descId]) && $data[$descId] != '') { 286 $item->setDescription($data[$descId]); 287 } 288 289 $item->setDateCreated((int) $data[$dateId]); 290 $item->setDateModified((int) $data[$dateId]); 291 292 if ($authorId != '' && $prefs['feed_' . $section . '_showAuthor'] == 'y') { 293 $author = $this->process_item_author($data[$authorId]); 294 $item->addAuthor($author); 295 } 296 297 $feed->addEntry($item); 298 } 299 300 $data = $feed->export($feed_format_name); 301 $this->put_to_cache($uniqueid, $feed_format, $data); 302 303 $output = []; 304 $output["data"] = $data; 305 $output["content-type"] = 'application/xml'; 306 307 return $output; 308 } 309 310 /** 311 * Return information about the user acording to its preferences 312 * 313 * @param string $login 314 * @return array author data (can be the login name or the realName if set and email if public) 315 */ 316 function process_item_author($login) 317 { 318 $userlib = TikiLib::lib('user'); 319 $tikilib = TikiLib::lib('tiki'); 320 321 $author = []; 322 323 if ($userlib->user_exists($login) && $tikilib->get_user_preference($login, 'user_information', 'private') == 'public') { 324 // if realName is not set use $login 325 $author['name'] = $tikilib->get_user_preference($login, 'realName', $login); 326 327 if ($tikilib->get_user_preference($login, 'email is public', 'n') != 'n') { 328 $res = $userlib->get_user_info($login, false); 329 $author['email'] = TikiMail::scrambleEmail($res['email']); 330 } 331 } else { 332 $author['name'] = $login; 333 } 334 335 return $author; 336 } 337 338 // -------------------------------------------- 339 // functions for rss feeds syndicated by others 340 // -------------------------------------------- 341 342 /* get (a part of) the list of existing rss feeds from db */ 343 function list_rss_modules($offset = 0, $maxRecords = null, $sort_mode = 'name_asc', $find = '') 344 { 345 global $prefs; 346 347 $conditions = []; 348 if ($maxRecords === null) { 349 $maxRecords = $prefs['maxRecords']; 350 } 351 if ($find) { 352 $conditions['search'] = $this->modules->expr('(`name` LIKE ? OR `description` LIKE ?)', ["%$find%", "%$find%"]); 353 } 354 355 $ret = $this->modules->fetchAll($this->modules->all(), $conditions, $maxRecords, $offset, $this->modules->sortMode($sort_mode)); 356 357 foreach ($ret as & $res) { 358 $res["minutes"] = $res["refresh"] / 60; 359 } 360 361 return [ 362 'data' => $ret, 363 'cant' => $this->modules->fetchCount($conditions), 364 ]; 365 } 366 367 /* replace rss feed in db */ 368 function replace_rss_module($rssId, $name, $description, $url, $refresh, $showTitle, $showPubDate, $noUpdate = false) 369 { 370 //if ($this->rss_module_name_exists($name)) return false; // TODO: Check the name 371 $refresh = 60 * $refresh; 372 373 $data = [ 374 'name' => $name, 375 'description' => $description, 376 'refresh' => $refresh, 377 'url' => $url, 378 'showTitle' => $showTitle, 379 'showPubDate' => $showPubDate, 380 ]; 381 382 if ($rssId) { 383 $this->modules->update($data, ['rssId' => (int) $rssId,]); 384 } else { 385 $data['lastUpdated'] = 1; 386 $rssId = $this->modules->insert($data); 387 } 388 389 if (! $noUpdate) { 390 // Updating is normally required, except for cases where we know it will be updated later (e.g. after article generation is set, so that articles are created immediately) 391 $this->refresh_rss_module($rssId); 392 } 393 return $rssId; 394 } 395 396 /* remove rss feed from db */ 397 function remove_rss_module($rssId) 398 { 399 $this->modules->delete(['rssId' => $rssId,]); 400 $this->items->deleteMultiple(['rssId' => $rssId,]); 401 402 return true; 403 } 404 405 /* read rss feed data from db */ 406 function get_rss_module($rssId) 407 { 408 return $this->modules->fetchFullRow(['rssId' => $rssId]); 409 } 410 411 function refresh_rss_module($rssId) 412 { 413 $this->update_feeds([ $rssId ], true); 414 } 415 416 function refresh_all_rss_modules() 417 { 418 $mods = $this->list_rss_modules(0, -1); 419 $feeds = []; 420 foreach ($mods['data'] as $mod) { 421 $feeds[] = $mod['rssId']; 422 } 423 $this->update_feeds($feeds, true); 424 } 425 426 /** 427 * @param int $rssId feed id 428 * @param int $olderThan publication date more than than this number of seconds ago 429 */ 430 function clear_rss_cache($rssId, $olderThan = 0) 431 { 432 $conditions = ['rssId' => (int)$rssId]; 433 434 if ($olderThan) { 435 $conditions['publication_date'] = $this->items->lesserThan(time() - $olderThan); 436 } 437 438 $this->items->deleteMultiple($conditions); 439 } 440 441 /* check if an rss feed name already exists */ 442 function rss_module_name_exists($name) 443 { 444 return $this->modules->fetchCount(['name' => $name]); 445 } 446 447 /* get rss feed id by name */ 448 function get_rss_module_id($name) 449 { 450 return $this->modules->fetchOne('rssId', ['name' => $name]); 451 } 452 453 /* check if 'showTitle' for an rss feed is enabled */ 454 function get_rss_showTitle($rssId) 455 { 456 return $this->modules->fetchOne('showTitle', ['rssId' => $rssId]); 457 } 458 459 /* check if 'showPubdate' for an rss feed is enabled */ 460 function get_rss_showPubDate($rssId) 461 { 462 return $this->modules->fetchOne('showPubDate', ['rssId' => $rssId]); 463 } 464 465 function get_feed_items($feeds, $count = 10) 466 { 467 $feeds = (array) $feeds; 468 469 $this->update_feeds($feeds); 470 471 return $this->items->fetchAll( 472 $this->items->all(), 473 ['rssId' => $this->items->in($feeds),], 474 $count, 475 0, 476 ['publication_date' => 'DESC'] 477 ); 478 } 479 480 private function update_feeds($feeds, $force = false) 481 { 482 global $tikilib; 483 484 $conditions = ['rssId' => $this->modules->in($feeds),]; 485 486 if (! $force) { 487 $conditions['date'] = $this->modules->expr('`lastUpdated` < ? - `refresh`', [$tikilib->now]); 488 } 489 490 $result = $this->modules->fetchAll(['rssId', 'url', 'actions'], $conditions); 491 492 foreach ($result as $row) { 493 $this->update_feed($row['rssId'], $row['url'], $row['actions']); 494 } 495 } 496 497 private function update_feed($rssId, $url, $actions) 498 { 499 global $tikilib; 500 501 $filter = new DeclFilter; 502 $filter->addStaticKeyFilters( 503 [ 504 'url' => 'url', 505 'title' => 'striptags', 506 'author' => 'striptags', 507 'description' => 'striptags', 508 'content' => 'purifier', 509 ] 510 ); 511 512 $guidFilter = TikiFilter::get('url'); 513 514 try { 515 $content = $tikilib->httprequest($url); 516 $feed = Zend\Feed\Reader\Reader::importString($content); 517 } catch (Zend\Feed\Exception\ExceptionInterface $e) { 518 $this->modules->update( 519 [ 520 'lastUpdated' => $tikilib->now, 521 'sitetitle' => 'N/A', 522 'siteurl' => '#', 523 ], 524 ['rssId' => $rssId,] 525 ); 526 return; 527 } 528 $siteTitle = TikiFilter::get('striptags')->filter($feed->getTitle()); 529 $siteUrl = TikiFilter::get('url')->filter($feed->getLink()); 530 531 $this->modules->update( 532 [ 533 'lastUpdated' => $tikilib->now, 534 'sitetitle' => $siteTitle, 535 'siteurl' => $siteUrl, 536 ], 537 ['rssId' => $rssId,] 538 ); 539 540 foreach ($feed as $entry) { // TODO: optimize. Atom entries have an 'updated' element which can be used to only update updated entries 541 $guid = $guidFilter->filter($entry->getId()); 542 543 $authors = $entry->getAuthors(); 544 545 $categories = $entry->getCategories(); 546 547 $link = $entry->getLink(); 548 if (! $link) { 549 $link = ''; 550 } 551 $description = $entry->getDescription(); 552 if (! $description) { 553 $description = ''; 554 } 555 $data = $filter->filter( 556 [ 557 'title' => $entry->getTitle(), 558 'url' => $link, 559 'description' => $description, 560 'content' => $entry->getContent(), 561 'author' => $authors ? implode(', ', $authors->getValues()) : '', 562 'categories' => $categories ? json_encode($categories->getValues()) : json_encode([]), 563 ] 564 ); 565 566 $data['guid'] = $guid; 567 if (method_exists($entry, 'getDateCreated') && $createdDate = $entry->getDateCreated()) { 568 $data['publication_date'] = $createdDate->getTimestamp(); 569 } else { 570 global $tikilib; 571 $data['publication_date'] = $tikilib->now; 572 } 573 574 $count = $this->items->fetchCount(['rssId' => $rssId, 'guid' => $guid]); 575 if (0 == $count) { 576 $this->insert_item($rssId, $data, $actions); 577 } else { 578 $this->update_item($rssId, $data['guid'], $data); 579 } 580 } 581 } 582 583 function get_feed_source_categories($rssId) 584 { 585 $feeds = $this->items->fetchAll(['categories'], ['rssId' => $rssId]); 586 $categories = []; 587 foreach ($feeds as $feed) { 588 if (isset($feed['categories'])) { 589 foreach (json_decode($feed['categories']) as $sourcecat) { 590 $categories[$sourcecat] = []; 591 } 592 } 593 } 594 $custom_info = $this->get_article_custom_info($rssId); 595 $categories = array_merge($categories, $custom_info); 596 ksort($categories, SORT_NATURAL); 597 return $categories; 598 } 599 600 function get_article_custom_info($rssId) 601 { 602 $result = $this->modules->fetchOne('actions', ['rssId' => $rssId]); 603 $actions = json_decode($result); 604 $categories = []; 605 foreach ($actions as $action) { 606 if (isset($action->custom_atype)) { 607 foreach ($action->custom_atype as $source_category => $atype) { 608 $categories[$source_category]['atype'] = $atype; 609 } 610 } 611 if (isset($action->custom_topic)) { 612 foreach ($action->custom_topic as $source_category => $topic) { 613 $categories[$source_category]['topic'] = $topic; 614 } 615 } 616 if (isset($action->custom_rating)) { 617 foreach ($action->custom_rating as $source_category => $rating) { 618 $categories[$source_category]['rating'] = $rating; 619 } 620 } 621 if (isset($action->custom_priority)) { 622 foreach ($action->custom_priority as $source_category => $priority) { 623 $categories[$source_category]['priority'] = $priority; 624 } 625 } 626 } 627 return $categories; 628 } 629 630 private function insert_item($rssId, $data, $actions) 631 { 632 $this->items->insert( 633 [ 634 'rssId' => $rssId, 635 'guid' => $data['guid'], 636 'url' => $data['url'], 637 'publication_date' => $data['publication_date'], 638 'title' => $data['title'], 639 'author' => $data['author'], 640 'description' => $data['description'], 641 'content' => $data['content'], 642 'categories' => $data['categories'], 643 ] 644 ); 645 646 $actions = json_decode($actions, true); 647 648 if (! empty($actions)) { 649 $pagecontentlib = TikiLib::lib('pagecontent'); 650 $data = $pagecontentlib->augmentInformation($data); 651 652 foreach ($actions as $action) { 653 $method = 'process_action_' . $action['type']; 654 unset($action['type']); 655 656 if ($action['active']) { 657 $this->$method($action, $data, $rssId); 658 } 659 } 660 } 661 } 662 663 private function update_item($rssId, $guid, $data) 664 { 665 // A feed may contain several entries with the same GUID... see http://framework.zend.com/issues/browse/ZF-10954. Assuming a single record would actually cause issues, see r37318. 666 $this->items->updateMultiple( 667 ['rssId' => $rssId, 'guid' => $guid,], 668 [ 669 'url' => $data['url'], 670 'publication_date' => $data['publication_date'], 671 'title' => $data['title'], 672 'author' => $data['author'], 673 'description' => $data['description'], 674 'content' => $data['content'], 675 ] 676 ); 677 } 678 679 private function process_action_article($configuration, $data, $rssId) 680 { 681 $tikilib = TikiLib::lib('tiki'); 682 $artlib = TikiLib::lib('art'); 683 $publication = $data['publication_date']; 684 685 // First override with custom settings for source categories if any 686 if (isset($data['categories'])) { 687 $source_categories = json_decode($data['categories'], true); 688 } 689 if (! empty($source_categories)) { 690 $custominfo = $this->get_article_custom_info($rssId); 691 692 $oldcats = array_keys($custominfo); 693 694 if ($newcats = array_diff($source_categories, $oldcats)) { 695 // send a notification if there are new categories 696 $nots = $tikilib->get_event_watches('article_submitted', '*'); 697 if (count($nots)) { 698 $title = $this->modules->fetchOne('name', ['rssId' => $rssId]); 699 include_once('lib/notifications/notificationemaillib.php'); 700 $smarty = TikiLib::lib('smarty'); 701 $smarty->assign('mail_site', $_SERVER['SERVER_NAME']); 702 $smarty->assign('rssId', $rssId); 703 $smarty->assign('title', $title); 704 $smarty->assign('newcats', $newcats); 705 sendEmailNotification($nots, 'watch', 'rss_new_source_category_subject.tpl', $_SERVER['SERVER_NAME'], 'rss_new_source_category.tpl'); 706 } 707 } 708 709 $current_priority = 0; 710 foreach ($custominfo as $source_category => $settings) { 711 if (in_array($source_category, $source_categories)) { 712 if (isset($settings['priority']) && $settings['priority'] < $current_priority) { 713 continue; 714 } 715 if (! empty($settings['atype'])) { 716 $configuration['atype'] = $settings['atype']; 717 } 718 if (isset($settings['topic']) && $settings['topic'] > '') { 719 // need to match 0 720 $configuration['topic'] = $settings['topic']; 721 } 722 if (isset($settings['rating']) && $settings['rating'] > '') { 723 // need to match 0 724 $configuration['rating'] = $settings['rating']; 725 } 726 $current_priority = isset($settings['priority']) ? $settings['priority'] : 0; 727 } 728 } 729 } 730 731 if ($configuration['future_publish'] > 0) { 732 $publication = $tikilib->now + $configuration['future_publish'] * 60; 733 } 734 735 $expire = $publication + 3600 * 24 * $configuration['expiry']; 736 737 if (strpos($data['content'], trim($data['description'])) === 0 && strlen($data['description']) < 1024) { 738 $data['content'] = substr($data['content'], strlen(trim($data['description']))); 739 } 740 $data['content'] = trim($data['content']) == '' ? $data['content'] : '~np~' . $data['content'] . '~/np~'; 741 742 if ($configuration['submission'] == true) { 743 $subid = $this->table('tiki_submissions')->fetchOne('subId', [ 744 'linkto' => $data['url'], 745 'topicId' => $configuration['topic'], 746 ]); 747 if (! $subid) { 748 $subid = 0; 749 } 750 $subid = $artlib->replace_submission( 751 $data['title'], 752 $data['author'], 753 $configuration['topic'], 754 'n', 755 '', 756 0, 757 '', 758 '', 759 $data['description'], 760 $data['content'], 761 $publication, 762 $expire, 763 'admin', 764 $subid, 765 0, 766 0, 767 $configuration['atype'], 768 '', 769 '', 770 $data['url'], 771 '', 772 $configuration['a_lang'], 773 $configuration['rating'] 774 ); 775 776 if (count($configuration['categories'])) { 777 $categlib = TikiLib::lib('categ'); 778 $objectId = $categlib->add_categorized_object('submission', $subid, $data['title'], $data['title'], 'tiki-edit_submission.php?subId=' . $subid); 779 780 foreach ($configuration['categories'] as $categId) { 781 $categlib->categorize($objectId, $categId); 782 } 783 } 784 } else { 785 $id = $this->table('tiki_articles')->fetchOne('articleId', [ 786 'linkto' => $data['url'], 787 'topicId' => $configuration['topic'], 788 ]); 789 if (! $id) { 790 $id = 0; 791 } 792 $id = $artlib->replace_article( 793 $data['title'], 794 $data['author'], 795 $configuration['topic'], 796 'n', 797 '', 798 0, 799 '', 800 '', 801 $data['description'], 802 $data['content'], 803 $publication, 804 $expire, 805 'admin', 806 $id, 807 0, 808 0, 809 $configuration['atype'], 810 '', 811 '', 812 $data['url'], 813 '', 814 $configuration['a_lang'], 815 $configuration['rating'] 816 ); 817 818 if (count($configuration['categories'])) { 819 $categlib = TikiLib::lib('categ'); 820 $objectId = $categlib->add_categorized_object('article', $id, $data['title'], $data['title'], 'tiki-read_article.php?articleId=' . $id); 821 822 foreach ($configuration['categories'] as $categId) { 823 $categlib->categorize($objectId, $categId); 824 } 825 } 826 827 TikiLib::lib('relation')->add_relation('tiki.rss.source', 'article', $id, 'rss', $rssId); 828 require_once('lib/search/refresh-functions.php'); 829 refresh_index('articles', $id); 830 $related_items = TikiLib::lib('relation')->get_relations_to('article', $id, 'tiki.article.attach'); 831 foreach ($related_items as $item) { 832 refresh_index($item['type'], $item['itemId']); 833 } 834 } 835 } 836 837 function set_article_generator($rssId, $configuration) 838 { 839 $configuration['type'] = 'article'; 840 841 $module = $this->get_rss_module($rssId); 842 843 if ($module['actions']) { 844 $actions = json_decode($module['actions'], true); 845 } else { 846 $actions = []; 847 } 848 849 $out = []; 850 foreach ($actions as $action) { 851 if ($action['type'] != 'article') { 852 $out[] = $action; 853 } 854 } 855 856 $out[] = $configuration; 857 858 $this->modules->update( 859 ['actions' => json_encode($out),], 860 ['rssId' => $rssId,] 861 ); 862 } 863 864 function get_article_generator($rssId) 865 { 866 $module = $this->get_rss_module($rssId); 867 868 if ($module['actions']) { 869 $actions = json_decode($module['actions'], true); 870 } else { 871 $actions = []; 872 } 873 874 $default = [ 875 'active' => false, 876 'expiry' => 365, 877 'atype' => 'Article', 878 'topic' => 0, 879 'future_publish' => -1, 880 'categories' => [], 881 'rating' => 5, 882 'feed_name' => $module['name'], 883 ]; 884 885 foreach ($actions as $action) { 886 if ($action['type'] == 'article') { 887 unset($action['type']); 888 return array_merge($default, $action); 889 } 890 } 891 892 return $default; 893 } 894 895 function generate_feed_from_data($data, $feed_descriptor) 896 { 897 require_once 'lib/smarty_tiki/modifier.sefurl.php'; 898 899 $tikilib = TikiLib::lib('tiki'); 900 $writer = new Zend\Feed\Writer\Feed(); 901 $writer->setTitle($feed_descriptor['feedTitle']); 902 $writer->setDescription($feed_descriptor['feedDescription']); 903 $writer->setLink($tikilib->tikiUrl('')); 904 $writer->setDateModified(time()); 905 906 foreach ($data as $row) { 907 $titleKey = $feed_descriptor['entryTitleKey']; 908 $url = $row[$feed_descriptor['entryUrlKey']]; 909 $title = $row[$titleKey]; 910 911 if (isset($feed_descriptor['entryObjectDescriptors'])) { 912 list($typeKey, $objectKey) = $feed_descriptor['entryObjectDescriptors']; 913 $object = $row[$objectKey]; 914 $type = $row[$typeKey]; 915 916 if (empty($url)) { 917 $url = smarty_modifier_sefurl($object, $type); 918 } 919 920 if (empty($title)) { 921 $title = TikiLib::lib('object')->get_title($type, $object); 922 } 923 } 924 925 $entry = $writer->createEntry(); 926 $entry->setTitle($title ? $title : tra('Unspecified')); 927 $entry->setLink($tikilib->tikiUrl($url)); 928 929 930 if (! empty($row[$feed_descriptor['entryModificationKey']])) { 931 $date = $row[$feed_descriptor['entryModificationKey']]; 932 if (! is_int($date)) { 933 $date = strtotime($date); 934 } 935 $entry->setDateModified($date); 936 } 937 938 $writer->addEntry($entry); 939 } 940 941 return $writer; 942 } 943} 944