1 | <?php |
||||||||
2 | require_once "colors.php"; |
||||||||
3 | |||||||||
4 | class Feeds extends Handler_Protected { |
||||||||
5 | const NEVER_GROUP_FEEDS = [ -6, 0]; |
||||||||
6 | const NEVER_GROUP_BY_DATE = [ -2, -1, -3]; |
||||||||
7 | |||||||||
8 | private $params; |
||||||||
9 | |||||||||
10 | function csrf_ignore($method) { |
||||||||
11 | $csrf_ignored = array("index", "quickaddfeed", "search"); |
||||||||
12 | |||||||||
13 | return array_search($method, $csrf_ignored) !== false; |
||||||||
14 | } |
||||||||
15 | |||||||||
16 | private function format_headline_subtoolbar($feed_site_url, $feed_title, |
||||||||
17 | $feed_id, $is_cat, $search, |
||||||||
18 | $error, $feed_last_updated) { |
||||||||
19 | |||||||||
20 | if ($is_cat) { |
||||||||
21 | $cat_q = "&is_cat=$is_cat"; |
||||||||
22 | } |
||||||||
23 | |||||||||
24 | if ($search) { |
||||||||
25 | $search_q = "&q=$search"; |
||||||||
26 | } else { |
||||||||
27 | $search_q = ""; |
||||||||
28 | } |
||||||||
29 | |||||||||
30 | $reply = ""; |
||||||||
31 | |||||||||
32 | $rss_link = htmlspecialchars(get_self_url_prefix(). |
||||||||
33 | "/public.php?op=rss&id=$feed_id$cat_q$search_q"); |
||||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
![]() |
|||||||||
34 | |||||||||
35 | $reply .= "<span class='left'>"; |
||||||||
36 | |||||||||
37 | $reply .= "<a href=\"#\" |
||||||||
38 | title=\"".__("Show as feed")."\" |
||||||||
39 | onclick=\"App.displayDlg('".__("Show as feed")."','generatedFeed', '$feed_id:$is_cat:$rss_link')\"> |
||||||||
40 | <i class='icon-syndicate material-icons'>rss_feed</i></a>"; |
||||||||
41 | |||||||||
42 | $reply .= "<span id='feed_title'>"; |
||||||||
43 | |||||||||
44 | if ($feed_site_url) { |
||||||||
45 | $last_updated = T_sprintf("Last updated: %s", $feed_last_updated); |
||||||||
46 | |||||||||
47 | $reply .= "<a title=\"$last_updated\" target='_blank' href=\"$feed_site_url\">". |
||||||||
48 | truncate_string(strip_tags($feed_title), 30)."</a>"; |
||||||||
49 | } else { |
||||||||
50 | $reply .= strip_tags($feed_title); |
||||||||
51 | } |
||||||||
52 | |||||||||
53 | if ($error) { |
||||||||
54 | $reply .= " <i title=\"".htmlspecialchars($error)."\" class='material-icons icon-error'>error</i>"; |
||||||||
55 | } |
||||||||
56 | |||||||||
57 | $reply .= "</span>"; |
||||||||
58 | $reply .= "<span id='feed_current_unread' style='display: none'></span>"; |
||||||||
59 | $reply .= "</span>"; |
||||||||
60 | |||||||||
61 | $reply .= "<span class=\"right\">"; |
||||||||
62 | $reply .= "<span id='selected_prompt'></span>"; |
||||||||
63 | $reply .= " "; |
||||||||
64 | $reply .= "<select dojoType=\"fox.form.Select\" |
||||||||
65 | onchange=\"Headlines.onActionChanged(this)\">"; |
||||||||
66 | |||||||||
67 | $reply .= "<option value=\"0\" disabled='1'>".__('Select...')."</option>"; |
||||||||
68 | |||||||||
69 | $reply .= "<option value=\"Headlines.select('all')\">".__('All')."</option>"; |
||||||||
70 | $reply .= "<option value=\"Headlines.select('unread')\">".__('Unread')."</option>"; |
||||||||
71 | $reply .= "<option value=\"Headlines.select('invert')\">".__('Invert')."</option>"; |
||||||||
72 | $reply .= "<option value=\"Headlines.select('none')\">".__('None')."</option>"; |
||||||||
73 | |||||||||
74 | $reply .= "<option value=\"0\" disabled=\"1\">".__('Selection toggle:')."</option>"; |
||||||||
75 | |||||||||
76 | $reply .= "<option value=\"Headlines.selectionToggleUnread()\">".__('Unread')."</option> |
||||||||
77 | <option value=\"Headlines.selectionToggleMarked()\">".__('Starred')."</option> |
||||||||
78 | <option value=\"Headlines.selectionTogglePublished()\">".__('Published')."</option>"; |
||||||||
79 | |||||||||
80 | $reply .= "<option value=\"0\" disabled=\"1\">".__('Selection:')."</option>"; |
||||||||
81 | |||||||||
82 | $reply .= "<option value=\"Headlines.catchupSelection()\">".__('Mark as read')."</option>"; |
||||||||
83 | $reply .= "<option value=\"Article.selectionSetScore()\">".__('Set score')."</option>"; |
||||||||
84 | |||||||||
85 | if ($feed_id == 0 && !$is_cat) { |
||||||||
86 | $reply .= "<option value=\"Headlines.archiveSelection()\">".__('Move back')."</option>"; |
||||||||
87 | $reply .= "<option value=\"Headlines.deleteSelection()\">".__('Delete')."</option>"; |
||||||||
88 | } else { |
||||||||
89 | $reply .= "<option value=\"Headlines.archiveSelection()\">".__('Archive')."</option>"; |
||||||||
90 | } |
||||||||
91 | |||||||||
92 | if (PluginHost::getInstance()->get_plugin("mail")) { |
||||||||
93 | $reply .= "<option value=\"Plugins.Mail.send()\">".__('Forward by email'). |
||||||||
94 | "</option>"; |
||||||||
95 | } |
||||||||
96 | |||||||||
97 | if (PluginHost::getInstance()->get_plugin("mailto")) { |
||||||||
98 | $reply .= "<option value=\"Plugins.Mailto.send()\">".__('Forward by email'). |
||||||||
99 | "</option>"; |
||||||||
100 | } |
||||||||
101 | |||||||||
102 | $reply .= "<option value=\"0\" disabled=\"1\">".__('Feed:')."</option>"; |
||||||||
103 | |||||||||
104 | //$reply .= "<option value=\"catchupPage()\">".__('Mark as read')."</option>"; |
||||||||
105 | |||||||||
106 | $reply .= "<option value=\"App.displayDlg('".__("Show as feed")."','generatedFeed', '$feed_id:$is_cat:$rss_link')\">". |
||||||||
107 | __('Show as feed')."</option>"; |
||||||||
108 | |||||||||
109 | $reply .= "</select>"; |
||||||||
110 | |||||||||
111 | //$reply .= "</h2"; |
||||||||
112 | |||||||||
113 | foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_HEADLINE_TOOLBAR_BUTTON) as $p) { |
||||||||
114 | $reply .= $p->hook_headline_toolbar_button($feed_id, $is_cat); |
||||||||
115 | } |
||||||||
116 | |||||||||
117 | $reply .= "</span>"; |
||||||||
118 | |||||||||
119 | return $reply; |
||||||||
120 | } |
||||||||
121 | |||||||||
122 | private function format_headlines_list($feed, $method, $view_mode, $limit, $cat_view, |
||||||||
123 | $offset, $override_order = false, $include_children = false, $check_first_id = false, |
||||||||
124 | $skip_first_id_check = false, $order_by = false) { |
||||||||
125 | |||||||||
126 | $disable_cache = false; |
||||||||
127 | |||||||||
128 | $reply = array(); |
||||||||
129 | |||||||||
130 | $rgba_cache = array(); |
||||||||
131 | $topmost_article_ids = array(); |
||||||||
132 | |||||||||
133 | if (!$offset) { |
||||||||
134 | $offset = 0; |
||||||||
135 | } |
||||||||
136 | if ($method == "undefined") { |
||||||||
137 | $method = ""; |
||||||||
138 | } |
||||||||
139 | |||||||||
140 | $method_split = explode(":", $method); |
||||||||
141 | |||||||||
142 | if ($method == "ForceUpdate" && $feed > 0 && is_numeric($feed)) { |
||||||||
143 | $sth = $this->pdo->prepare("UPDATE ttrss_feeds |
||||||||
144 | SET last_updated = '1970-01-01', last_update_started = '1970-01-01' |
||||||||
145 | WHERE id = ?"); |
||||||||
146 | $sth->execute([$feed]); |
||||||||
147 | } |
||||||||
148 | |||||||||
149 | if ($method_split[0] == "MarkAllReadGR") { |
||||||||
150 | $this->catchup_feed($method_split[1], false); |
||||||||
151 | } |
||||||||
152 | |||||||||
153 | // FIXME: might break tag display? |
||||||||
154 | |||||||||
155 | if (is_numeric($feed) && $feed > 0 && !$cat_view) { |
||||||||
156 | $sth = $this->pdo->prepare("SELECT id FROM ttrss_feeds WHERE id = ? LIMIT 1"); |
||||||||
157 | $sth->execute([$feed]); |
||||||||
158 | |||||||||
159 | if (!$sth->fetch()) { |
||||||||
160 | $reply['content'] = "<div align='center'>".__('Feed not found.')."</div>"; |
||||||||
161 | } |
||||||||
162 | } |
||||||||
163 | |||||||||
164 | @$search = $_REQUEST["query"]; |
||||||||
165 | @$search_language = $_REQUEST["search_language"]; // PGSQL only |
||||||||
166 | |||||||||
167 | if ($search) { |
||||||||
168 | $disable_cache = true; |
||||||||
169 | } |
||||||||
170 | |||||||||
171 | if (!$cat_view && is_numeric($feed) && $feed < PLUGIN_FEED_BASE_INDEX && $feed > LABEL_BASE_INDEX) { |
||||||||
172 | $handler = PluginHost::getInstance()->get_feed_handler( |
||||||||
173 | PluginHost::feed_to_pfeed_id($feed)); |
||||||||
174 | |||||||||
175 | if ($handler) { |
||||||||
176 | $options = array( |
||||||||
177 | "limit" => $limit, |
||||||||
178 | "view_mode" => $view_mode, |
||||||||
179 | "cat_view" => $cat_view, |
||||||||
180 | "search" => $search, |
||||||||
181 | "override_order" => $override_order, |
||||||||
182 | "offset" => $offset, |
||||||||
183 | "owner_uid" => $_SESSION["uid"], |
||||||||
184 | "filter" => false, |
||||||||
185 | "since_id" => 0, |
||||||||
186 | "include_children" => $include_children, |
||||||||
187 | "order_by" => $order_by); |
||||||||
188 | |||||||||
189 | $qfh_ret = $handler->get_headlines(PluginHost::feed_to_pfeed_id($feed), |
||||||||
190 | $options); |
||||||||
191 | } |
||||||||
192 | |||||||||
193 | } else { |
||||||||
194 | |||||||||
195 | $params = array( |
||||||||
196 | "feed" => $feed, |
||||||||
197 | "limit" => $limit, |
||||||||
198 | "view_mode" => $view_mode, |
||||||||
199 | "cat_view" => $cat_view, |
||||||||
200 | "search" => $search, |
||||||||
201 | "search_language" => $search_language, |
||||||||
202 | "override_order" => $override_order, |
||||||||
203 | "offset" => $offset, |
||||||||
204 | "include_children" => $include_children, |
||||||||
205 | "check_first_id" => $check_first_id, |
||||||||
206 | "skip_first_id_check" => $skip_first_id_check, |
||||||||
207 | "order_by" => $order_by |
||||||||
208 | ); |
||||||||
209 | |||||||||
210 | $qfh_ret = $this->queryFeedHeadlines($params); |
||||||||
211 | } |
||||||||
212 | |||||||||
213 | $vfeed_group_enabled = get_pref("VFEED_GROUP_BY_FEED") && |
||||||||
214 | !(in_array($feed, Feeds::NEVER_GROUP_FEEDS) && !$cat_view); |
||||||||
215 | |||||||||
216 | $result = $qfh_ret[0]; // this could be either a PDO query result or a -1 if first id changed |
||||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||||||
217 | $feed_title = $qfh_ret[1]; |
||||||||
218 | $feed_site_url = $qfh_ret[2]; |
||||||||
219 | $last_error = $qfh_ret[3]; |
||||||||
220 | $last_updated = strpos($qfh_ret[4], '1970-') === false ? |
||||||||
221 | make_local_datetime($qfh_ret[4], false) : __("Never"); |
||||||||
222 | $highlight_words = $qfh_ret[5]; |
||||||||
223 | $reply['first_id'] = $qfh_ret[6]; |
||||||||
224 | $reply['is_vfeed'] = $qfh_ret[7]; |
||||||||
225 | $query_error_override = $qfh_ret[8]; |
||||||||
226 | |||||||||
227 | $reply['search_query'] = [$search, $search_language]; |
||||||||
228 | $reply['vfeed_group_enabled'] = $vfeed_group_enabled; |
||||||||
229 | |||||||||
230 | $reply['toolbar'] = $this->format_headline_subtoolbar($feed_site_url, |
||||||||
231 | $feed_title, |
||||||||
232 | $feed, $cat_view, $search, |
||||||||
233 | $last_error, $last_updated); |
||||||||
234 | |||||||||
235 | if ($offset == 0) { |
||||||||
236 | foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_HEADLINES_BEFORE) as $p) { |
||||||||
237 | $reply['content'] .= $p->hook_headlines_before($feed, $cat_view, $qfh_ret); |
||||||||
238 | } |
||||||||
239 | } |
||||||||
240 | |||||||||
241 | $reply['content'] = []; |
||||||||
242 | |||||||||
243 | $headlines_count = 0; |
||||||||
244 | |||||||||
245 | if (is_object($result)) { |
||||||||
246 | while ($line = $result->fetch(PDO::FETCH_ASSOC)) { |
||||||||
247 | |||||||||
248 | ++$headlines_count; |
||||||||
249 | |||||||||
250 | if (!get_pref('SHOW_CONTENT_PREVIEW')) { |
||||||||
251 | $line["content_preview"] = ""; |
||||||||
252 | } else { |
||||||||
253 | $line["content_preview"] = "— ".truncate_string(strip_tags($line["content"]), 250); |
||||||||
254 | |||||||||
255 | foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_QUERY_HEADLINES) as $p) { |
||||||||
256 | $line = $p->hook_query_headlines($line, 250, false); |
||||||||
257 | } |
||||||||
258 | } |
||||||||
259 | |||||||||
260 | $id = $line["id"]; |
||||||||
261 | |||||||||
262 | // frontend doesn't expect pdo returning booleans as strings on mysql |
||||||||
263 | if (DB_TYPE == "mysql") { |
||||||||
0 ignored issues
–
show
|
|||||||||
264 | foreach (["unread", "marked", "published"] as $k) { |
||||||||
265 | $line[$k] = $line[$k] === "1"; |
||||||||
266 | } |
||||||||
267 | } |
||||||||
268 | |||||||||
269 | // normalize archived feed |
||||||||
270 | if ($line['feed_id'] === null) { |
||||||||
271 | $line['feed_id'] = 0; |
||||||||
272 | $line["feed_title"] = __("Archived articles"); |
||||||||
273 | } |
||||||||
274 | |||||||||
275 | $feed_id = $line["feed_id"]; |
||||||||
276 | |||||||||
277 | $label_cache = $line["label_cache"]; |
||||||||
278 | $labels = false; |
||||||||
279 | |||||||||
280 | if ($label_cache) { |
||||||||
281 | $label_cache = json_decode($label_cache, true); |
||||||||
282 | |||||||||
283 | if ($label_cache) { |
||||||||
284 | if ($label_cache["no-labels"] == 1) { |
||||||||
285 | $labels = array(); |
||||||||
286 | } else { |
||||||||
287 | $labels = $label_cache; |
||||||||
288 | } |
||||||||
289 | } |
||||||||
290 | } |
||||||||
291 | |||||||||
292 | if (!is_array($labels)) { |
||||||||
293 | $labels = Article::get_article_labels($id); |
||||||||
294 | } |
||||||||
295 | |||||||||
296 | $labels_str = "<span class=\"HLLCTR-$id\">"; |
||||||||
297 | $labels_str .= Article::format_article_labels($labels); |
||||||||
298 | $labels_str .= "</span>"; |
||||||||
299 | |||||||||
300 | $line["labels"] = $labels_str; |
||||||||
301 | |||||||||
302 | if (count($topmost_article_ids) < 3) { |
||||||||
303 | array_push($topmost_article_ids, $id); |
||||||||
304 | } |
||||||||
305 | |||||||||
306 | if (!$line["feed_title"]) { |
||||||||
307 | $line["feed_title"] = ""; |
||||||||
308 | } |
||||||||
309 | |||||||||
310 | $line["buttons_left"] = ""; |
||||||||
311 | foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_ARTICLE_LEFT_BUTTON) as $p) { |
||||||||
312 | $line["buttons_left"] .= $p->hook_article_left_button($line); |
||||||||
313 | } |
||||||||
314 | |||||||||
315 | $line["buttons"] = ""; |
||||||||
316 | foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_ARTICLE_BUTTON) as $p) { |
||||||||
317 | $line["buttons"] .= $p->hook_article_button($line); |
||||||||
318 | } |
||||||||
319 | |||||||||
320 | $line["content"] = sanitize($line["content"], |
||||||||
321 | $line['hide_images'], false, $line["site_url"], $highlight_words, $line["id"]); |
||||||||
322 | |||||||||
323 | foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_RENDER_ARTICLE_CDM) as $p) { |
||||||||
324 | $line = $p->hook_render_article_cdm($line); |
||||||||
325 | } |
||||||||
326 | |||||||||
327 | $line['content'] = DiskCache::rewriteUrls($line['content']); |
||||||||
328 | |||||||||
329 | if ($line['note']) { |
||||||||
330 | $line['note'] = Article::format_article_note($id, $line['note']); |
||||||||
331 | } else { |
||||||||
332 | $line['note'] = ""; |
||||||||
333 | } |
||||||||
334 | |||||||||
335 | if (!get_pref("CDM_EXPANDED")) { |
||||||||
336 | $line["cdm_excerpt"] = "<span class='collapse'> |
||||||||
337 | <i class='material-icons' onclick='return Article.cdmUnsetActive(event)' |
||||||||
338 | title=\"" . __("Collapse article")."\">remove_circle</i></span>"; |
||||||||
339 | |||||||||
340 | if (get_pref('SHOW_CONTENT_PREVIEW')) { |
||||||||
341 | $line["cdm_excerpt"] .= "<span class='excerpt'>".$line["content_preview"]."</span>"; |
||||||||
342 | } |
||||||||
343 | } |
||||||||
344 | |||||||||
345 | $line["enclosures"] = Article::format_article_enclosures($id, $line["always_display_enclosures"], |
||||||||
346 | $line["content"], $line["hide_images"]); |
||||||||
347 | |||||||||
348 | if ($line["orig_feed_id"]) { |
||||||||
349 | |||||||||
350 | $ofgh = $this->pdo->prepare("SELECT * FROM ttrss_archived_feeds |
||||||||
351 | WHERE id = ? AND owner_uid = ?"); |
||||||||
352 | $ofgh->execute([$line["orig_feed_id"], $_SESSION['uid']]); |
||||||||
353 | |||||||||
354 | if ($tmp_line = $ofgh->fetch()) { |
||||||||
355 | $line["orig_feed"] = [$tmp_line["title"], $tmp_line["site_url"], $tmp_line["feed_url"]]; |
||||||||
356 | } |
||||||||
357 | } |
||||||||
358 | |||||||||
359 | $line["updated_long"] = make_local_datetime($line["updated"], true); |
||||||||
360 | $line["updated"] = make_local_datetime($line["updated"], false, false, false, true); |
||||||||
361 | |||||||||
362 | |||||||||
363 | $line['imported'] = T_sprintf("Imported at %s", |
||||||||
364 | make_local_datetime($line["date_entered"], false)); |
||||||||
365 | |||||||||
366 | if ($line["tag_cache"]) { |
||||||||
367 | $tags = explode(",", $line["tag_cache"]); |
||||||||
368 | } else { |
||||||||
369 | $tags = false; |
||||||||
370 | } |
||||||||
371 | |||||||||
372 | $line["tags_str"] = Article::format_tags_string($tags); |
||||||||
373 | |||||||||
374 | if (feeds::feedHasIcon($feed_id)) { |
||||||||
375 | $line['feed_icon'] = "<img class=\"icon\" src=\"".ICONS_URL."/$feed_id.ico\" alt=\"\">"; |
||||||||
0 ignored issues
–
show
|
|||||||||
376 | } else { |
||||||||
377 | $line['feed_icon'] = "<i class='icon-no-feed material-icons'>rss_feed</i>"; |
||||||||
378 | } |
||||||||
379 | |||||||||
380 | //setting feed headline background color, needs to change text color based on dark/light |
||||||||
381 | $fav_color = $line['favicon_avg_color']; |
||||||||
382 | |||||||||
383 | require_once "colors.php"; |
||||||||
384 | |||||||||
385 | if (!isset($rgba_cache[$feed_id])) { |
||||||||
386 | if ($fav_color && $fav_color != 'fail') { |
||||||||
387 | $rgba_cache[$feed_id] = _color_unpack($fav_color); |
||||||||
388 | } else { |
||||||||
389 | $rgba_cache[$feed_id] = _color_unpack($this->color_of($line['feed_title'])); |
||||||||
390 | } |
||||||||
391 | } |
||||||||
392 | |||||||||
393 | if (isset($rgba_cache[$feed_id])) { |
||||||||
394 | $line['feed_bg_color'] = 'rgba('.implode(",", $rgba_cache[$feed_id]).',0.3)'; |
||||||||
395 | } |
||||||||
396 | |||||||||
397 | /* we don't need those */ |
||||||||
398 | |||||||||
399 | foreach (["date_entered", "guid", "last_published", "last_marked", "tag_cache", "favicon_avg_color", |
||||||||
400 | "uuid", "label_cache", "yyiw"] as $k) { |
||||||||
401 | unset($line[$k]); |
||||||||
402 | } |
||||||||
403 | |||||||||
404 | array_push($reply['content'], $line); |
||||||||
405 | } |
||||||||
406 | } |
||||||||
407 | |||||||||
408 | if (!$headlines_count) { |
||||||||
409 | |||||||||
410 | if (is_object($result)) { |
||||||||
411 | |||||||||
412 | if ($query_error_override) { |
||||||||
413 | $message = $query_error_override; |
||||||||
414 | } else { |
||||||||
415 | switch ($view_mode) { |
||||||||
416 | case "unread": |
||||||||
417 | $message = __("No unread articles found to display."); |
||||||||
418 | break; |
||||||||
419 | case "updated": |
||||||||
420 | $message = __("No updated articles found to display."); |
||||||||
421 | break; |
||||||||
422 | case "marked": |
||||||||
423 | $message = __("No starred articles found to display."); |
||||||||
424 | break; |
||||||||
425 | default: |
||||||||
426 | if ($feed < LABEL_BASE_INDEX) { |
||||||||
427 | $message = __("No articles found to display. You can assign articles to labels manually from article header context menu (applies to all selected articles) or use a filter."); |
||||||||
428 | } else { |
||||||||
429 | $message = __("No articles found to display."); |
||||||||
430 | } |
||||||||
431 | } |
||||||||
432 | } |
||||||||
433 | |||||||||
434 | if (!$offset && $message) { |
||||||||
435 | $reply['content'] = "<div class='whiteBox'>$message"; |
||||||||
436 | |||||||||
437 | $reply['content'] .= "<p><span class=\"text-muted\">"; |
||||||||
438 | |||||||||
439 | $sth = $this->pdo->prepare("SELECT ".SUBSTRING_FOR_DATE."(MAX(last_updated), 1, 19) AS last_updated FROM ttrss_feeds |
||||||||
440 | WHERE owner_uid = ?"); |
||||||||
441 | $sth->execute([$_SESSION['uid']]); |
||||||||
442 | $row = $sth->fetch(); |
||||||||
443 | |||||||||
444 | $last_updated = make_local_datetime($row["last_updated"], false); |
||||||||
445 | |||||||||
446 | $reply['content'] .= sprintf(__("Feeds last updated at %s"), $last_updated); |
||||||||
447 | |||||||||
448 | $sth = $this->pdo->prepare("SELECT COUNT(id) AS num_errors |
||||||||
449 | FROM ttrss_feeds WHERE last_error != '' AND owner_uid = ?"); |
||||||||
450 | $sth->execute([$_SESSION['uid']]); |
||||||||
451 | $row = $sth->fetch(); |
||||||||
452 | |||||||||
453 | $num_errors = $row["num_errors"]; |
||||||||
454 | |||||||||
455 | if ($num_errors > 0) { |
||||||||
456 | $reply['content'] .= "<br/>"; |
||||||||
457 | $reply['content'] .= "<a class=\"text-muted\" href=\"#\" onclick=\"CommonDialogs.showFeedsWithErrors()\">". |
||||||||
458 | __('Some feeds have update errors (click for details)')."</a>"; |
||||||||
459 | } |
||||||||
460 | $reply['content'] .= "</span></p></div>"; |
||||||||
461 | |||||||||
462 | } |
||||||||
463 | } else if (is_numeric($result) && $result == -1) { |
||||||||
464 | $reply['first_id_changed'] = true; |
||||||||
465 | } |
||||||||
466 | } |
||||||||
467 | |||||||||
468 | return array($topmost_article_ids, $headlines_count, $feed, $disable_cache, $reply); |
||||||||
469 | } |
||||||||
470 | |||||||||
471 | public function catchupAll() { |
||||||||
472 | $sth = $this->pdo->prepare("UPDATE ttrss_user_entries SET |
||||||||
473 | last_read = NOW(), unread = false WHERE unread = true AND owner_uid = ?"); |
||||||||
474 | $sth->execute([$_SESSION['uid']]); |
||||||||
475 | |||||||||
476 | CCache::zero_all($_SESSION["uid"]); |
||||||||
477 | } |
||||||||
478 | |||||||||
479 | public function view() { |
||||||||
480 | $reply = array(); |
||||||||
481 | |||||||||
482 | $feed = $_REQUEST["feed"]; |
||||||||
483 | $method = $_REQUEST["m"]; |
||||||||
484 | $view_mode = $_REQUEST["view_mode"]; |
||||||||
485 | $limit = 30; |
||||||||
486 | @$cat_view = $_REQUEST["cat"] == "true"; |
||||||||
487 | @$next_unread_feed = $_REQUEST["nuf"]; |
||||||||
488 | @$offset = $_REQUEST["skip"]; |
||||||||
489 | $order_by = $_REQUEST["order_by"]; |
||||||||
490 | $check_first_id = $_REQUEST["fid"]; |
||||||||
491 | |||||||||
492 | if (is_numeric($feed)) { |
||||||||
493 | $feed = (int) $feed; |
||||||||
494 | } |
||||||||
495 | |||||||||
496 | /* Feed -5 is a special case: it is used to display auxiliary information |
||||||||
497 | * when there's nothing to load - e.g. no stuff in fresh feed */ |
||||||||
498 | |||||||||
499 | if ($feed == -5) { |
||||||||
500 | print json_encode($this->generate_dashboard_feed()); |
||||||||
501 | return; |
||||||||
502 | } |
||||||||
503 | |||||||||
504 | $sth = false; |
||||||||
505 | if ($feed < LABEL_BASE_INDEX) { |
||||||||
506 | |||||||||
507 | $label_feed = Labels::feed_to_label_id($feed); |
||||||||
508 | |||||||||
509 | $sth = $this->pdo->prepare("SELECT id FROM ttrss_labels2 WHERE |
||||||||
510 | id = ? AND owner_uid = ?"); |
||||||||
511 | $sth->execute([$label_feed, $_SESSION['uid']]); |
||||||||
512 | |||||||||
513 | } else if (!$cat_view && is_numeric($feed) && $feed > 0) { |
||||||||
514 | |||||||||
515 | $sth = $this->pdo->prepare("SELECT id FROM ttrss_feeds WHERE |
||||||||
516 | id = ? AND owner_uid = ?"); |
||||||||
517 | $sth->execute([$feed, $_SESSION['uid']]); |
||||||||
518 | |||||||||
519 | } else if ($cat_view && is_numeric($feed) && $feed > 0) { |
||||||||
520 | |||||||||
521 | $sth = $this->pdo->prepare("SELECT id FROM ttrss_feed_categories WHERE |
||||||||
522 | id = ? AND owner_uid = ?"); |
||||||||
523 | |||||||||
524 | $sth->execute([$feed, $_SESSION['uid']]); |
||||||||
525 | } |
||||||||
526 | |||||||||
527 | if ($sth && !$sth->fetch()) { |
||||||||
528 | print json_encode($this->generate_error_feed(__("Feed not found."))); |
||||||||
529 | return; |
||||||||
530 | } |
||||||||
531 | |||||||||
532 | /* Updating a label ccache means recalculating all of the caches |
||||||||
533 | * so for performance reasons we don't do that here */ |
||||||||
534 | |||||||||
535 | if ($feed >= 0) { |
||||||||
536 | CCache::update($feed, $_SESSION["uid"], $cat_view); |
||||||||
537 | } |
||||||||
538 | |||||||||
539 | set_pref("_DEFAULT_VIEW_MODE", $view_mode); |
||||||||
540 | set_pref("_DEFAULT_VIEW_ORDER_BY", $order_by); |
||||||||
541 | |||||||||
542 | /* bump login timestamp if needed */ |
||||||||
543 | if (time() - $_SESSION["last_login_update"] > 3600) { |
||||||||
544 | $sth = $this->pdo->prepare("UPDATE ttrss_users SET last_login = NOW() WHERE id = ?"); |
||||||||
545 | $sth->execute([$_SESSION['uid']]); |
||||||||
546 | |||||||||
547 | $_SESSION["last_login_update"] = time(); |
||||||||
548 | } |
||||||||
549 | |||||||||
550 | if (!$cat_view && is_numeric($feed) && $feed > 0) { |
||||||||
551 | $sth = $this->pdo->prepare("UPDATE ttrss_feeds SET last_viewed = NOW() |
||||||||
552 | WHERE id = ? AND owner_uid = ?"); |
||||||||
553 | $sth->execute([$feed, $_SESSION['uid']]); |
||||||||
554 | } |
||||||||
555 | |||||||||
556 | $reply['headlines'] = []; |
||||||||
557 | |||||||||
558 | $override_order = false; |
||||||||
559 | $skip_first_id_check = false; |
||||||||
560 | |||||||||
561 | switch ($order_by) { |
||||||||
562 | case "title": |
||||||||
563 | $override_order = "ttrss_entries.title, date_entered, updated"; |
||||||||
564 | break; |
||||||||
565 | case "date_reverse": |
||||||||
566 | $override_order = "score DESC, date_entered, updated"; |
||||||||
567 | $skip_first_id_check = true; |
||||||||
568 | break; |
||||||||
569 | case "feed_dates": |
||||||||
570 | $override_order = "updated DESC"; |
||||||||
571 | break; |
||||||||
572 | } |
||||||||
573 | |||||||||
574 | $ret = $this->format_headlines_list($feed, $method, |
||||||||
575 | $view_mode, $limit, $cat_view, $offset, |
||||||||
576 | $override_order, true, $check_first_id, $skip_first_id_check, $order_by); |
||||||||
577 | |||||||||
578 | $headlines_count = $ret[1]; |
||||||||
579 | $disable_cache = $ret[3]; |
||||||||
580 | $reply['headlines'] = $ret[4]; |
||||||||
581 | |||||||||
582 | if (!$next_unread_feed) { |
||||||||
583 | $reply['headlines']['id'] = $feed; |
||||||||
584 | } else { |
||||||||
585 | $reply['headlines']['id'] = $next_unread_feed; |
||||||||
586 | } |
||||||||
587 | |||||||||
588 | $reply['headlines']['is_cat'] = (bool) $cat_view; |
||||||||
589 | |||||||||
590 | $reply['headlines-info'] = ["count" => (int) $headlines_count, |
||||||||
591 | "disable_cache" => (bool) $disable_cache]; |
||||||||
592 | |||||||||
593 | // this is parsed by handleRpcJson() on first viewfeed() to set cdm expanded, etc |
||||||||
594 | $reply['runtime-info'] = make_runtime_info(); |
||||||||
595 | |||||||||
596 | $reply_json = json_encode($reply); |
||||||||
597 | |||||||||
598 | if (!$reply_json) { |
||||||||
599 | $reply_json = json_encode(["error" => ["code" => 15, |
||||||||
600 | "message" => json_last_error_msg()]]); |
||||||||
601 | } |
||||||||
602 | |||||||||
603 | print $reply_json; |
||||||||
604 | |||||||||
605 | } |
||||||||
606 | |||||||||
607 | private function generate_dashboard_feed() { |
||||||||
608 | $reply = array(); |
||||||||
609 | |||||||||
610 | $reply['headlines']['id'] = -5; |
||||||||
611 | $reply['headlines']['is_cat'] = false; |
||||||||
612 | |||||||||
613 | $reply['headlines']['toolbar'] = ''; |
||||||||
614 | |||||||||
615 | $reply['headlines']['content'] = "<div class='whiteBox'>".__('No feed selected.'); |
||||||||
616 | |||||||||
617 | $reply['headlines']['content'] .= "<p><span class=\"text-muted\">"; |
||||||||
618 | |||||||||
619 | $sth = $this->pdo->prepare("SELECT ".SUBSTRING_FOR_DATE."(MAX(last_updated), 1, 19) AS last_updated FROM ttrss_feeds |
||||||||
620 | WHERE owner_uid = ?"); |
||||||||
621 | $sth->execute([$_SESSION['uid']]); |
||||||||
622 | $row = $sth->fetch(); |
||||||||
623 | |||||||||
624 | $last_updated = make_local_datetime($row["last_updated"], false); |
||||||||
625 | |||||||||
626 | $reply['headlines']['content'] .= sprintf(__("Feeds last updated at %s"), $last_updated); |
||||||||
627 | |||||||||
628 | $sth = $this->pdo->prepare("SELECT COUNT(id) AS num_errors |
||||||||
629 | FROM ttrss_feeds WHERE last_error != '' AND owner_uid = ?"); |
||||||||
630 | $sth->execute([$_SESSION['uid']]); |
||||||||
631 | $row = $sth->fetch(); |
||||||||
632 | |||||||||
633 | $num_errors = $row["num_errors"]; |
||||||||
634 | |||||||||
635 | if ($num_errors > 0) { |
||||||||
636 | $reply['headlines']['content'] .= "<br/>"; |
||||||||
637 | $reply['headlines']['content'] .= "<a class=\"text-muted\" href=\"#\" onclick=\"CommonDialogs.showFeedsWithErrors()\">". |
||||||||
638 | __('Some feeds have update errors (click for details)')."</a>"; |
||||||||
639 | } |
||||||||
640 | $reply['headlines']['content'] .= "</span></p>"; |
||||||||
641 | |||||||||
642 | $reply['headlines-info'] = array("count" => 0, |
||||||||
643 | "unread" => 0, |
||||||||
644 | "disable_cache" => true); |
||||||||
645 | |||||||||
646 | return $reply; |
||||||||
647 | } |
||||||||
648 | |||||||||
649 | private function generate_error_feed($error) { |
||||||||
650 | $reply = array(); |
||||||||
651 | |||||||||
652 | $reply['headlines']['id'] = -7; |
||||||||
653 | $reply['headlines']['is_cat'] = false; |
||||||||
654 | |||||||||
655 | $reply['headlines']['toolbar'] = ''; |
||||||||
656 | $reply['headlines']['content'] = "<div class='whiteBox'>".$error."</div>"; |
||||||||
657 | |||||||||
658 | $reply['headlines-info'] = array("count" => 0, |
||||||||
659 | "unread" => 0, |
||||||||
660 | "disable_cache" => true); |
||||||||
661 | |||||||||
662 | return $reply; |
||||||||
663 | } |
||||||||
664 | |||||||||
665 | public function quickAddFeed() { |
||||||||
666 | print "<form onsubmit='return false'>"; |
||||||||
667 | |||||||||
668 | print_hidden("op", "rpc"); |
||||||||
669 | print_hidden("method", "addfeed"); |
||||||||
670 | |||||||||
671 | print "<div id='fadd_error_message' style='display : none' class='alert alert-danger'></div>"; |
||||||||
672 | |||||||||
673 | print "<div id='fadd_multiple_notify' style='display : none'>"; |
||||||||
674 | print_notice("Provided URL is a HTML page referencing multiple feeds, please select required feed from the dropdown menu below."); |
||||||||
0 ignored issues
–
show
The call to
print_notice() has too many arguments starting with 'Provided URL is a HTML ...e dropdown menu below.' .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() The function
print_notice() has been deprecated: Use twig function noticeMessage
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||||||
675 | print "<p></div>"; |
||||||||
676 | |||||||||
677 | print "<section>"; |
||||||||
678 | |||||||||
679 | print "<fieldset>"; |
||||||||
680 | print "<div style='float : right'><img style='display : none' id='feed_add_spinner' src='images/indicator_white.gif'></div>"; |
||||||||
681 | print "<input style='font-size : 16px; width : 500px;' |
||||||||
682 | placeHolder=\"".__("Feed or site URL")."\" |
||||||||
683 | dojoType='dijit.form.ValidationTextBox' required='1' name='feed' id='feedDlg_feedUrl'>"; |
||||||||
684 | |||||||||
685 | print "</fieldset>"; |
||||||||
686 | |||||||||
687 | print "<fieldset>"; |
||||||||
688 | |||||||||
689 | if (get_pref('ENABLE_FEED_CATS')) { |
||||||||
690 | print "<label class='inline'>".__('Place in category:')."</label> "; |
||||||||
691 | print_feed_cat_select("cat", false, 'dojoType="fox.form.Select"'); |
||||||||
692 | } |
||||||||
693 | |||||||||
694 | print "</fieldset>"; |
||||||||
695 | |||||||||
696 | print "</section>"; |
||||||||
697 | |||||||||
698 | print '<div id="feedDlg_feedsContainer" style="display : none"> |
||||||||
699 | <header>' . __('Available feeds').'</header> |
||||||||
700 | <section> |
||||||||
701 | <fieldset> |
||||||||
702 | <select id="feedDlg_feedContainerSelect" |
||||||||
703 | dojoType="fox.form.Select" size="3"> |
||||||||
704 | <script type="dojo/method" event="onChange" args="value"> |
||||||||
705 | dijit.byId("feedDlg_feedUrl").attr("value", value); |
||||||||
706 | </script> |
||||||||
707 | </select> |
||||||||
708 | </fieldset> |
||||||||
709 | </section> |
||||||||
710 | </div>'; |
||||||||
711 | |||||||||
712 | print "<div id='feedDlg_loginContainer' style='display : none'> |
||||||||
713 | <section> |
||||||||
714 | <fieldset> |
||||||||
715 | <input dojoType=\"dijit.form.TextBox\" name='login'\" |
||||||||
716 | placeHolder=\"".__("Login")."\" |
||||||||
717 | autocomplete=\"new-password\" |
||||||||
718 | style=\"width : 10em;\"> |
||||||||
719 | <input |
||||||||
720 | placeHolder=\"".__("Password")."\" |
||||||||
721 | dojoType=\"dijit.form.TextBox\" type='password' |
||||||||
722 | autocomplete=\"new-password\" |
||||||||
723 | style=\"width : 10em;\" name='pass'\"> |
||||||||
724 | </fieldset> |
||||||||
725 | </section> |
||||||||
726 | </div>"; |
||||||||
727 | |||||||||
728 | print "<section>"; |
||||||||
729 | print "<label> |
||||||||
730 | <label class='checkbox'><input type='checkbox' name='need_auth' dojoType='dijit.form.CheckBox' id='feedDlg_loginCheck' |
||||||||
731 | onclick='displayIfChecked(this, \"feedDlg_loginContainer\")'> |
||||||||
732 | ".__('This feed requires authentication.')."</label>"; |
||||||||
733 | print "</section>"; |
||||||||
734 | |||||||||
735 | print "<footer>"; |
||||||||
736 | print "<button dojoType='dijit.form.Button' class='alt-primary' type='submit' |
||||||||
737 | onclick=\"return dijit.byId('feedAddDlg').execute()\">".__('Subscribe')."</button>"; |
||||||||
738 | |||||||||
739 | print "<button dojoType='dijit.form.Button' onclick=\"return dijit.byId('feedAddDlg').hide()\">".__('Cancel')."</button>"; |
||||||||
740 | print "</footer>"; |
||||||||
741 | |||||||||
742 | print "</form>"; |
||||||||
743 | } |
||||||||
744 | |||||||||
745 | public function search() { |
||||||||
746 | $this->params = explode(":", $_REQUEST["param"], 2); |
||||||||
747 | |||||||||
748 | $active_feed_id = sprintf("%d", $this->params[0]); |
||||||||
749 | $is_cat = $this->params[1] != "false"; |
||||||||
750 | |||||||||
751 | print "<form onsubmit='return false;'>"; |
||||||||
752 | |||||||||
753 | print "<section>"; |
||||||||
754 | |||||||||
755 | print "<fieldset>"; |
||||||||
756 | print "<input dojoType='dijit.form.ValidationTextBox' id='search_query' |
||||||||
757 | style='font-size : 16px; width : 540px;' |
||||||||
758 | placeHolder=\"".T_sprintf("Search %s...", $this->getFeedTitle($active_feed_id, $is_cat))."\" |
||||||||
759 | name='query' type='search' value=''>"; |
||||||||
760 | print "</fieldset>"; |
||||||||
761 | |||||||||
762 | if (DB_TYPE == "pgsql") { |
||||||||
0 ignored issues
–
show
|
|||||||||
763 | print "<fieldset>"; |
||||||||
764 | print "<label class='inline'>".__("Language:")."</label>"; |
||||||||
765 | print_select("search_language", get_pref('DEFAULT_SEARCH_LANGUAGE'), Pref_Feeds::get_ts_languages(), |
||||||||
766 | "dojoType='fox.form.Select' title=\"".__('Used for word stemming')."\""); |
||||||||
767 | print "</fieldset>"; |
||||||||
768 | } |
||||||||
769 | |||||||||
770 | print "</section>"; |
||||||||
771 | |||||||||
772 | print "<footer>"; |
||||||||
773 | |||||||||
774 | if (count(PluginHost::getInstance()->get_hooks(PluginHost::HOOK_SEARCH)) == 0) { |
||||||||
775 | print "<button dojoType='dijit.form.Button' style='float : left' class='alt-info' onclick='window.open(\"https://tt-rss.org/wiki/SearchSyntax\")'> |
||||||||
776 | <i class='material-icons'>help</i> ".__("Search syntax")."</button>"; |
||||||||
777 | } |
||||||||
778 | |||||||||
779 | print "<button dojoType='dijit.form.Button' type='submit' class='alt-primary' onclick=\"dijit.byId('searchDlg').execute()\">".__('Search')."</button> |
||||||||
780 | <button dojoType='dijit.form.Button' onclick=\"dijit.byId('searchDlg').hide()\">".__('Cancel')."</button>"; |
||||||||
781 | |||||||||
782 | print "</footer>"; |
||||||||
783 | |||||||||
784 | print "</form>"; |
||||||||
785 | } |
||||||||
786 | |||||||||
787 | public function update_debugger() { |
||||||||
788 | header("Content-type: text/html"); |
||||||||
789 | |||||||||
790 | Debug::set_enabled(true); |
||||||||
791 | Debug::set_loglevel($_REQUEST["xdebug"]); |
||||||||
792 | |||||||||
793 | $feed_id = (int) $_REQUEST["feed_id"]; |
||||||||
794 | @$do_update = $_REQUEST["action"] == "do_update"; |
||||||||
795 | $csrf_token = $_REQUEST["csrf_token"]; |
||||||||
796 | |||||||||
797 | $sth = $this->pdo->prepare("SELECT id FROM ttrss_feeds WHERE id = ? AND owner_uid = ?"); |
||||||||
798 | $sth->execute([$feed_id, $_SESSION['uid']]); |
||||||||
799 | |||||||||
800 | if (!$sth->fetch()) { |
||||||||
801 | print "Access denied."; |
||||||||
802 | return; |
||||||||
803 | } |
||||||||
804 | |||||||||
805 | $refetch_checked = isset($_REQUEST["force_refetch"]) ? "checked" : ""; |
||||||||
806 | $rehash_checked = isset($_REQUEST["force_rehash"]) ? "checked" : ""; |
||||||||
807 | |||||||||
808 | ?> |
||||||||
809 | <!DOCTYPE html> |
||||||||
810 | <html> |
||||||||
811 | <head> |
||||||||
812 | <?php echo stylesheet_tag("css/default.css") ?> |
||||||||
0 ignored issues
–
show
Are you sure the usage of
stylesheet_tag('css/default.css') is correct as it seems to always return null .
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. ![]() The function
stylesheet_tag() has been deprecated: Use Twig filter cssTag
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||||||
813 | <title>Feed Debugger</title> |
||||||||
814 | <?php |
||||||||
815 | echo stylesheet_tag("css/default.css"); |
||||||||
0 ignored issues
–
show
The function
stylesheet_tag() has been deprecated: Use Twig filter cssTag
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() Are you sure the usage of
stylesheet_tag('css/default.css') is correct as it seems to always return null .
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. ![]() |
|||||||||
816 | echo javascript_tag("lib/prototype.js"); |
||||||||
0 ignored issues
–
show
Are you sure the usage of
javascript_tag('lib/prototype.js') is correct as it seems to always return null .
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. ![]() The function
javascript_tag() has been deprecated: Use Twig filter jsTag
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||||||
817 | echo javascript_tag("lib/dojo/dojo.js"); |
||||||||
0 ignored issues
–
show
Are you sure the usage of
javascript_tag('lib/dojo/dojo.js') is correct as it seems to always return null .
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. ![]() The function
javascript_tag() has been deprecated: Use Twig filter jsTag
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||||||
818 | echo javascript_tag("lib/dojo/tt-rss-layer.js"); |
||||||||
0 ignored issues
–
show
The function
javascript_tag() has been deprecated: Use Twig filter jsTag
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() Are you sure the usage of
javascript_tag('lib/dojo/tt-rss-layer.js') is correct as it seems to always return null .
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. ![]() |
|||||||||
819 | ?> |
||||||||
820 | </head> |
||||||||
821 | <body class="flat ttrss_utility feed_debugger"> |
||||||||
822 | <script type="text/javascript"> |
||||||||
823 | require(['dojo/parser', "dojo/ready", 'dijit/form/Button','dijit/form/CheckBox', 'dijit/form/Form', |
||||||||
824 | 'dijit/form/Select','dijit/form/TextBox','dijit/form/ValidationTextBox'],function(parser, ready){ |
||||||||
825 | ready(function() { |
||||||||
826 | parser.parse(); |
||||||||
827 | }); |
||||||||
828 | }); |
||||||||
829 | </script> |
||||||||
830 | |||||||||
831 | <div class="container"> |
||||||||
832 | <h1>Feed Debugger: <?php echo "$feed_id: ".$this->getFeedTitle($feed_id) ?></h1> |
||||||||
833 | <div class="content"> |
||||||||
834 | <form method="GET" action=""> |
||||||||
835 | <input type="hidden" name="op" value="feeds"> |
||||||||
836 | <input type="hidden" name="method" value="update_debugger"> |
||||||||
837 | <input type="hidden" name="xdebug" value="1"> |
||||||||
838 | <input type="hidden" name="csrf_token" value="<?php echo $csrf_token ?>"> |
||||||||
839 | <input type="hidden" name="action" value="do_update"> |
||||||||
840 | <input type="hidden" name="feed_id" value="<?php echo $feed_id ?>"> |
||||||||
841 | |||||||||
842 | <fieldset class="narrow"> |
||||||||
843 | <label class="checkbox"><input dojoType="dijit.form.CheckBox" type="checkbox" name="force_refetch" value="1" <?php echo $refetch_checked ?>> Force refetch</label> |
||||||||
844 | </fieldset> |
||||||||
845 | |||||||||
846 | <fieldset class="narrow"> |
||||||||
847 | <label class="checkbox"><input dojoType="dijit.form.CheckBox" type="checkbox" name="force_rehash" value="1" <?php echo $rehash_checked ?>> Force rehash</label> |
||||||||
848 | </fieldset> |
||||||||
849 | |||||||||
850 | <button type="submit" dojoType="dijit.form.Button" class="alt-primary">Continue</button> |
||||||||
851 | </form> |
||||||||
852 | |||||||||
853 | <hr> |
||||||||
854 | |||||||||
855 | <pre><?php |
||||||||
856 | |||||||||
857 | if ($do_update) { |
||||||||
858 | RSSUtils::update_rss_feed($feed_id, true); |
||||||||
859 | } |
||||||||
860 | |||||||||
861 | ?></pre> |
||||||||
862 | </div> |
||||||||
863 | </div> |
||||||||
864 | </body> |
||||||||
865 | </html> |
||||||||
866 | <?php |
||||||||
867 | |||||||||
868 | } |
||||||||
869 | |||||||||
870 | public static function catchup_feed($feed, $cat_view, $owner_uid = false, $mode = 'all', $search = false) { |
||||||||
871 | |||||||||
872 | if (!$owner_uid) { |
||||||||
873 | $owner_uid = $_SESSION['uid']; |
||||||||
874 | } |
||||||||
875 | |||||||||
876 | $pdo = Db::pdo(); |
||||||||
877 | |||||||||
878 | if (is_array($search) && $search[0]) { |
||||||||
879 | $search_qpart = ""; |
||||||||
880 | |||||||||
881 | foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_SEARCH) as $plugin) { |
||||||||
882 | list($search_qpart, $search_words) = $plugin->hook_search($search[0]); |
||||||||
883 | break; |
||||||||
884 | } |
||||||||
885 | |||||||||
886 | // fall back in case of no plugins |
||||||||
887 | if (!$search_qpart) { |
||||||||
888 | list($search_qpart, $search_words) = Feeds::search_to_sql($search[0], $search[1]); |
||||||||
889 | } |
||||||||
890 | } else { |
||||||||
891 | $search_qpart = "true"; |
||||||||
892 | } |
||||||||
893 | |||||||||
894 | // TODO: all this interval stuff needs some generic generator function |
||||||||
895 | |||||||||
896 | switch ($mode) { |
||||||||
897 | case "1day": |
||||||||
898 | if (DB_TYPE == "pgsql") { |
||||||||
0 ignored issues
–
show
|
|||||||||
899 | $date_qpart = "date_entered < NOW() - INTERVAL '1 day' "; |
||||||||
900 | } else { |
||||||||
901 | $date_qpart = "date_entered < DATE_SUB(NOW(), INTERVAL 1 DAY) "; |
||||||||
902 | } |
||||||||
903 | break; |
||||||||
904 | case "1week": |
||||||||
905 | if (DB_TYPE == "pgsql") { |
||||||||
906 | $date_qpart = "date_entered < NOW() - INTERVAL '1 week' "; |
||||||||
907 | } else { |
||||||||
908 | $date_qpart = "date_entered < DATE_SUB(NOW(), INTERVAL 1 WEEK) "; |
||||||||
909 | } |
||||||||
910 | break; |
||||||||
911 | case "2week": |
||||||||
912 | if (DB_TYPE == "pgsql") { |
||||||||
913 | $date_qpart = "date_entered < NOW() - INTERVAL '2 week' "; |
||||||||
914 | } else { |
||||||||
915 | $date_qpart = "date_entered < DATE_SUB(NOW(), INTERVAL 2 WEEK) "; |
||||||||
916 | } |
||||||||
917 | break; |
||||||||
918 | default: |
||||||||
919 | $date_qpart = "true"; |
||||||||
920 | } |
||||||||
921 | |||||||||
922 | if (is_numeric($feed)) { |
||||||||
923 | if ($cat_view) { |
||||||||
924 | |||||||||
925 | if ($feed >= 0) { |
||||||||
926 | |||||||||
927 | if ($feed > 0) { |
||||||||
928 | $children = Feeds::getChildCategories($feed, $owner_uid); |
||||||||
929 | array_push($children, $feed); |
||||||||
930 | $children = array_map("intval", $children); |
||||||||
931 | |||||||||
932 | $children = join(",", $children); |
||||||||
933 | |||||||||
934 | $cat_qpart = "cat_id IN ($children)"; |
||||||||
935 | } else { |
||||||||
936 | $cat_qpart = "cat_id IS NULL"; |
||||||||
937 | } |
||||||||
938 | |||||||||
939 | $sth = $pdo->prepare("UPDATE ttrss_user_entries |
||||||||
940 | SET unread = false, last_read = NOW() WHERE ref_id IN |
||||||||
941 | (SELECT id FROM |
||||||||
942 | (SELECT DISTINCT id FROM ttrss_entries, ttrss_user_entries WHERE ref_id = id |
||||||||
943 | AND owner_uid = ? AND unread = true AND feed_id IN |
||||||||
944 | (SELECT id FROM ttrss_feeds WHERE $cat_qpart) AND $date_qpart AND $search_qpart) as tmp)"); |
||||||||
945 | $sth->execute([$owner_uid]); |
||||||||
946 | |||||||||
947 | } else if ($feed == -2) { |
||||||||
948 | |||||||||
949 | $sth = $pdo->prepare("UPDATE ttrss_user_entries |
||||||||
950 | SET unread = false,last_read = NOW() WHERE (SELECT COUNT(*) |
||||||||
951 | FROM ttrss_user_labels2, ttrss_entries WHERE article_id = ref_id AND id = ref_id AND $date_qpart AND $search_qpart) > 0 |
||||||||
952 | AND unread = true AND owner_uid = ?"); |
||||||||
953 | $sth->execute([$owner_uid]); |
||||||||
954 | } |
||||||||
955 | |||||||||
956 | } else if ($feed > 0) { |
||||||||
957 | |||||||||
958 | $sth = $pdo->prepare("UPDATE ttrss_user_entries |
||||||||
959 | SET unread = false, last_read = NOW() WHERE ref_id IN |
||||||||
960 | (SELECT id FROM |
||||||||
961 | (SELECT DISTINCT id FROM ttrss_entries, ttrss_user_entries WHERE ref_id = id |
||||||||
962 | AND owner_uid = ? AND unread = true AND feed_id = ? AND $date_qpart AND $search_qpart) as tmp)"); |
||||||||
963 | $sth->execute([$owner_uid, $feed]); |
||||||||
964 | |||||||||
965 | } else if ($feed < 0 && $feed > LABEL_BASE_INDEX) { // special, like starred |
||||||||
966 | |||||||||
967 | if ($feed == -1) { |
||||||||
968 | $sth = $pdo->prepare("UPDATE ttrss_user_entries |
||||||||
969 | SET unread = false, last_read = NOW() WHERE ref_id IN |
||||||||
970 | (SELECT id FROM |
||||||||
971 | (SELECT DISTINCT id FROM ttrss_entries, ttrss_user_entries WHERE ref_id = id |
||||||||
972 | AND owner_uid = ? AND unread = true AND marked = true AND $date_qpart AND $search_qpart) as tmp)"); |
||||||||
973 | $sth->execute([$owner_uid]); |
||||||||
974 | } |
||||||||
975 | |||||||||
976 | if ($feed == -2) { |
||||||||
977 | $sth = $pdo->prepare("UPDATE ttrss_user_entries |
||||||||
978 | SET unread = false, last_read = NOW() WHERE ref_id IN |
||||||||
979 | (SELECT id FROM |
||||||||
980 | (SELECT DISTINCT id FROM ttrss_entries, ttrss_user_entries WHERE ref_id = id |
||||||||
981 | AND owner_uid = ? AND unread = true AND published = true AND $date_qpart AND $search_qpart) as tmp)"); |
||||||||
982 | $sth->execute([$owner_uid]); |
||||||||
983 | } |
||||||||
984 | |||||||||
985 | if ($feed == -3) { |
||||||||
986 | |||||||||
987 | $intl = (int) get_pref("FRESH_ARTICLE_MAX_AGE"); |
||||||||
988 | |||||||||
989 | if (DB_TYPE == "pgsql") { |
||||||||
990 | $match_part = "date_entered > NOW() - INTERVAL '$intl hour' "; |
||||||||
991 | } else { |
||||||||
992 | $match_part = "date_entered > DATE_SUB(NOW(), |
||||||||
993 | INTERVAL $intl HOUR) "; |
||||||||
994 | } |
||||||||
995 | |||||||||
996 | $sth = $pdo->prepare("UPDATE ttrss_user_entries |
||||||||
997 | SET unread = false, last_read = NOW() WHERE ref_id IN |
||||||||
998 | (SELECT id FROM |
||||||||
999 | (SELECT DISTINCT id FROM ttrss_entries, ttrss_user_entries WHERE ref_id = id |
||||||||
1000 | AND owner_uid = ? AND score >= 0 AND unread = true AND $date_qpart AND $match_part AND $search_qpart) as tmp)"); |
||||||||
1001 | $sth->execute([$owner_uid]); |
||||||||
1002 | } |
||||||||
1003 | |||||||||
1004 | if ($feed == -4) { |
||||||||
1005 | $sth = $pdo->prepare("UPDATE ttrss_user_entries |
||||||||
1006 | SET unread = false, last_read = NOW() WHERE ref_id IN |
||||||||
1007 | (SELECT id FROM |
||||||||
1008 | (SELECT DISTINCT id FROM ttrss_entries, ttrss_user_entries WHERE ref_id = id |
||||||||
1009 | AND owner_uid = ? AND unread = true AND $date_qpart AND $search_qpart) as tmp)"); |
||||||||
1010 | $sth->execute([$owner_uid]); |
||||||||
1011 | } |
||||||||
1012 | |||||||||
1013 | } else if ($feed < LABEL_BASE_INDEX) { // label |
||||||||
1014 | |||||||||
1015 | $label_id = Labels::feed_to_label_id($feed); |
||||||||
1016 | |||||||||
1017 | $sth = $pdo->prepare("UPDATE ttrss_user_entries |
||||||||
1018 | SET unread = false, last_read = NOW() WHERE ref_id IN |
||||||||
1019 | (SELECT id FROM |
||||||||
1020 | (SELECT DISTINCT ttrss_entries.id FROM ttrss_entries, ttrss_user_entries, ttrss_user_labels2 WHERE ref_id = id |
||||||||
1021 | AND label_id = ? AND ref_id = article_id |
||||||||
1022 | AND owner_uid = ? AND unread = true AND $date_qpart AND $search_qpart) as tmp)"); |
||||||||
1023 | $sth->execute([$label_id, $owner_uid]); |
||||||||
1024 | |||||||||
1025 | } |
||||||||
1026 | |||||||||
1027 | CCache::update($feed, $owner_uid, $cat_view); |
||||||||
1028 | |||||||||
1029 | } else { // tag |
||||||||
1030 | $sth = $pdo->prepare("UPDATE ttrss_user_entries |
||||||||
1031 | SET unread = false, last_read = NOW() WHERE ref_id IN |
||||||||
1032 | (SELECT id FROM |
||||||||
1033 | (SELECT DISTINCT ttrss_entries.id FROM ttrss_entries, ttrss_user_entries, ttrss_tags WHERE ref_id = ttrss_entries.id |
||||||||
1034 | AND post_int_id = int_id AND tag_name = ? |
||||||||
1035 | AND ttrss_user_entries.owner_uid = ? AND unread = true AND $date_qpart AND $search_qpart) as tmp)"); |
||||||||
1036 | $sth->execute([$feed, $owner_uid]); |
||||||||
1037 | |||||||||
1038 | } |
||||||||
1039 | } |
||||||||
1040 | |||||||||
1041 | public static function getFeedArticles($feed, $is_cat = false, $unread_only = false, |
||||||||
1042 | $owner_uid = false) { |
||||||||
1043 | |||||||||
1044 | $n_feed = (int) $feed; |
||||||||
1045 | $need_entries = false; |
||||||||
1046 | |||||||||
1047 | $pdo = Db::pdo(); |
||||||||
1048 | |||||||||
1049 | if (!$owner_uid) { |
||||||||
1050 | $owner_uid = $_SESSION["uid"]; |
||||||||
1051 | } |
||||||||
1052 | |||||||||
1053 | if ($unread_only) { |
||||||||
1054 | $unread_qpart = "unread = true"; |
||||||||
1055 | } else { |
||||||||
1056 | $unread_qpart = "true"; |
||||||||
1057 | } |
||||||||
1058 | |||||||||
1059 | $match_part = ""; |
||||||||
1060 | |||||||||
1061 | if ($is_cat) { |
||||||||
1062 | return Feeds::getCategoryUnread($n_feed, $owner_uid); |
||||||||
1063 | } else if ($n_feed == -6) { |
||||||||
1064 | return 0; |
||||||||
1065 | } else if ($feed != "0" && $n_feed == 0) { |
||||||||
1066 | |||||||||
1067 | $sth = $pdo->prepare("SELECT SUM((SELECT COUNT(int_id) |
||||||||
1068 | FROM ttrss_user_entries,ttrss_entries WHERE int_id = post_int_id |
||||||||
1069 | AND ref_id = id AND $unread_qpart)) AS count FROM ttrss_tags |
||||||||
1070 | WHERE owner_uid = ? AND tag_name = ?"); |
||||||||
1071 | |||||||||
1072 | $sth->execute([$owner_uid, $feed]); |
||||||||
1073 | $row = $sth->fetch(); |
||||||||
1074 | |||||||||
1075 | return $row["count"]; |
||||||||
1076 | |||||||||
1077 | } else if ($n_feed == -1) { |
||||||||
1078 | $match_part = "marked = true"; |
||||||||
1079 | } else if ($n_feed == -2) { |
||||||||
1080 | $match_part = "published = true"; |
||||||||
1081 | } else if ($n_feed == -3) { |
||||||||
1082 | $match_part = "unread = true AND score >= 0"; |
||||||||
1083 | |||||||||
1084 | $intl = (int) get_pref("FRESH_ARTICLE_MAX_AGE", $owner_uid); |
||||||||
1085 | |||||||||
1086 | if (DB_TYPE == "pgsql") { |
||||||||
0 ignored issues
–
show
|
|||||||||
1087 | $match_part .= " AND date_entered > NOW() - INTERVAL '$intl hour' "; |
||||||||
1088 | } else { |
||||||||
1089 | $match_part .= " AND date_entered > DATE_SUB(NOW(), INTERVAL $intl HOUR) "; |
||||||||
1090 | } |
||||||||
1091 | |||||||||
1092 | $need_entries = true; |
||||||||
1093 | |||||||||
1094 | } else if ($n_feed == -4) { |
||||||||
1095 | $match_part = "true"; |
||||||||
1096 | } else if ($n_feed >= 0) { |
||||||||
1097 | |||||||||
1098 | if ($n_feed != 0) { |
||||||||
1099 | $match_part = "feed_id = ".(int) $n_feed; |
||||||||
1100 | } else { |
||||||||
1101 | $match_part = "feed_id IS NULL"; |
||||||||
1102 | } |
||||||||
1103 | |||||||||
1104 | } else if ($feed < LABEL_BASE_INDEX) { |
||||||||
1105 | |||||||||
1106 | $label_id = Labels::feed_to_label_id($feed); |
||||||||
1107 | |||||||||
1108 | return Feeds::getLabelUnread($label_id, $owner_uid); |
||||||||
1109 | } |
||||||||
1110 | |||||||||
1111 | if ($match_part) { |
||||||||
1112 | |||||||||
1113 | if ($need_entries) { |
||||||||
1114 | $from_qpart = "ttrss_user_entries,ttrss_entries"; |
||||||||
1115 | $from_where = "ttrss_entries.id = ttrss_user_entries.ref_id AND"; |
||||||||
1116 | } else { |
||||||||
1117 | $from_qpart = "ttrss_user_entries"; |
||||||||
1118 | $from_where = ""; |
||||||||
1119 | } |
||||||||
1120 | |||||||||
1121 | $sth = $pdo->prepare("SELECT count(int_id) AS unread |
||||||||
1122 | FROM $from_qpart WHERE |
||||||||
1123 | $unread_qpart AND $from_where ($match_part) AND ttrss_user_entries.owner_uid = ?"); |
||||||||
1124 | $sth->execute([$owner_uid]); |
||||||||
1125 | $row = $sth->fetch(); |
||||||||
1126 | |||||||||
1127 | return $row["unread"]; |
||||||||
1128 | |||||||||
1129 | } else { |
||||||||
1130 | |||||||||
1131 | $sth = $pdo->prepare("SELECT COUNT(post_int_id) AS unread |
||||||||
1132 | FROM ttrss_tags,ttrss_user_entries,ttrss_entries |
||||||||
1133 | WHERE tag_name = ? AND post_int_id = int_id AND ref_id = ttrss_entries.id |
||||||||
1134 | AND $unread_qpart AND ttrss_tags.owner_uid = ,"); |
||||||||
1135 | |||||||||
1136 | $sth->execute([$feed, $owner_uid]); |
||||||||
1137 | $row = $sth->fetch(); |
||||||||
1138 | |||||||||
1139 | return $row["unread"]; |
||||||||
1140 | } |
||||||||
1141 | } |
||||||||
1142 | |||||||||
1143 | /** |
||||||||
1144 | * @return array (code => Status code, message => error message if available) |
||||||||
1145 | * |
||||||||
1146 | * 0 - OK, Feed already exists |
||||||||
1147 | * 1 - OK, Feed added |
||||||||
1148 | * 2 - Invalid URL |
||||||||
1149 | * 3 - URL content is HTML, no feeds available |
||||||||
1150 | * 4 - URL content is HTML which contains multiple feeds. |
||||||||
1151 | * Here you should call extractfeedurls in rpc-backend |
||||||||
1152 | * to get all possible feeds. |
||||||||
1153 | * 5 - Couldn't download the URL content. |
||||||||
1154 | * 6 - Content is an invalid XML. |
||||||||
1155 | */ |
||||||||
1156 | public static function subscribe_to_feed($url, $cat_id = 0, |
||||||||
1157 | $auth_login = '', $auth_pass = '') { |
||||||||
1158 | |||||||||
1159 | global $fetch_last_error; |
||||||||
1160 | global $fetch_last_error_content; |
||||||||
1161 | global $fetch_last_content_type; |
||||||||
1162 | |||||||||
1163 | $pdo = Db::pdo(); |
||||||||
1164 | |||||||||
1165 | $url = Feeds::fix_url($url); |
||||||||
1166 | |||||||||
1167 | if (!$url || !Feeds::validate_feed_url($url)) { |
||||||||
1168 | return array("code" => 2); |
||||||||
1169 | } |
||||||||
1170 | |||||||||
1171 | $contents = @fetch_file_contents($url, false, $auth_login, $auth_pass); |
||||||||
1172 | |||||||||
1173 | foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_SUBSCRIBE_FEED) as $plugin) { |
||||||||
1174 | $contents = $plugin->hook_subscribe_feed($contents, $url, $auth_login, $auth_pass); |
||||||||
1175 | } |
||||||||
1176 | |||||||||
1177 | if (!$contents) { |
||||||||
1178 | if (preg_match("/cloudflare\.com/", $fetch_last_error_content)) { |
||||||||
1179 | $fetch_last_error .= " (feed behind Cloudflare)"; |
||||||||
1180 | } |
||||||||
1181 | |||||||||
1182 | return array("code" => 5, "message" => $fetch_last_error); |
||||||||
1183 | } |
||||||||
1184 | |||||||||
1185 | if (mb_strpos($fetch_last_content_type, "html") !== false && Feeds::is_html($contents)) { |
||||||||
1186 | $feedUrls = Feeds::get_feeds_from_html($url, $contents); |
||||||||
1187 | |||||||||
1188 | if (count($feedUrls) == 0) { |
||||||||
1189 | return array("code" => 3); |
||||||||
1190 | } else if (count($feedUrls) > 1) { |
||||||||
1191 | return array("code" => 4, "feeds" => $feedUrls); |
||||||||
1192 | } |
||||||||
1193 | //use feed url as new URL |
||||||||
1194 | $url = key($feedUrls); |
||||||||
1195 | } |
||||||||
1196 | |||||||||
1197 | if (!$cat_id) { |
||||||||
1198 | $cat_id = null; |
||||||||
1199 | } |
||||||||
1200 | |||||||||
1201 | $sth = $pdo->prepare("SELECT id FROM ttrss_feeds |
||||||||
1202 | WHERE feed_url = ? AND owner_uid = ?"); |
||||||||
1203 | $sth->execute([$url, $_SESSION['uid']]); |
||||||||
1204 | |||||||||
1205 | if ($row = $sth->fetch()) { |
||||||||
1206 | return array("code" => 0, "feed_id" => (int) $row["id"]); |
||||||||
1207 | } else { |
||||||||
1208 | $sth = $pdo->prepare( |
||||||||
1209 | "INSERT INTO ttrss_feeds |
||||||||
1210 | (owner_uid,feed_url,title,cat_id, auth_login,auth_pass,update_method,auth_pass_encrypted) |
||||||||
1211 | VALUES (?, ?, ?, ?, ?, ?, 0, false)"); |
||||||||
1212 | |||||||||
1213 | $sth->execute([$_SESSION['uid'], $url, "[Unknown]", $cat_id, (string) $auth_login, (string) $auth_pass]); |
||||||||
1214 | |||||||||
1215 | $sth = $pdo->prepare("SELECT id FROM ttrss_feeds WHERE feed_url = ? |
||||||||
1216 | AND owner_uid = ?"); |
||||||||
1217 | $sth->execute([$url, $_SESSION['uid']]); |
||||||||
1218 | $row = $sth->fetch(); |
||||||||
1219 | |||||||||
1220 | $feed_id = $row["id"]; |
||||||||
1221 | |||||||||
1222 | if ($feed_id) { |
||||||||
1223 | RSSUtils::set_basic_feed_info($feed_id); |
||||||||
1224 | } |
||||||||
1225 | |||||||||
1226 | return array("code" => 1, "feed_id" => (int) $feed_id); |
||||||||
1227 | |||||||||
1228 | } |
||||||||
1229 | } |
||||||||
1230 | |||||||||
1231 | public static function getIconFile($feed_id) { |
||||||||
1232 | return ICONS_DIR."/$feed_id.ico"; |
||||||||
0 ignored issues
–
show
|
|||||||||
1233 | } |
||||||||
1234 | |||||||||
1235 | public static function feedHasIcon($id) { |
||||||||
1236 | return is_file(ICONS_DIR."/$id.ico") && filesize(ICONS_DIR."/$id.ico") > 0; |
||||||||
0 ignored issues
–
show
|
|||||||||
1237 | } |
||||||||
1238 | |||||||||
1239 | public static function getFeedIcon($id) { |
||||||||
1240 | switch ($id) { |
||||||||
1241 | case 0: |
||||||||
1242 | return "archive"; |
||||||||
1243 | case -1: |
||||||||
1244 | return "star"; |
||||||||
1245 | case -2: |
||||||||
1246 | return "rss_feed"; |
||||||||
1247 | case -3: |
||||||||
1248 | return "whatshot"; |
||||||||
1249 | case -4: |
||||||||
1250 | return "inbox"; |
||||||||
1251 | case -6: |
||||||||
1252 | return "restore"; |
||||||||
1253 | default: |
||||||||
1254 | if ($id < LABEL_BASE_INDEX) { |
||||||||
1255 | return "label"; |
||||||||
1256 | } else { |
||||||||
1257 | $icon = self::getIconFile($id); |
||||||||
1258 | |||||||||
1259 | if ($icon && file_exists($icon)) { |
||||||||
1260 | return ICONS_URL."/".basename($icon)."?".filemtime($icon); |
||||||||
0 ignored issues
–
show
|
|||||||||
1261 | } |
||||||||
1262 | } |
||||||||
1263 | } |
||||||||
1264 | |||||||||
1265 | return false; |
||||||||
1266 | } |
||||||||
1267 | |||||||||
1268 | public static function getFeedTitle($id, $cat = false) { |
||||||||
1269 | $pdo = Db::pdo(); |
||||||||
1270 | |||||||||
1271 | if ($cat) { |
||||||||
1272 | return Feeds::getCategoryTitle($id); |
||||||||
1273 | } else if ($id == -1) { |
||||||||
1274 | return __("Starred articles"); |
||||||||
1275 | } else if ($id == -2) { |
||||||||
1276 | return __("Published articles"); |
||||||||
1277 | } else if ($id == -3) { |
||||||||
1278 | return __("Fresh articles"); |
||||||||
1279 | } else if ($id == -4) { |
||||||||
1280 | return __("All articles"); |
||||||||
1281 | } else if ($id === 0 || $id === "0") { |
||||||||
1282 | return __("Archived articles"); |
||||||||
1283 | } else if ($id == -6) { |
||||||||
1284 | return __("Recently read"); |
||||||||
1285 | } else if ($id < LABEL_BASE_INDEX) { |
||||||||
1286 | |||||||||
1287 | $label_id = Labels::feed_to_label_id($id); |
||||||||
1288 | |||||||||
1289 | $sth = $pdo->prepare("SELECT caption FROM ttrss_labels2 WHERE id = ?"); |
||||||||
1290 | $sth->execute([$label_id]); |
||||||||
1291 | |||||||||
1292 | if ($row = $sth->fetch()) { |
||||||||
1293 | return $row["caption"]; |
||||||||
1294 | } else { |
||||||||
1295 | return "Unknown label ($label_id)"; |
||||||||
1296 | } |
||||||||
1297 | |||||||||
1298 | } else if (is_numeric($id) && $id > 0) { |
||||||||
1299 | |||||||||
1300 | $sth = $pdo->prepare("SELECT title FROM ttrss_feeds WHERE id = ?"); |
||||||||
1301 | $sth->execute([$id]); |
||||||||
1302 | |||||||||
1303 | if ($row = $sth->fetch()) { |
||||||||
1304 | return $row["title"]; |
||||||||
1305 | } else { |
||||||||
1306 | return "Unknown feed ($id)"; |
||||||||
1307 | } |
||||||||
1308 | |||||||||
1309 | } else { |
||||||||
1310 | return $id; |
||||||||
1311 | } |
||||||||
1312 | } |
||||||||
1313 | |||||||||
1314 | public static function getCategoryUnread($cat, $owner_uid = false) { |
||||||||
1315 | |||||||||
1316 | if (!$owner_uid) { |
||||||||
1317 | $owner_uid = $_SESSION["uid"]; |
||||||||
1318 | } |
||||||||
1319 | |||||||||
1320 | $pdo = Db::pdo(); |
||||||||
1321 | |||||||||
1322 | if ($cat >= 0) { |
||||||||
1323 | |||||||||
1324 | if (!$cat) { |
||||||||
1325 | $cat = null; |
||||||||
1326 | } |
||||||||
1327 | |||||||||
1328 | $sth = $pdo->prepare("SELECT id FROM ttrss_feeds |
||||||||
1329 | WHERE (cat_id = :cat OR (:cat IS NULL AND cat_id IS NULL)) |
||||||||
1330 | AND owner_uid = :uid"); |
||||||||
1331 | |||||||||
1332 | $sth->execute([":cat" => $cat, ":uid" => $owner_uid]); |
||||||||
1333 | |||||||||
1334 | $cat_feeds = array(); |
||||||||
1335 | while ($line = $sth->fetch()) { |
||||||||
1336 | array_push($cat_feeds, "feed_id = ".(int) $line["id"]); |
||||||||
1337 | } |
||||||||
1338 | |||||||||
1339 | if (count($cat_feeds) == 0) { |
||||||||
1340 | return 0; |
||||||||
1341 | } |
||||||||
1342 | |||||||||
1343 | $match_part = implode(" OR ", $cat_feeds); |
||||||||
1344 | |||||||||
1345 | $sth = $pdo->prepare("SELECT COUNT(int_id) AS unread |
||||||||
1346 | FROM ttrss_user_entries |
||||||||
1347 | WHERE unread = true AND ($match_part) |
||||||||
1348 | AND owner_uid = ?"); |
||||||||
1349 | $sth->execute([$owner_uid]); |
||||||||
1350 | |||||||||
1351 | $unread = 0; |
||||||||
1352 | |||||||||
1353 | # this needs to be rewritten |
||||||||
1354 | while ($line = $sth->fetch()) { |
||||||||
1355 | $unread += $line["unread"]; |
||||||||
1356 | } |
||||||||
1357 | |||||||||
1358 | return $unread; |
||||||||
1359 | } else if ($cat == -1) { |
||||||||
1360 | return getFeedUnread(-1) + getFeedUnread(-2) + getFeedUnread(-3) + getFeedUnread(0); |
||||||||
1361 | } else if ($cat == -2) { |
||||||||
1362 | |||||||||
1363 | $sth = $pdo->prepare("SELECT COUNT(unread) AS unread FROM |
||||||||
1364 | ttrss_user_entries, ttrss_user_labels2 |
||||||||
1365 | WHERE article_id = ref_id AND unread = true |
||||||||
1366 | AND ttrss_user_entries.owner_uid = ?"); |
||||||||
1367 | $sth->execute([$owner_uid]); |
||||||||
1368 | $row = $sth->fetch(); |
||||||||
1369 | |||||||||
1370 | return $row["unread"]; |
||||||||
1371 | } |
||||||||
1372 | } |
||||||||
1373 | |||||||||
1374 | // only accepts real cats (>= 0) |
||||||||
1375 | public static function getCategoryChildrenUnread($cat, $owner_uid = false) { |
||||||||
1376 | if (!$owner_uid) { |
||||||||
1377 | $owner_uid = $_SESSION["uid"]; |
||||||||
1378 | } |
||||||||
1379 | |||||||||
1380 | $pdo = Db::pdo(); |
||||||||
1381 | |||||||||
1382 | $sth = $pdo->prepare("SELECT id FROM ttrss_feed_categories WHERE parent_cat = ? |
||||||||
1383 | AND owner_uid = ?"); |
||||||||
1384 | $sth->execute([$cat, $owner_uid]); |
||||||||
1385 | |||||||||
1386 | $unread = 0; |
||||||||
1387 | |||||||||
1388 | while ($line = $sth->fetch()) { |
||||||||
1389 | $unread += Feeds::getCategoryUnread($line["id"], $owner_uid); |
||||||||
1390 | $unread += Feeds::getCategoryChildrenUnread($line["id"], $owner_uid); |
||||||||
1391 | } |
||||||||
1392 | |||||||||
1393 | return $unread; |
||||||||
1394 | } |
||||||||
1395 | |||||||||
1396 | public static function getGlobalUnread($user_id = false) { |
||||||||
1397 | |||||||||
1398 | if (!$user_id) { |
||||||||
1399 | $user_id = $_SESSION["uid"]; |
||||||||
1400 | } |
||||||||
1401 | |||||||||
1402 | $pdo = Db::pdo(); |
||||||||
1403 | |||||||||
1404 | $sth = $pdo->prepare("SELECT SUM(value) AS c_id FROM ttrss_counters_cache |
||||||||
1405 | WHERE owner_uid = ? AND feed_id > 0"); |
||||||||
1406 | $sth->execute([$user_id]); |
||||||||
1407 | $row = $sth->fetch(); |
||||||||
1408 | |||||||||
1409 | return $row["c_id"]; |
||||||||
1410 | } |
||||||||
1411 | |||||||||
1412 | public static function getCategoryTitle($cat_id) { |
||||||||
1413 | |||||||||
1414 | if ($cat_id == -1) { |
||||||||
1415 | return __("Special"); |
||||||||
1416 | } else if ($cat_id == -2) { |
||||||||
1417 | return __("Labels"); |
||||||||
1418 | } else { |
||||||||
1419 | |||||||||
1420 | $pdo = Db::pdo(); |
||||||||
1421 | |||||||||
1422 | $sth = $pdo->prepare("SELECT title FROM ttrss_feed_categories WHERE |
||||||||
1423 | id = ?"); |
||||||||
1424 | $sth->execute([$cat_id]); |
||||||||
1425 | |||||||||
1426 | if ($row = $sth->fetch()) { |
||||||||
1427 | return $row["title"]; |
||||||||
1428 | } else { |
||||||||
1429 | return __("Uncategorized"); |
||||||||
1430 | } |
||||||||
1431 | } |
||||||||
1432 | } |
||||||||
1433 | |||||||||
1434 | public static function getLabelUnread($label_id, $owner_uid = false) { |
||||||||
1435 | if (!$owner_uid) { |
||||||||
1436 | $owner_uid = $_SESSION["uid"]; |
||||||||
1437 | } |
||||||||
1438 | |||||||||
1439 | $pdo = Db::pdo(); |
||||||||
1440 | |||||||||
1441 | $sth = $pdo->prepare("SELECT COUNT(ref_id) AS unread FROM ttrss_user_entries, ttrss_user_labels2 |
||||||||
1442 | WHERE owner_uid = ? AND unread = true AND label_id = ? AND article_id = ref_id"); |
||||||||
1443 | |||||||||
1444 | $sth->execute([$owner_uid, $label_id]); |
||||||||
1445 | |||||||||
1446 | if ($row = $sth->fetch()) { |
||||||||
1447 | return $row["unread"]; |
||||||||
1448 | } else { |
||||||||
1449 | return 0; |
||||||||
1450 | } |
||||||||
1451 | } |
||||||||
1452 | |||||||||
1453 | public static function queryFeedHeadlines($params) { |
||||||||
1454 | |||||||||
1455 | $pdo = Db::pdo(); |
||||||||
1456 | |||||||||
1457 | // WARNING: due to highly dynamic nature of this query its going to quote parameters |
||||||||
1458 | // right before adding them to SQL part |
||||||||
1459 | |||||||||
1460 | $feed = $params["feed"]; |
||||||||
1461 | $limit = isset($params["limit"]) ? $params["limit"] : 30; |
||||||||
1462 | $view_mode = $params["view_mode"]; |
||||||||
1463 | $cat_view = isset($params["cat_view"]) ? $params["cat_view"] : false; |
||||||||
1464 | $search = isset($params["search"]) ? $params["search"] : false; |
||||||||
1465 | $search_language = isset($params["search_language"]) ? $params["search_language"] : ""; |
||||||||
1466 | $override_order = isset($params["override_order"]) ? $params["override_order"] : false; |
||||||||
1467 | $offset = isset($params["offset"]) ? $params["offset"] : 0; |
||||||||
1468 | $owner_uid = isset($params["owner_uid"]) ? $params["owner_uid"] : $_SESSION["uid"]; |
||||||||
1469 | $since_id = isset($params["since_id"]) ? $params["since_id"] : 0; |
||||||||
1470 | $include_children = isset($params["include_children"]) ? $params["include_children"] : false; |
||||||||
1471 | $ignore_vfeed_group = isset($params["ignore_vfeed_group"]) ? $params["ignore_vfeed_group"] : false; |
||||||||
1472 | $override_strategy = isset($params["override_strategy"]) ? $params["override_strategy"] : false; |
||||||||
1473 | $override_vfeed = isset($params["override_vfeed"]) ? $params["override_vfeed"] : false; |
||||||||
1474 | $start_ts = isset($params["start_ts"]) ? $params["start_ts"] : false; |
||||||||
1475 | $check_first_id = isset($params["check_first_id"]) ? $params["check_first_id"] : false; |
||||||||
1476 | $skip_first_id_check = isset($params["skip_first_id_check"]) ? $params["skip_first_id_check"] : false; |
||||||||
1477 | //$order_by = isset($params["order_by"]) ? $params["order_by"] : false; |
||||||||
1478 | |||||||||
1479 | $ext_tables_part = ""; |
||||||||
1480 | $limit_query_part = ""; |
||||||||
1481 | $query_error_override = ""; |
||||||||
1482 | |||||||||
1483 | $search_words = []; |
||||||||
1484 | |||||||||
1485 | if ($search) { |
||||||||
1486 | $search_query_part = ""; |
||||||||
1487 | |||||||||
1488 | foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_SEARCH) as $plugin) { |
||||||||
1489 | list($search_query_part, $search_words) = $plugin->hook_search($search); |
||||||||
1490 | break; |
||||||||
1491 | } |
||||||||
1492 | |||||||||
1493 | // fall back in case of no plugins |
||||||||
1494 | if (!$search_query_part) { |
||||||||
1495 | list($search_query_part, $search_words) = Feeds::search_to_sql($search, $search_language); |
||||||||
1496 | } |
||||||||
1497 | |||||||||
1498 | if (DB_TYPE == "pgsql") { |
||||||||
0 ignored issues
–
show
|
|||||||||
1499 | $test_sth = $pdo->prepare("select $search_query_part |
||||||||
1500 | FROM ttrss_entries, ttrss_user_entries WHERE id = ref_id limit 1"); |
||||||||
1501 | |||||||||
1502 | try { |
||||||||
1503 | $test_sth->execute(); |
||||||||
1504 | } catch (PDOException $e) { |
||||||||
1505 | // looks like tsquery syntax is invalid |
||||||||
1506 | $search_query_part = "false"; |
||||||||
1507 | |||||||||
1508 | $query_error_override = T_sprintf("Incorrect search syntax: %s.", implode(" ", $search_words)); |
||||||||
1509 | } |
||||||||
1510 | } |
||||||||
1511 | |||||||||
1512 | $search_query_part .= " AND "; |
||||||||
1513 | } else { |
||||||||
1514 | $search_query_part = ""; |
||||||||
1515 | } |
||||||||
1516 | |||||||||
1517 | if ($since_id) { |
||||||||
1518 | $since_id_part = "ttrss_entries.id > ".$pdo->quote($since_id)." AND "; |
||||||||
1519 | } else { |
||||||||
1520 | $since_id_part = ""; |
||||||||
1521 | } |
||||||||
1522 | |||||||||
1523 | $view_query_part = ""; |
||||||||
1524 | |||||||||
1525 | if ($view_mode == "adaptive") { |
||||||||
1526 | if ($search) { |
||||||||
1527 | $view_query_part = " "; |
||||||||
1528 | } else if ($feed != -1) { |
||||||||
1529 | |||||||||
1530 | $unread = getFeedUnread($feed, $cat_view); |
||||||||
1531 | |||||||||
1532 | if ($cat_view && $feed > 0 && $include_children) { |
||||||||
1533 | $unread += Feeds::getCategoryChildrenUnread($feed); |
||||||||
1534 | } |
||||||||
1535 | |||||||||
1536 | if ($unread > 0) { |
||||||||
1537 | $view_query_part = " unread = true AND "; |
||||||||
1538 | } |
||||||||
1539 | } |
||||||||
1540 | } |
||||||||
1541 | |||||||||
1542 | if ($view_mode == "marked") { |
||||||||
1543 | $view_query_part = " marked = true AND "; |
||||||||
1544 | } |
||||||||
1545 | |||||||||
1546 | if ($view_mode == "has_note") { |
||||||||
1547 | $view_query_part = " (note IS NOT NULL AND note != '') AND "; |
||||||||
1548 | } |
||||||||
1549 | |||||||||
1550 | if ($view_mode == "published") { |
||||||||
1551 | $view_query_part = " published = true AND "; |
||||||||
1552 | } |
||||||||
1553 | |||||||||
1554 | if ($view_mode == "unread" && $feed != -6) { |
||||||||
1555 | $view_query_part = " unread = true AND "; |
||||||||
1556 | } |
||||||||
1557 | |||||||||
1558 | if ($limit > 0) { |
||||||||
1559 | $limit_query_part = "LIMIT ".(int) $limit; |
||||||||
1560 | } |
||||||||
1561 | |||||||||
1562 | $allow_archived = false; |
||||||||
1563 | |||||||||
1564 | $vfeed_query_part = ""; |
||||||||
1565 | |||||||||
1566 | /* tags */ |
||||||||
1567 | if (!is_numeric($feed)) { |
||||||||
1568 | $query_strategy_part = "true"; |
||||||||
1569 | $vfeed_query_part = "(SELECT title FROM ttrss_feeds WHERE |
||||||||
1570 | id = feed_id) as feed_title,"; |
||||||||
1571 | } else if ($feed > 0) { |
||||||||
1572 | |||||||||
1573 | if ($cat_view) { |
||||||||
1574 | |||||||||
1575 | if ($feed > 0) { |
||||||||
1576 | if ($include_children) { |
||||||||
1577 | # sub-cats |
||||||||
1578 | $subcats = Feeds::getChildCategories($feed, $owner_uid); |
||||||||
1579 | array_push($subcats, $feed); |
||||||||
1580 | $subcats = array_map("intval", $subcats); |
||||||||
1581 | |||||||||
1582 | $query_strategy_part = "cat_id IN (". |
||||||||
1583 | implode(",", $subcats).")"; |
||||||||
1584 | |||||||||
1585 | } else { |
||||||||
1586 | $query_strategy_part = "cat_id = ".$pdo->quote($feed); |
||||||||
1587 | } |
||||||||
1588 | |||||||||
1589 | } else { |
||||||||
1590 | $query_strategy_part = "cat_id IS NULL"; |
||||||||
1591 | } |
||||||||
1592 | |||||||||
1593 | $vfeed_query_part = "ttrss_feeds.title AS feed_title,"; |
||||||||
1594 | |||||||||
1595 | } else { |
||||||||
1596 | $query_strategy_part = "feed_id = ".$pdo->quote($feed); |
||||||||
1597 | } |
||||||||
1598 | } else if ($feed == 0 && !$cat_view) { // archive virtual feed |
||||||||
1599 | $query_strategy_part = "feed_id IS NULL"; |
||||||||
1600 | $allow_archived = true; |
||||||||
1601 | } else if ($feed == 0 && $cat_view) { // uncategorized |
||||||||
1602 | $query_strategy_part = "cat_id IS NULL AND feed_id IS NOT NULL"; |
||||||||
1603 | $vfeed_query_part = "ttrss_feeds.title AS feed_title,"; |
||||||||
1604 | } else if ($feed == -1) { // starred virtual feed |
||||||||
1605 | $query_strategy_part = "marked = true"; |
||||||||
1606 | $vfeed_query_part = "ttrss_feeds.title AS feed_title,"; |
||||||||
1607 | $allow_archived = true; |
||||||||
1608 | |||||||||
1609 | if (!$override_order) { |
||||||||
1610 | $override_order = "last_marked DESC, date_entered DESC, updated DESC"; |
||||||||
1611 | } |
||||||||
1612 | |||||||||
1613 | } else if ($feed == -2) { // published virtual feed OR labels category |
||||||||
1614 | |||||||||
1615 | if (!$cat_view) { |
||||||||
1616 | $query_strategy_part = "published = true"; |
||||||||
1617 | $vfeed_query_part = "ttrss_feeds.title AS feed_title,"; |
||||||||
1618 | $allow_archived = true; |
||||||||
1619 | |||||||||
1620 | if (!$override_order) { |
||||||||
1621 | $override_order = "last_published DESC, date_entered DESC, updated DESC"; |
||||||||
1622 | } |
||||||||
1623 | |||||||||
1624 | } else { |
||||||||
1625 | $vfeed_query_part = "ttrss_feeds.title AS feed_title,"; |
||||||||
1626 | |||||||||
1627 | $ext_tables_part = "ttrss_labels2,ttrss_user_labels2,"; |
||||||||
1628 | |||||||||
1629 | $query_strategy_part = "ttrss_labels2.id = ttrss_user_labels2.label_id AND |
||||||||
1630 | ttrss_user_labels2.article_id = ref_id"; |
||||||||
1631 | |||||||||
1632 | } |
||||||||
1633 | } else if ($feed == -6) { // recently read |
||||||||
1634 | $query_strategy_part = "unread = false AND last_read IS NOT NULL"; |
||||||||
1635 | |||||||||
1636 | if (DB_TYPE == "pgsql") { |
||||||||
1637 | $query_strategy_part .= " AND last_read > NOW() - INTERVAL '1 DAY' "; |
||||||||
1638 | } else { |
||||||||
1639 | $query_strategy_part .= " AND last_read > DATE_SUB(NOW(), INTERVAL 1 DAY) "; |
||||||||
1640 | } |
||||||||
1641 | |||||||||
1642 | $vfeed_query_part = "ttrss_feeds.title AS feed_title,"; |
||||||||
1643 | $allow_archived = true; |
||||||||
1644 | $ignore_vfeed_group = true; |
||||||||
1645 | |||||||||
1646 | if (!$override_order) { |
||||||||
1647 | $override_order = "last_read DESC"; |
||||||||
1648 | } |
||||||||
1649 | |||||||||
1650 | } else if ($feed == -3) { // fresh virtual feed |
||||||||
1651 | $query_strategy_part = "unread = true AND score >= 0"; |
||||||||
1652 | |||||||||
1653 | $intl = (int) get_pref("FRESH_ARTICLE_MAX_AGE", $owner_uid); |
||||||||
1654 | |||||||||
1655 | if (DB_TYPE == "pgsql") { |
||||||||
1656 | $query_strategy_part .= " AND date_entered > NOW() - INTERVAL '$intl hour' "; |
||||||||
1657 | } else { |
||||||||
1658 | $query_strategy_part .= " AND date_entered > DATE_SUB(NOW(), INTERVAL $intl HOUR) "; |
||||||||
1659 | } |
||||||||
1660 | |||||||||
1661 | $vfeed_query_part = "ttrss_feeds.title AS feed_title,"; |
||||||||
1662 | } else if ($feed == -4) { // all articles virtual feed |
||||||||
1663 | $allow_archived = true; |
||||||||
1664 | $query_strategy_part = "true"; |
||||||||
1665 | $vfeed_query_part = "ttrss_feeds.title AS feed_title,"; |
||||||||
1666 | } else if ($feed <= LABEL_BASE_INDEX) { // labels |
||||||||
1667 | $label_id = Labels::feed_to_label_id($feed); |
||||||||
1668 | |||||||||
1669 | $query_strategy_part = "label_id = ".$pdo->quote($label_id)." AND |
||||||||
1670 | ttrss_labels2.id = ttrss_user_labels2.label_id AND |
||||||||
1671 | ttrss_user_labels2.article_id = ref_id"; |
||||||||
1672 | |||||||||
1673 | $vfeed_query_part = "ttrss_feeds.title AS feed_title,"; |
||||||||
1674 | $ext_tables_part = "ttrss_labels2,ttrss_user_labels2,"; |
||||||||
1675 | $allow_archived = true; |
||||||||
1676 | |||||||||
1677 | } else { |
||||||||
1678 | $query_strategy_part = "true"; |
||||||||
1679 | } |
||||||||
1680 | |||||||||
1681 | $order_by = "score DESC, date_entered DESC, updated DESC"; |
||||||||
1682 | |||||||||
1683 | if ($override_order) { |
||||||||
1684 | $order_by = $override_order; |
||||||||
1685 | } |
||||||||
1686 | |||||||||
1687 | if ($override_strategy) { |
||||||||
1688 | $query_strategy_part = $override_strategy; |
||||||||
1689 | } |
||||||||
1690 | |||||||||
1691 | if ($override_vfeed) { |
||||||||
1692 | $vfeed_query_part = $override_vfeed; |
||||||||
1693 | } |
||||||||
1694 | |||||||||
1695 | if ($search) { |
||||||||
1696 | $feed_title = T_sprintf("Search results: %s", $search); |
||||||||
1697 | } else { |
||||||||
1698 | if ($cat_view) { |
||||||||
1699 | $feed_title = Feeds::getCategoryTitle($feed); |
||||||||
1700 | } else { |
||||||||
1701 | if (is_numeric($feed) && $feed > 0) { |
||||||||
1702 | $ssth = $pdo->prepare("SELECT title,site_url,last_error,last_updated |
||||||||
1703 | FROM ttrss_feeds WHERE id = ? AND owner_uid = ?"); |
||||||||
1704 | $ssth->execute([$feed, $owner_uid]); |
||||||||
1705 | $row = $ssth->fetch(); |
||||||||
1706 | |||||||||
1707 | $feed_title = $row["title"]; |
||||||||
1708 | $feed_site_url = $row["site_url"]; |
||||||||
1709 | $last_error = $row["last_error"]; |
||||||||
1710 | $last_updated = $row["last_updated"]; |
||||||||
1711 | } else { |
||||||||
1712 | $feed_title = Feeds::getFeedTitle($feed); |
||||||||
1713 | } |
||||||||
1714 | } |
||||||||
1715 | } |
||||||||
1716 | |||||||||
1717 | $content_query_part = "content, "; |
||||||||
1718 | |||||||||
1719 | if ($limit_query_part) { |
||||||||
1720 | $offset_query_part = "OFFSET ".(int) $offset; |
||||||||
1721 | } else { |
||||||||
1722 | $offset_query_part = ""; |
||||||||
1723 | } |
||||||||
1724 | |||||||||
1725 | if ($start_ts) { |
||||||||
1726 | $start_ts_formatted = date("Y/m/d H:i:s", strtotime($start_ts)); |
||||||||
1727 | $start_ts_query_part = "date_entered >= '$start_ts_formatted' AND"; |
||||||||
1728 | } else { |
||||||||
1729 | $start_ts_query_part = ""; |
||||||||
1730 | } |
||||||||
1731 | |||||||||
1732 | if (is_numeric($feed)) { |
||||||||
1733 | // proper override_order applied above |
||||||||
1734 | if ($vfeed_query_part && !$ignore_vfeed_group && get_pref('VFEED_GROUP_BY_FEED', $owner_uid)) { |
||||||||
1735 | |||||||||
1736 | if (!(in_array($feed, Feeds::NEVER_GROUP_BY_DATE) && !$cat_view)) { |
||||||||
1737 | $yyiw_desc = $order_by == "date_reverse" ? "" : "desc"; |
||||||||
1738 | $yyiw_order_qpart = "yyiw $yyiw_desc, "; |
||||||||
1739 | } else { |
||||||||
1740 | $yyiw_order_qpart = ""; |
||||||||
1741 | } |
||||||||
1742 | |||||||||
1743 | if (!$override_order) { |
||||||||
1744 | $order_by = "$yyiw_order_qpart ttrss_feeds.title, $order_by"; |
||||||||
1745 | } else { |
||||||||
1746 | $order_by = "$yyiw_order_qpart ttrss_feeds.title, $override_order"; |
||||||||
1747 | } |
||||||||
1748 | } |
||||||||
1749 | |||||||||
1750 | if (!$allow_archived) { |
||||||||
1751 | $from_qpart = "${ext_tables_part}ttrss_entries LEFT JOIN ttrss_user_entries ON (ref_id = ttrss_entries.id),ttrss_feeds"; |
||||||||
1752 | $feed_check_qpart = "ttrss_user_entries.feed_id = ttrss_feeds.id AND"; |
||||||||
1753 | |||||||||
1754 | } else { |
||||||||
1755 | $from_qpart = "${ext_tables_part}ttrss_entries LEFT JOIN ttrss_user_entries ON (ref_id = ttrss_entries.id) |
||||||||
1756 | LEFT JOIN ttrss_feeds ON (feed_id = ttrss_feeds.id)"; |
||||||||
1757 | } |
||||||||
1758 | |||||||||
1759 | if ($vfeed_query_part) { |
||||||||
1760 | $vfeed_query_part .= "favicon_avg_color,"; |
||||||||
1761 | } |
||||||||
1762 | |||||||||
1763 | $first_id = 0; |
||||||||
1764 | $first_id_query_strategy_part = $query_strategy_part; |
||||||||
1765 | |||||||||
1766 | if ($feed == -3) { |
||||||||
1767 | $first_id_query_strategy_part = "true"; |
||||||||
1768 | } |
||||||||
1769 | |||||||||
1770 | if (DB_TYPE == "pgsql") { |
||||||||
1771 | $sanity_interval_qpart = "date_entered >= NOW() - INTERVAL '1 hour' AND"; |
||||||||
1772 | $yyiw_qpart = "to_char(date_entered, 'IYYY-IW') AS yyiw"; |
||||||||
1773 | } else { |
||||||||
1774 | $sanity_interval_qpart = "date_entered >= DATE_SUB(NOW(), INTERVAL 1 hour) AND"; |
||||||||
1775 | $yyiw_qpart = "date_format(date_entered, '%Y-%u') AS yyiw"; |
||||||||
1776 | } |
||||||||
1777 | |||||||||
1778 | if (!$search && !$skip_first_id_check) { |
||||||||
1779 | // if previous topmost article id changed that means our current pagination is no longer valid |
||||||||
1780 | $query = "SELECT DISTINCT |
||||||||
1781 | ttrss_feeds.title, |
||||||||
1782 | date_entered, |
||||||||
1783 | $yyiw_qpart, |
||||||||
1784 | guid, |
||||||||
1785 | ttrss_entries.id, |
||||||||
1786 | ttrss_entries.title, |
||||||||
1787 | updated, |
||||||||
1788 | score, |
||||||||
1789 | marked, |
||||||||
1790 | published, |
||||||||
1791 | last_marked, |
||||||||
1792 | last_published, |
||||||||
1793 | last_read |
||||||||
1794 | FROM |
||||||||
1795 | $from_qpart |
||||||||
1796 | WHERE |
||||||||
1797 | $feed_check_qpart |
||||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||||||
1798 | ttrss_user_entries.owner_uid = ".$pdo->quote($owner_uid)." AND |
||||||||
1799 | $search_query_part |
||||||||
1800 | $start_ts_query_part |
||||||||
1801 | $since_id_part |
||||||||
1802 | $sanity_interval_qpart |
||||||||
1803 | $first_id_query_strategy_part ORDER BY $order_by LIMIT 1"; |
||||||||
1804 | |||||||||
1805 | /*if ($_REQUEST["debug"]) { |
||||||||
1806 | print $query; |
||||||||
1807 | }*/ |
||||||||
1808 | |||||||||
1809 | $res = $pdo->query($query); |
||||||||
1810 | |||||||||
1811 | if ($row = $res->fetch()) { |
||||||||
1812 | $first_id = (int) $row["id"]; |
||||||||
1813 | |||||||||
1814 | if ($offset > 0 && $first_id && $check_first_id && $first_id != $check_first_id) { |
||||||||
1815 | return array(-1, $feed_title, $feed_site_url, $last_error, $last_updated, $search_words, $first_id, $vfeed_query_part != "", $query_error_override); |
||||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Comprehensibility
Best Practice
introduced
by
Comprehensibility
Best Practice
introduced
by
|
|||||||||
1816 | } |
||||||||
1817 | } |
||||||||
1818 | } |
||||||||
1819 | |||||||||
1820 | $query = "SELECT DISTINCT |
||||||||
1821 | date_entered, |
||||||||
1822 | $yyiw_qpart, |
||||||||
1823 | guid, |
||||||||
1824 | ttrss_entries.id,ttrss_entries.title, |
||||||||
1825 | updated, |
||||||||
1826 | label_cache, |
||||||||
1827 | tag_cache, |
||||||||
1828 | always_display_enclosures, |
||||||||
1829 | site_url, |
||||||||
1830 | note, |
||||||||
1831 | num_comments, |
||||||||
1832 | comments, |
||||||||
1833 | int_id, |
||||||||
1834 | uuid, |
||||||||
1835 | lang, |
||||||||
1836 | hide_images, |
||||||||
1837 | unread,feed_id,marked,published,link,last_read,orig_feed_id, |
||||||||
1838 | last_marked, last_published, |
||||||||
1839 | $vfeed_query_part |
||||||||
1840 | $content_query_part |
||||||||
1841 | author,score |
||||||||
1842 | FROM |
||||||||
1843 | $from_qpart |
||||||||
1844 | WHERE |
||||||||
1845 | $feed_check_qpart |
||||||||
1846 | ttrss_user_entries.owner_uid = ".$pdo->quote($owner_uid)." AND |
||||||||
1847 | $search_query_part |
||||||||
1848 | $start_ts_query_part |
||||||||
1849 | $view_query_part |
||||||||
1850 | $since_id_part |
||||||||
1851 | $query_strategy_part ORDER BY $order_by |
||||||||
1852 | $limit_query_part $offset_query_part"; |
||||||||
1853 | |||||||||
1854 | //if ($_REQUEST["debug"]) print $query; |
||||||||
1855 | |||||||||
1856 | $res = $pdo->query($query); |
||||||||
1857 | |||||||||
1858 | } else { |
||||||||
1859 | // browsing by tag |
||||||||
1860 | |||||||||
1861 | $query = "SELECT DISTINCT |
||||||||
1862 | date_entered, |
||||||||
1863 | guid, |
||||||||
1864 | note, |
||||||||
1865 | ttrss_entries.id as id, |
||||||||
1866 | title, |
||||||||
1867 | updated, |
||||||||
1868 | unread, |
||||||||
1869 | feed_id, |
||||||||
1870 | orig_feed_id, |
||||||||
1871 | marked, |
||||||||
1872 | published, |
||||||||
1873 | num_comments, |
||||||||
1874 | comments, |
||||||||
1875 | int_id, |
||||||||
1876 | tag_cache, |
||||||||
1877 | label_cache, |
||||||||
1878 | link, |
||||||||
1879 | lang, |
||||||||
1880 | uuid, |
||||||||
1881 | last_read, |
||||||||
1882 | (SELECT hide_images FROM ttrss_feeds WHERE id = feed_id) AS hide_images, |
||||||||
1883 | last_marked, last_published, |
||||||||
1884 | $since_id_part |
||||||||
1885 | $vfeed_query_part |
||||||||
1886 | $content_query_part |
||||||||
1887 | author, score |
||||||||
1888 | FROM ttrss_entries, ttrss_user_entries, ttrss_tags |
||||||||
1889 | WHERE |
||||||||
1890 | ref_id = ttrss_entries.id AND |
||||||||
1891 | ttrss_user_entries.owner_uid = ".$pdo->quote($owner_uid)." AND |
||||||||
1892 | post_int_id = int_id AND |
||||||||
1893 | tag_name = ".$pdo->quote($feed)." AND |
||||||||
1894 | $view_query_part |
||||||||
1895 | $search_query_part |
||||||||
1896 | $start_ts_query_part |
||||||||
1897 | $query_strategy_part ORDER BY $order_by |
||||||||
1898 | $limit_query_part $offset_query_part"; |
||||||||
1899 | |||||||||
1900 | if ($_REQUEST["debug"]) { |
||||||||
1901 | print $query; |
||||||||
1902 | } |
||||||||
1903 | |||||||||
1904 | $res = $pdo->query($query); |
||||||||
1905 | } |
||||||||
1906 | |||||||||
1907 | return array($res, $feed_title, $feed_site_url, $last_error, $last_updated, $search_words, $first_id, $vfeed_query_part != "", $query_error_override); |
||||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||||||
1908 | |||||||||
1909 | } |
||||||||
1910 | |||||||||
1911 | public static function getParentCategories($cat, $owner_uid) { |
||||||||
1912 | $rv = array(); |
||||||||
1913 | |||||||||
1914 | $pdo = Db::pdo(); |
||||||||
1915 | |||||||||
1916 | $sth = $pdo->prepare("SELECT parent_cat FROM ttrss_feed_categories |
||||||||
1917 | WHERE id = ? AND parent_cat IS NOT NULL AND owner_uid = ?"); |
||||||||
1918 | $sth->execute([$cat, $owner_uid]); |
||||||||
1919 | |||||||||
1920 | while ($line = $sth->fetch()) { |
||||||||
1921 | array_push($rv, $line["parent_cat"]); |
||||||||
1922 | $rv = array_merge($rv, Feeds::getParentCategories($line["parent_cat"], $owner_uid)); |
||||||||
1923 | } |
||||||||
1924 | |||||||||
1925 | return $rv; |
||||||||
1926 | } |
||||||||
1927 | |||||||||
1928 | public static function getChildCategories($cat, $owner_uid) { |
||||||||
1929 | $rv = array(); |
||||||||
1930 | |||||||||
1931 | $pdo = Db::pdo(); |
||||||||
1932 | |||||||||
1933 | $sth = $pdo->prepare("SELECT id FROM ttrss_feed_categories |
||||||||
1934 | WHERE parent_cat = ? AND owner_uid = ?"); |
||||||||
1935 | $sth->execute([$cat, $owner_uid]); |
||||||||
1936 | |||||||||
1937 | while ($line = $sth->fetch()) { |
||||||||
1938 | array_push($rv, $line["id"]); |
||||||||
1939 | $rv = array_merge($rv, Feeds::getChildCategories($line["id"], $owner_uid)); |
||||||||
1940 | } |
||||||||
1941 | |||||||||
1942 | return $rv; |
||||||||
1943 | } |
||||||||
1944 | |||||||||
1945 | public static function getFeedCategory($feed) { |
||||||||
1946 | $pdo = Db::pdo(); |
||||||||
1947 | |||||||||
1948 | $sth = $pdo->prepare("SELECT cat_id FROM ttrss_feeds |
||||||||
1949 | WHERE id = ?"); |
||||||||
1950 | $sth->execute([$feed]); |
||||||||
1951 | |||||||||
1952 | if ($row = $sth->fetch()) { |
||||||||
1953 | return $row["cat_id"]; |
||||||||
1954 | } else { |
||||||||
1955 | return false; |
||||||||
1956 | } |
||||||||
1957 | |||||||||
1958 | } |
||||||||
1959 | |||||||||
1960 | function color_of($name) { |
||||||||
1961 | $colormap = ["#1cd7d7", "#d91111", "#1212d7", "#8e16e5", "#7b7b7b", |
||||||||
1962 | "#39f110", "#0bbea6", "#ec0e0e", "#1534f2", "#b9e416", |
||||||||
1963 | "#479af2", "#f36b14", "#10c7e9", "#1e8fe7", "#e22727"]; |
||||||||
1964 | |||||||||
1965 | $sum = 0; |
||||||||
1966 | |||||||||
1967 | for ($i = 0; $i < strlen($name); $i++) { |
||||||||
1968 | $sum += ord($name[$i]); |
||||||||
1969 | } |
||||||||
1970 | |||||||||
1971 | $sum %= count($colormap); |
||||||||
1972 | |||||||||
1973 | return $colormap[$sum]; |
||||||||
1974 | } |
||||||||
1975 | |||||||||
1976 | public static function get_feeds_from_html($url, $content) { |
||||||||
1977 | $url = Feeds::fix_url($url); |
||||||||
1978 | $baseUrl = substr($url, 0, strrpos($url, '/') + 1); |
||||||||
1979 | |||||||||
1980 | $feedUrls = []; |
||||||||
1981 | |||||||||
1982 | $doc = new DOMDocument(); |
||||||||
1983 | if ($doc->loadHTML($content)) { |
||||||||
1984 | $xpath = new DOMXPath($doc); |
||||||||
1985 | $entries = $xpath->query('/html/head/link[@rel="alternate" and '. |
||||||||
1986 | '(contains(@type,"rss") or contains(@type,"atom"))]|/html/head/link[@rel="feed"]'); |
||||||||
1987 | |||||||||
1988 | foreach ($entries as $entry) { |
||||||||
1989 | if ($entry->hasAttribute('href')) { |
||||||||
1990 | $title = $entry->getAttribute('title'); |
||||||||
1991 | if ($title == '') { |
||||||||
1992 | $title = $entry->getAttribute('type'); |
||||||||
1993 | } |
||||||||
1994 | $feedUrl = rewrite_relative_url( |
||||||||
1995 | $baseUrl, $entry->getAttribute('href') |
||||||||
1996 | ); |
||||||||
1997 | $feedUrls[$feedUrl] = $title; |
||||||||
1998 | } |
||||||||
1999 | } |
||||||||
2000 | } |
||||||||
2001 | return $feedUrls; |
||||||||
2002 | } |
||||||||
2003 | |||||||||
2004 | public static function is_html($content) { |
||||||||
2005 | return preg_match("/<html|DOCTYPE html/i", substr($content, 0, 8192)) !== 0; |
||||||||
2006 | } |
||||||||
2007 | |||||||||
2008 | public static function validate_feed_url($url) { |
||||||||
2009 | $parts = parse_url($url); |
||||||||
2010 | |||||||||
2011 | return ($parts['scheme'] == 'http' || $parts['scheme'] == 'feed' || $parts['scheme'] == 'https'); |
||||||||
2012 | } |
||||||||
2013 | |||||||||
2014 | /** |
||||||||
2015 | * Fixes incomplete URLs by prepending "http://". |
||||||||
2016 | * Also replaces feed:// with http://, and |
||||||||
2017 | * prepends a trailing slash if the url is a domain name only. |
||||||||
2018 | * |
||||||||
2019 | * @param string $url Possibly incomplete URL |
||||||||
2020 | * |
||||||||
2021 | * @return string Fixed URL. |
||||||||
2022 | */ |
||||||||
2023 | public static function fix_url($url) { |
||||||||
2024 | |||||||||
2025 | // support schema-less urls |
||||||||
2026 | if (strpos($url, '//') === 0) { |
||||||||
2027 | $url = 'https:'.$url; |
||||||||
2028 | } |
||||||||
2029 | |||||||||
2030 | if (strpos($url, '://') === false) { |
||||||||
2031 | $url = 'http://'.$url; |
||||||||
2032 | } else if (substr($url, 0, 5) == 'feed:') { |
||||||||
2033 | $url = 'http:'.substr($url, 5); |
||||||||
2034 | } |
||||||||
2035 | |||||||||
2036 | //prepend slash if the URL has no slash in it |
||||||||
2037 | // "http://www.example" -> "http://www.example/" |
||||||||
2038 | if (strpos($url, '/', strpos($url, ':') + 3) === false) { |
||||||||
2039 | $url .= '/'; |
||||||||
2040 | } |
||||||||
2041 | |||||||||
2042 | //convert IDNA hostname to punycode if possible |
||||||||
2043 | if (function_exists("idn_to_ascii")) { |
||||||||
2044 | $parts = parse_url($url); |
||||||||
2045 | if (mb_detect_encoding($parts['host']) != 'ASCII') |
||||||||
2046 | { |
||||||||
2047 | $parts['host'] = idn_to_ascii($parts['host']); |
||||||||
2048 | $url = build_url($parts); |
||||||||
2049 | } |
||||||||
2050 | } |
||||||||
2051 | |||||||||
2052 | if ($url != "http:///") { |
||||||||
2053 | return $url; |
||||||||
2054 | } else { |
||||||||
2055 | return ''; |
||||||||
2056 | } |
||||||||
2057 | } |
||||||||
2058 | |||||||||
2059 | public static function add_feed_category($feed_cat, $parent_cat_id = false, $order_id = 0) { |
||||||||
2060 | |||||||||
2061 | if (!$feed_cat) { |
||||||||
2062 | return false; |
||||||||
2063 | } |
||||||||
2064 | |||||||||
2065 | $feed_cat = mb_substr($feed_cat, 0, 250); |
||||||||
2066 | if (!$parent_cat_id) { |
||||||||
2067 | $parent_cat_id = null; |
||||||||
2068 | } |
||||||||
2069 | |||||||||
2070 | $pdo = Db::pdo(); |
||||||||
2071 | $tr_in_progress = false; |
||||||||
2072 | |||||||||
2073 | try { |
||||||||
2074 | $pdo->beginTransaction(); |
||||||||
2075 | } catch (Exception $e) { |
||||||||
2076 | $tr_in_progress = true; |
||||||||
2077 | } |
||||||||
2078 | |||||||||
2079 | $sth = $pdo->prepare("SELECT id FROM ttrss_feed_categories |
||||||||
2080 | WHERE (parent_cat = :parent OR (:parent IS NULL AND parent_cat IS NULL)) |
||||||||
2081 | AND title = :title AND owner_uid = :uid"); |
||||||||
2082 | $sth->execute([':parent' => $parent_cat_id, ':title' => $feed_cat, ':uid' => $_SESSION['uid']]); |
||||||||
2083 | |||||||||
2084 | if (!$sth->fetch()) { |
||||||||
2085 | |||||||||
2086 | $sth = $pdo->prepare("INSERT INTO ttrss_feed_categories (owner_uid,title,parent_cat,order_id) |
||||||||
2087 | VALUES (?, ?, ?, ?)"); |
||||||||
2088 | $sth->execute([$_SESSION['uid'], $feed_cat, $parent_cat_id, (int) $order_id]); |
||||||||
2089 | |||||||||
2090 | if (!$tr_in_progress) { |
||||||||
2091 | $pdo->commit(); |
||||||||
2092 | } |
||||||||
2093 | |||||||||
2094 | return true; |
||||||||
2095 | } |
||||||||
2096 | |||||||||
2097 | $pdo->commit(); |
||||||||
2098 | |||||||||
2099 | return false; |
||||||||
2100 | } |
||||||||
2101 | |||||||||
2102 | public static function get_feed_access_key($feed_id, $is_cat, $owner_uid = false) { |
||||||||
2103 | |||||||||
2104 | if (!$owner_uid) { |
||||||||
2105 | $owner_uid = $_SESSION["uid"]; |
||||||||
2106 | } |
||||||||
2107 | |||||||||
2108 | $is_cat = bool_to_sql_bool($is_cat); |
||||||||
2109 | |||||||||
2110 | $pdo = Db::pdo(); |
||||||||
2111 | |||||||||
2112 | $sth = $pdo->prepare("SELECT access_key FROM ttrss_access_keys |
||||||||
2113 | WHERE feed_id = ? AND is_cat = ? |
||||||||
2114 | AND owner_uid = ?"); |
||||||||
2115 | $sth->execute([$feed_id, $is_cat, $owner_uid]); |
||||||||
2116 | |||||||||
2117 | if ($row = $sth->fetch()) { |
||||||||
2118 | return $row["access_key"]; |
||||||||
2119 | } else { |
||||||||
2120 | $key = uniqid_short(); |
||||||||
2121 | |||||||||
2122 | $sth = $pdo->prepare("INSERT INTO ttrss_access_keys |
||||||||
2123 | (access_key, feed_id, is_cat, owner_uid) |
||||||||
2124 | VALUES (?, ?, ?, ?)"); |
||||||||
2125 | |||||||||
2126 | $sth->execute([$key, $feed_id, $is_cat, $owner_uid]); |
||||||||
2127 | |||||||||
2128 | return $key; |
||||||||
2129 | } |
||||||||
2130 | } |
||||||||
2131 | |||||||||
2132 | /** |
||||||||
2133 | * Purge a feed old posts. |
||||||||
2134 | * |
||||||||
2135 | * @param mixed $link A database connection. |
||||||||
2136 | * @param mixed $feed_id The id of the purged feed. |
||||||||
2137 | * @param mixed $purge_interval Olderness of purged posts. |
||||||||
2138 | * @param boolean $debug Set to True to enable the debug. False by default. |
||||||||
2139 | * @access public |
||||||||
2140 | * @return void |
||||||||
2141 | */ |
||||||||
2142 | public static function purge_feed($feed_id, $purge_interval) { |
||||||||
2143 | |||||||||
2144 | if (!$purge_interval) { |
||||||||
2145 | $purge_interval = Feeds::feed_purge_interval($feed_id); |
||||||||
2146 | } |
||||||||
2147 | |||||||||
2148 | $pdo = Db::pdo(); |
||||||||
2149 | |||||||||
2150 | $sth = $pdo->prepare("SELECT owner_uid FROM ttrss_feeds WHERE id = ?"); |
||||||||
2151 | $sth->execute([$feed_id]); |
||||||||
2152 | |||||||||
2153 | $owner_uid = false; |
||||||||
2154 | |||||||||
2155 | if ($row = $sth->fetch()) { |
||||||||
2156 | $owner_uid = $row["owner_uid"]; |
||||||||
2157 | } |
||||||||
2158 | |||||||||
2159 | if ($purge_interval == -1 || !$purge_interval) { |
||||||||
2160 | if ($owner_uid) { |
||||||||
2161 | CCache::update($feed_id, $owner_uid); |
||||||||
2162 | } |
||||||||
2163 | return; |
||||||||
2164 | } |
||||||||
2165 | |||||||||
2166 | if (!$owner_uid) { |
||||||||
2167 | return; |
||||||||
2168 | } |
||||||||
2169 | |||||||||
2170 | if (FORCE_ARTICLE_PURGE == 0) { |
||||||||
0 ignored issues
–
show
|
|||||||||
2171 | $purge_unread = get_pref("PURGE_UNREAD_ARTICLES", |
||||||||
2172 | $owner_uid, false); |
||||||||
2173 | } else { |
||||||||
2174 | $purge_unread = true; |
||||||||
2175 | $purge_interval = FORCE_ARTICLE_PURGE; |
||||||||
2176 | } |
||||||||
2177 | |||||||||
2178 | if (!$purge_unread) { |
||||||||
2179 | $query_limit = " unread = false AND "; |
||||||||
2180 | } else { |
||||||||
2181 | $query_limit = ""; |
||||||||
2182 | } |
||||||||
2183 | |||||||||
2184 | $purge_interval = (int) $purge_interval; |
||||||||
2185 | |||||||||
2186 | if (DB_TYPE == "pgsql") { |
||||||||
0 ignored issues
–
show
|
|||||||||
2187 | $sth = $pdo->prepare("DELETE FROM ttrss_user_entries |
||||||||
2188 | USING ttrss_entries |
||||||||
2189 | WHERE ttrss_entries.id = ref_id AND |
||||||||
2190 | marked = false AND |
||||||||
2191 | feed_id = ? AND |
||||||||
2192 | $query_limit |
||||||||
2193 | ttrss_entries.date_updated < NOW() - INTERVAL '$purge_interval days'"); |
||||||||
2194 | $sth->execute([$feed_id]); |
||||||||
2195 | |||||||||
2196 | } else { |
||||||||
2197 | $sth = $pdo->prepare("DELETE FROM ttrss_user_entries |
||||||||
2198 | USING ttrss_user_entries, ttrss_entries |
||||||||
2199 | WHERE ttrss_entries.id = ref_id AND |
||||||||
2200 | marked = false AND |
||||||||
2201 | feed_id = ? AND |
||||||||
2202 | $query_limit |
||||||||
2203 | ttrss_entries.date_updated < DATE_SUB(NOW(), INTERVAL $purge_interval DAY)"); |
||||||||
2204 | $sth->execute([$feed_id]); |
||||||||
2205 | |||||||||
2206 | } |
||||||||
2207 | |||||||||
2208 | $rows = $sth->rowCount(); |
||||||||
2209 | |||||||||
2210 | CCache::update($feed_id, $owner_uid); |
||||||||
2211 | |||||||||
2212 | Debug::log("Purged feed $feed_id ($purge_interval): deleted $rows articles"); |
||||||||
2213 | |||||||||
2214 | return $rows; |
||||||||
2215 | } |
||||||||
2216 | |||||||||
2217 | public static function feed_purge_interval($feed_id) { |
||||||||
2218 | |||||||||
2219 | $pdo = DB::pdo(); |
||||||||
2220 | |||||||||
2221 | $sth = $pdo->prepare("SELECT purge_interval, owner_uid FROM ttrss_feeds |
||||||||
2222 | WHERE id = ?"); |
||||||||
2223 | $sth->execute([$feed_id]); |
||||||||
2224 | |||||||||
2225 | if ($row = $sth->fetch()) { |
||||||||
2226 | $purge_interval = $row["purge_interval"]; |
||||||||
2227 | $owner_uid = $row["owner_uid"]; |
||||||||
2228 | |||||||||
2229 | if ($purge_interval == 0) { |
||||||||
2230 | $purge_interval = get_pref( |
||||||||
2231 | 'PURGE_OLD_DAYS', $owner_uid); |
||||||||
2232 | } |
||||||||
2233 | |||||||||
2234 | return $purge_interval; |
||||||||
2235 | |||||||||
2236 | } else { |
||||||||
2237 | return -1; |
||||||||
2238 | } |
||||||||
2239 | } |
||||||||
2240 | |||||||||
2241 | public static function search_to_sql($search, $search_language) { |
||||||||
2242 | |||||||||
2243 | $keywords = str_getcsv(trim($search), " "); |
||||||||
2244 | $query_keywords = array(); |
||||||||
2245 | $search_words = array(); |
||||||||
2246 | $search_query_leftover = array(); |
||||||||
2247 | |||||||||
2248 | $pdo = Db::pdo(); |
||||||||
2249 | |||||||||
2250 | if ($search_language) { |
||||||||
2251 | $search_language = $pdo->quote(mb_strtolower($search_language)); |
||||||||
2252 | } else { |
||||||||
2253 | $search_language = $pdo->quote("english"); |
||||||||
2254 | } |
||||||||
2255 | |||||||||
2256 | foreach ($keywords as $k) { |
||||||||
2257 | if (strpos($k, "-") === 0) { |
||||||||
2258 | $k = substr($k, 1); |
||||||||
2259 | $not = "NOT"; |
||||||||
2260 | } else { |
||||||||
2261 | $not = ""; |
||||||||
2262 | } |
||||||||
2263 | |||||||||
2264 | $commandpair = explode(":", mb_strtolower($k), 2); |
||||||||
2265 | |||||||||
2266 | switch ($commandpair[0]) { |
||||||||
2267 | case "title": |
||||||||
2268 | if ($commandpair[1]) { |
||||||||
2269 | array_push($query_keywords, "($not (LOWER(ttrss_entries.title) LIKE ". |
||||||||
2270 | $pdo->quote('%'.mb_strtolower($commandpair[1]).'%')."))"); |
||||||||
2271 | } else { |
||||||||
2272 | array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%') |
||||||||
2273 | OR UPPER(ttrss_entries.content) $not LIKE UPPER(".$pdo->quote("%$k%")."))"); |
||||||||
2274 | array_push($search_words, $k); |
||||||||
2275 | } |
||||||||
2276 | break; |
||||||||
2277 | case "author": |
||||||||
2278 | if ($commandpair[1]) { |
||||||||
2279 | array_push($query_keywords, "($not (LOWER(author) LIKE ". |
||||||||
2280 | $pdo->quote('%'.mb_strtolower($commandpair[1]).'%')."))"); |
||||||||
2281 | } else { |
||||||||
2282 | array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%') |
||||||||
2283 | OR UPPER(ttrss_entries.content) $not LIKE UPPER(".$pdo->quote("%$k%")."))"); |
||||||||
2284 | array_push($search_words, $k); |
||||||||
2285 | } |
||||||||
2286 | break; |
||||||||
2287 | case "note": |
||||||||
2288 | if ($commandpair[1]) { |
||||||||
2289 | if ($commandpair[1] == "true") { |
||||||||
2290 | array_push($query_keywords, "($not (note IS NOT NULL AND note != ''))"); |
||||||||
2291 | } else if ($commandpair[1] == "false") { |
||||||||
2292 | array_push($query_keywords, "($not (note IS NULL OR note = ''))"); |
||||||||
2293 | } else { |
||||||||
2294 | array_push($query_keywords, "($not (LOWER(note) LIKE ". |
||||||||
2295 | $pdo->quote('%'.mb_strtolower($commandpair[1]).'%')."))"); |
||||||||
2296 | } |
||||||||
2297 | } else { |
||||||||
2298 | array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER(".$pdo->quote("%$k%").") |
||||||||
2299 | OR UPPER(ttrss_entries.content) $not LIKE UPPER(".$pdo->quote("%$k%")."))"); |
||||||||
2300 | if (!$not) { |
||||||||
2301 | array_push($search_words, $k); |
||||||||
2302 | } |
||||||||
2303 | } |
||||||||
2304 | break; |
||||||||
2305 | case "star": |
||||||||
2306 | |||||||||
2307 | if ($commandpair[1]) { |
||||||||
2308 | if ($commandpair[1] == "true") { |
||||||||
2309 | array_push($query_keywords, "($not (marked = true))"); |
||||||||
2310 | } else { |
||||||||
2311 | array_push($query_keywords, "($not (marked = false))"); |
||||||||
2312 | } |
||||||||
2313 | } else { |
||||||||
2314 | array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER(".$pdo->quote("%$k%").") |
||||||||
2315 | OR UPPER(ttrss_entries.content) $not LIKE UPPER(".$pdo->quote("%$k%")."))"); |
||||||||
2316 | if (!$not) { |
||||||||
2317 | array_push($search_words, $k); |
||||||||
2318 | } |
||||||||
2319 | } |
||||||||
2320 | break; |
||||||||
2321 | case "pub": |
||||||||
2322 | if ($commandpair[1]) { |
||||||||
2323 | if ($commandpair[1] == "true") { |
||||||||
2324 | array_push($query_keywords, "($not (published = true))"); |
||||||||
2325 | } else { |
||||||||
2326 | array_push($query_keywords, "($not (published = false))"); |
||||||||
2327 | } |
||||||||
2328 | |||||||||
2329 | } else { |
||||||||
2330 | array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER('%$k%') |
||||||||
2331 | OR UPPER(ttrss_entries.content) $not LIKE UPPER(".$pdo->quote("%$k%")."))"); |
||||||||
2332 | if (!$not) { |
||||||||
2333 | array_push($search_words, $k); |
||||||||
2334 | } |
||||||||
2335 | } |
||||||||
2336 | break; |
||||||||
2337 | case "unread": |
||||||||
2338 | if ($commandpair[1]) { |
||||||||
2339 | if ($commandpair[1] == "true") { |
||||||||
2340 | array_push($query_keywords, "($not (unread = true))"); |
||||||||
2341 | } else { |
||||||||
2342 | array_push($query_keywords, "($not (unread = false))"); |
||||||||
2343 | } |
||||||||
2344 | |||||||||
2345 | } else { |
||||||||
2346 | array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER(".$pdo->quote("%$k%").") |
||||||||
2347 | OR UPPER(ttrss_entries.content) $not LIKE UPPER(".$pdo->quote("%$k%")."))"); |
||||||||
2348 | if (!$not) { |
||||||||
2349 | array_push($search_words, $k); |
||||||||
2350 | } |
||||||||
2351 | } |
||||||||
2352 | break; |
||||||||
2353 | default: |
||||||||
2354 | if (strpos($k, "@") === 0) { |
||||||||
2355 | |||||||||
2356 | $user_tz_string = get_pref('USER_TIMEZONE', $_SESSION['uid']); |
||||||||
2357 | $orig_ts = strtotime(substr($k, 1)); |
||||||||
2358 | $k = date("Y-m-d", convert_timestamp($orig_ts, $user_tz_string, 'UTC')); |
||||||||
2359 | |||||||||
2360 | //$k = date("Y-m-d", strtotime(substr($k, 1))); |
||||||||
2361 | |||||||||
2362 | array_push($query_keywords, "(".SUBSTRING_FOR_DATE."(updated,1,LENGTH('$k')) $not = '$k')"); |
||||||||
2363 | } else { |
||||||||
2364 | |||||||||
2365 | if (DB_TYPE == "pgsql") { |
||||||||
0 ignored issues
–
show
|
|||||||||
2366 | $k = mb_strtolower($k); |
||||||||
2367 | array_push($search_query_leftover, $not ? "!$k" : $k); |
||||||||
2368 | } else { |
||||||||
2369 | array_push($query_keywords, "(UPPER(ttrss_entries.title) $not LIKE UPPER(".$pdo->quote("%$k%").") |
||||||||
2370 | OR UPPER(ttrss_entries.content) $not LIKE UPPER(".$pdo->quote("%$k%")."))"); |
||||||||
2371 | } |
||||||||
2372 | |||||||||
2373 | if (!$not) { |
||||||||
2374 | array_push($search_words, $k); |
||||||||
2375 | } |
||||||||
2376 | } |
||||||||
2377 | } |
||||||||
2378 | } |
||||||||
2379 | |||||||||
2380 | if (count($search_query_leftover) > 0) { |
||||||||
2381 | |||||||||
2382 | if (DB_TYPE == "pgsql") { |
||||||||
2383 | |||||||||
2384 | // if there's no joiners consider this a "simple" search and |
||||||||
2385 | // concatenate everything with &, otherwise don't try to mess with tsquery syntax |
||||||||
2386 | if (preg_match("/[&|]/", implode(" ", $search_query_leftover))) { |
||||||||
2387 | $tsquery = $pdo->quote(implode(" ", $search_query_leftover)); |
||||||||
2388 | } else { |
||||||||
2389 | $tsquery = $pdo->quote(implode(" & ", $search_query_leftover)); |
||||||||
2390 | } |
||||||||
2391 | |||||||||
2392 | array_push($query_keywords, |
||||||||
2393 | "(tsvector_combined @@ to_tsquery($search_language, $tsquery))"); |
||||||||
2394 | } |
||||||||
2395 | |||||||||
2396 | } |
||||||||
2397 | |||||||||
2398 | $search_query_part = implode("AND", $query_keywords); |
||||||||
2399 | |||||||||
2400 | return array($search_query_part, $search_words); |
||||||||
2401 | } |
||||||||
2402 | } |
||||||||
2403 | |||||||||
2404 |