summaryrefslogtreecommitdiff
path: root/classes/article.php
diff options
context:
space:
mode:
Diffstat (limited to 'classes/article.php')
-rwxr-xr-xclasses/article.php421
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 = " &mdash; " . 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 .= ", &hellip;";
-
- 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;
+ }
}