diff options
Diffstat (limited to 'classes/article.php')
-rwxr-xr-x | classes/article.php | 421 |
1 files changed, 153 insertions, 268 deletions
diff --git a/classes/article.php b/classes/article.php index 6d3746968..6baf8f068 100755 --- a/classes/article.php +++ b/classes/article.php @@ -5,7 +5,7 @@ class Article extends Handler_Protected { const ARTICLE_KIND_YOUTUBE = 3; function redirect() { - $id = clean($_REQUEST['id']); + $id = (int) clean($_REQUEST['id'] ?? 0); $sth = $this->pdo->prepare("SELECT link FROM ttrss_entries, ttrss_user_entries WHERE id = ? AND id = ref_id AND owner_uid = ? @@ -13,18 +13,21 @@ class Article extends Handler_Protected { $sth->execute([$id, $_SESSION['uid']]); if ($row = $sth->fetch()) { - $article_url = $row['link']; - $article_url = str_replace("\n", "", $article_url); + $article_url = UrlHelper::validate(str_replace("\n", "", $row['link'])); - header("Location: $article_url"); - return; + if ($article_url) { + header("Location: $article_url"); + } else { + header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found"); + print "URL of article $id is blank."; + } } else { print_error(__("Article not found.")); } } - static function create_published_article($title, $url, $content, $labels_str, + static function _create_published_article($title, $url, $content, $labels_str, $owner_uid) { $guid = 'SHA1:' . sha1("ttshared:" . $url . $owner_uid); // include owner_uid to prevent global GUID clash @@ -82,7 +85,7 @@ class Article extends Handler_Protected { content = ?, content_hash = ? WHERE id = ?"); $sth->execute([$content, $content_hash, $ref_id]); - if (DB_TYPE == "pgsql"){ + if (Config::get(Config::DB_TYPE) == "pgsql") { $sth = $pdo->prepare("UPDATE ttrss_entries SET tsvector_combined = to_tsvector( :ts_content) WHERE id = :id"); @@ -127,7 +130,7 @@ class Article extends Handler_Protected { if ($row = $sth->fetch()) { $ref_id = $row["id"]; - if (DB_TYPE == "pgsql"){ + if (Config::get(Config::DB_TYPE) == "pgsql"){ $sth = $pdo->prepare("UPDATE ttrss_entries SET tsvector_combined = to_tsvector( :ts_content) WHERE id = :id"); @@ -158,39 +161,15 @@ class Article extends Handler_Protected { return $rc; } - function editArticleTags() { - - $param = clean($_REQUEST['param']); - - $tags = self::get_article_tags($param); - - $tags_str = join(", ", $tags); - - print_hidden("id", "$param"); - print_hidden("op", "article"); - print_hidden("method", "setArticleTags"); - - print "<header class='horizontal'>" . __("Tags for this article (separated by commas):")."</header>"; - - print "<section>"; - print "<textarea dojoType='dijit.form.SimpleTextarea' rows='4' - style='height : 100px; font-size : 12px; width : 98%' id='tags_str' - name='tags_str'>$tags_str</textarea> - <div class='autocomplete' id='tags_choices' - style='display:none'></div>"; - print "</section>"; - - print "<footer>"; - print "<button dojoType='dijit.form.Button' - type='submit' class='alt-primary'>".__('Save')."</button> "; - print "<button dojoType='dijit.form.Button' - onclick='App.dialogOf(this).hide()'>".__('Cancel')."</button>"; - print "</footer>"; + function printArticleTags() { + $id = (int) clean($_REQUEST['id'] ?? 0); + print json_encode(["id" => $id, + "tags" => self::_get_tags($id)]); } function setScore() { - $ids = explode(",", clean($_REQUEST['id'])); + $ids = array_map("intval", clean($_REQUEST['ids'] ?? [])); $score = (int)clean($_REQUEST['score']); $ids_qmarks = arr_qmarks($ids); @@ -220,8 +199,10 @@ class Article extends Handler_Protected { $id = clean($_REQUEST["id"]); - $tags_str = clean($_REQUEST["tags_str"]); - $tags = array_unique(array_map('trim', explode(",", $tags_str))); + //$tags_str = clean($_REQUEST["tags_str"]); + //$tags = array_unique(array_map('trim', explode(",", $tags_str))); + + $tags = FeedItem_Common::normalize_categories(explode(",", clean($_REQUEST["tags_str"]))); $this->pdo->beginTransaction(); @@ -246,8 +227,6 @@ class Article extends Handler_Protected { (post_int_id, owner_uid, tag_name) VALUES (?, ?, ?)"); - $tags = FeedItem_Common::normalize_categories($tags); - foreach ($tags as $tag) { $csth->execute([$int_id, $_SESSION['uid'], $tag]); @@ -269,18 +248,12 @@ class Article extends Handler_Protected { $this->pdo->commit(); - $tags = self::get_article_tags($id); - $tags_str = $this->format_tags_string($tags); - $tags_str_full = join(", ", $tags); - - if (!$tags_str_full) $tags_str_full = __("no tags"); - - print json_encode(array("id" => (int)$id, - "content" => $tags_str, "content_full" => $tags_str_full)); + // get latest tags from the database, original $tags is sometimes JSON-encoded as a hash ({}) - ??? + print json_encode(["id" => (int)$id, "tags" => $this->_get_tags($id)]); } - function completeTags() { + /*function completeTags() { $search = clean($_REQUEST["search"]); $sth = $this->pdo->prepare("SELECT DISTINCT tag_name FROM ttrss_tags @@ -295,17 +268,17 @@ class Article extends Handler_Protected { print "<li>" . $line["tag_name"] . "</li>"; } print "</ul>"; - } + }*/ function assigntolabel() { - return $this->labelops(true); + return $this->_label_ops(true); } function removefromlabel() { - return $this->labelops(false); + return $this->_label_ops(false); } - private function labelops($assign) { + private function _label_ops($assign) { $reply = array(); $ids = explode(",", clean($_REQUEST["ids"])); @@ -313,22 +286,17 @@ class Article extends Handler_Protected { $label = Labels::find_caption($label_id, $_SESSION["uid"]); - $reply["info-for-headlines"] = array(); + $reply["labels-for"] = []; if ($label) { - foreach ($ids as $id) { - if ($assign) Labels::add_article($id, $label, $_SESSION["uid"]); else Labels::remove_article($id, $label, $_SESSION["uid"]); - $labels = $this->get_article_labels($id, $_SESSION["uid"]); - - array_push($reply["info-for-headlines"], - array("id" => $id, "labels" => $this->format_article_labels($labels))); - + array_push($reply["labels-for"], + ["id" => (int)$id, "labels" => $this->_get_labels($id)]); } } @@ -337,163 +305,84 @@ class Article extends Handler_Protected { print json_encode($reply); } - function getArticleFeed($id) { - $sth = $this->pdo->prepare("SELECT feed_id FROM ttrss_user_entries - WHERE ref_id = ? AND owner_uid = ?"); - $sth->execute([$id, $_SESSION['uid']]); - - if ($row = $sth->fetch()) { - return $row["feed_id"]; - } else { - return 0; - } - } - - static function format_article_enclosures($id, $always_display_enclosures, - $article_content, $hide_images = false) { - - $result = self::get_article_enclosures($id); - $rv = ''; + static function _format_enclosures($id, + $always_display_enclosures, + $article_content, + $hide_images = false) { + + $enclosures = self::_get_enclosures($id); + $enclosures_formatted = ""; + + /*foreach ($enclosures as &$enc) { + array_push($enclosures, [ + "type" => $enc["content_type"], + "filename" => basename($enc["content_url"]), + "url" => $enc["content_url"], + "title" => $enc["title"], + "width" => (int) $enc["width"], + "height" => (int) $enc["height"] + ]); + }*/ PluginHost::getInstance()->chain_hooks_callback(PluginHost::HOOK_FORMAT_ENCLOSURES, - function ($result) use (&$rv) { + function ($result) use (&$enclosures_formatted, &$enclosures) { if (is_array($result)) { - $rv = $result[0]; - $result = $result[1]; + $enclosures_formatted = $result[0]; + $enclosures = $result[1]; } else { - $rv = $result; + $enclosures_formatted = $result; } }, - $rv, $result, $id, $always_display_enclosures, $article_content, $hide_images); + $enclosures_formatted, $enclosures, $id, $always_display_enclosures, $article_content, $hide_images); - if ($rv === '' && !empty($result)) { - $entries_html = array(); - $entries = array(); - $entries_inline = array(); - - foreach ($result as $line) { - - PluginHost::getInstance()->chain_hooks_callback(PluginHost::HOOK_ENCLOSURE_ENTRY, - function($result) use (&$line) { - $line = $result; - }, - $line, $id); - - $url = $line["content_url"]; - $ctype = $line["content_type"]; - $title = $line["title"]; - $width = $line["width"]; - $height = $line["height"]; - - if (!$ctype) $ctype = __("unknown type"); - - //$filename = substr($url, strrpos($url, "/")+1); - $filename = basename($url); - - $player = format_inline_player($url, $ctype); - - if ($player) array_push($entries_inline, $player); + if (!empty($enclosures_formatted)) { + return [ + 'formatted' => $enclosures_formatted, + 'entries' => [] + ]; + } -# $entry .= " <a target=\"_blank\" href=\"" . htmlspecialchars($url) . "\" rel=\"noopener noreferrer\">" . -# $filename . " (" . $ctype . ")" . "</a>"; + $rv = [ + 'formatted' => '', + 'entries' => [] + ]; - $entry = "<div onclick=\"Article.popupOpenUrl('".htmlspecialchars($url)."')\" - dojoType=\"dijit.MenuItem\">$filename ($ctype)</div>"; + $rv['can_inline'] = isset($_SESSION["uid"]) && + empty($_SESSION["bw_limit"]) && + !get_pref("STRIP_IMAGES") && + ($always_display_enclosures || !preg_match("/<img/i", $article_content)); - array_push($entries_html, $entry); + $rv['inline_text_only'] = $hide_images && $rv['can_inline']; - $entry = array(); + foreach ($enclosures as $enc) { - $entry["type"] = $ctype; - $entry["filename"] = $filename; - $entry["url"] = $url; - $entry["title"] = $title; - $entry["width"] = $width; - $entry["height"] = $height; + // this is highly approximate + $enc["filename"] = basename($enc["content_url"]); - array_push($entries, $entry); - } + $rendered_enc = ""; + PluginHost::getInstance()->chain_hooks_callback(PluginHost::HOOK_RENDER_ENCLOSURE, + function ($result) use (&$rendered_enc) { + $rendered_enc = $result; + }, + $enc, $id, $rv); - if ($_SESSION['uid'] && !get_pref("STRIP_IMAGES") && !$_SESSION["bw_limit"]) { - if ($always_display_enclosures || - !preg_match("/<img/i", $article_content)) { - - foreach ($entries as $entry) { - - $retval = null; - - PluginHost::getInstance()->chain_hooks_callback(PluginHost::HOOK_RENDER_ENCLOSURE, - function($result) use (&$retval) { - $retval = $result; - }, - $entry, $hide_images); - - if (!empty($retval)) { - $rv .= $retval; - } else { - - if (preg_match("/image/", $entry["type"])) { - - if (!$hide_images) { - $encsize = ''; - if ($entry['height'] > 0) - $encsize .= ' height="' . intval($entry['height']) . '"'; - if ($entry['width'] > 0) - $encsize .= ' width="' . intval($entry['width']) . '"'; - $rv .= "<p><img - alt=\"".htmlspecialchars($entry["filename"])."\" - src=\"" .htmlspecialchars($entry["url"]) . "\" - " . $encsize . " /></p>"; - } else { - $rv .= "<p><a target=\"_blank\" rel=\"noopener noreferrer\" - href=\"".htmlspecialchars($entry["url"])."\" - >" .htmlspecialchars($entry["url"]) . "</a></p>"; - } - - if ($entry['title']) { - $rv.= "<div class=\"enclosure_title\">${entry['title']}</div>"; - } - } - } - } - } - } + if ($rendered_enc) { + $rv['formatted'] .= $rendered_enc; + } else { + PluginHost::getInstance()->chain_hooks_callback(PluginHost::HOOK_ENCLOSURE_ENTRY, + function ($result) use (&$enc) { + $enc = $result; + }, + $enc, $id, $rv); - if (count($entries_inline) > 0) { - //$rv .= "<hr clear='both'/>"; - foreach ($entries_inline as $entry) { $rv .= $entry; }; - $rv .= "<br clear='both'/>"; + array_push($rv['entries'], $enc); } - - $rv .= "<div class=\"attachments\" dojoType=\"fox.form.DropDownButton\">". - "<span>" . __('Attachments')."</span>"; - - $rv .= "<div dojoType=\"dijit.Menu\" style=\"display: none;\">"; - - foreach ($entries as $entry) { - if ($entry["title"]) - $title = " — " . truncate_string($entry["title"], 30); - else - $title = ""; - - if ($entry["filename"]) - $filename = truncate_middle(htmlspecialchars($entry["filename"]), 60); - else - $filename = ""; - - $rv .= "<div onclick='Article.popupOpenUrl(\"".htmlspecialchars($entry["url"])."\")' - dojoType=\"dijit.MenuItem\">".$filename . $title."</div>"; - - }; - - $rv .= "</div>"; - $rv .= "</div>"; } return $rv; } - static function get_article_tags($id, $owner_uid = 0, $tag_cache = false) { + static function _get_tags($id, $owner_uid = 0, $tag_cache = false) { $a_id = $id; @@ -543,59 +432,22 @@ class Article extends Handler_Protected { return $tags; } - static function format_tags_string($tags) { - if (!is_array($tags) || count($tags) == 0) { - return __("no tags"); - } else { - $maxtags = min(5, count($tags)); - $tags_str = ""; - - for ($i = 0; $i < $maxtags; $i++) { - $tags_str .= "<a class=\"tag\" href=\"#\" onclick=\"Feeds.open({feed:'".$tags[$i]."'})\">" . $tags[$i] . "</a>, "; - } - - $tags_str = mb_substr($tags_str, 0, mb_strlen($tags_str)-2); - - if (count($tags) > $maxtags) - $tags_str .= ", …"; - - return $tags_str; - } - } - - static function format_article_labels($labels) { - - if (!is_array($labels)) return ''; - - $labels_str = ""; - - foreach ($labels as $l) { - $labels_str .= sprintf("<div class='label' - style='color : %s; background-color : %s'>%s</div>", - $l[2], $l[3], $l[1]); - } - - return $labels_str; + function getmetadatabyid() { + $id = clean($_REQUEST['id']); - } + $sth = $this->pdo->prepare("SELECT link, title FROM ttrss_entries, ttrss_user_entries + WHERE ref_id = ? AND ref_id = id AND owner_uid = ?"); + $sth->execute([$id, $_SESSION['uid']]); - static function format_article_note($id, $note, $allow_edit = true) { + if ($row = $sth->fetch()) { + $link = $row['link']; + $title = $row['title']; - if ($allow_edit) { - $onclick = "onclick='Plugins.Note.edit($id)'"; - $note_class = 'editable'; - } else { - $onclick = ''; - $note_class = ''; + echo json_encode(["link" => $link, "title" => $title]); } - - return "<div class='article-note $note_class'> - <i class='material-icons'>note</i> - <div $onclick class='body'>$note</div> - </div>"; } - static function get_article_enclosures($id) { + static function _get_enclosures($id) { $pdo = Db::pdo(); @@ -607,10 +459,10 @@ class Article extends Handler_Protected { $cache = new DiskCache("images"); - while ($line = $sth->fetch()) { + while ($line = $sth->fetch(PDO::FETCH_ASSOC)) { if ($cache->exists(sha1($line["content_url"]))) { - $line["content_url"] = $cache->getUrl(sha1($line["content_url"])); + $line["content_url"] = $cache->get_url(sha1($line["content_url"])); } array_push($rv, $line); @@ -619,11 +471,11 @@ class Article extends Handler_Protected { return $rv; } - static function purge_orphans() { + static function _purge_orphans() { // purge orphaned posts in main content table - if (DB_TYPE == "mysql") + if (Config::get(Config::DB_TYPE) == "mysql") $limit_qpart = "LIMIT 5000"; else $limit_qpart = ""; @@ -638,7 +490,7 @@ class Article extends Handler_Protected { } } - static function catchupArticlesById($ids, $cmode, $owner_uid = false) { + static function _catchup_by_id($ids, $cmode, $owner_uid = false) { if (!$owner_uid) $owner_uid = $_SESSION["uid"]; @@ -663,21 +515,7 @@ class Article extends Handler_Protected { $sth->execute(array_merge($ids, [$owner_uid])); } - static function getLastArticleId() { - $pdo = Db::pdo(); - - $sth = $pdo->prepare("SELECT ref_id AS id FROM ttrss_user_entries - WHERE owner_uid = ? ORDER BY ref_id DESC LIMIT 1"); - $sth->execute([$_SESSION['uid']]); - - if ($row = $sth->fetch()) { - return $row['id']; - } else { - return -1; - } - } - - static function get_article_labels($id, $owner_uid = false) { + static function _get_labels($id, $owner_uid = false) { $rv = array(); if (!$owner_uid) $owner_uid = $_SESSION["uid"]; @@ -724,7 +562,7 @@ class Article extends Handler_Protected { return $rv; } - static function get_article_image($enclosures, $content, $site_url) { + static function _get_image($enclosures, $content, $site_url) { $article_image = ""; $article_stream = ""; @@ -794,12 +632,59 @@ class Article extends Handler_Protected { $cache = new DiskCache("images"); if ($article_image && $cache->exists(sha1($article_image))) - $article_image = $cache->getUrl(sha1($article_image)); + $article_image = $cache->get_url(sha1($article_image)); if ($article_stream && $cache->exists(sha1($article_stream))) - $article_stream = $cache->getUrl(sha1($article_stream)); + $article_stream = $cache->get_url(sha1($article_stream)); return [$article_image, $article_stream, $article_kind]; } + // only cached, returns label ids (not label feed ids) + static function _labels_of(array $article_ids) { + if (count($article_ids) == 0) + return []; + + $id_qmarks = arr_qmarks($article_ids); + + $sth = Db::pdo()->prepare("SELECT DISTINCT label_cache FROM ttrss_entries e, ttrss_user_entries ue + WHERE ue.ref_id = e.id AND id IN ($id_qmarks)"); + + $sth->execute($article_ids); + + $rv = []; + + while ($row = $sth->fetch()) { + $labels = json_decode($row["label_cache"]); + + if (isset($labels) && is_array($labels)) { + foreach ($labels as $label) { + if (empty($label["no-labels"])) + array_push($rv, Labels::feed_to_label_id($label[0])); + } + } + } + + return array_unique($rv); + } + + static function _feeds_of(array $article_ids) { + if (count($article_ids) == 0) + return []; + + $id_qmarks = arr_qmarks($article_ids); + + $sth = Db::pdo()->prepare("SELECT DISTINCT feed_id FROM ttrss_entries e, ttrss_user_entries ue + WHERE ue.ref_id = e.id AND id IN ($id_qmarks)"); + + $sth->execute($article_ids); + + $rv = []; + + while ($row = $sth->fetch()) { + array_push($rv, $row["feed_id"]); + } + + return $rv; + } } |