diff options
Diffstat (limited to 'classes/pref/feeds.php')
-rwxr-xr-x | classes/pref/feeds.php | 1182 |
1 files changed, 370 insertions, 812 deletions
diff --git a/classes/pref/feeds.php b/classes/pref/feeds.php index 47e5689ec..086c52697 100755 --- a/classes/pref/feeds.php +++ b/classes/pref/feeds.php @@ -1,7 +1,7 @@ <?php class Pref_Feeds extends Handler_Protected { function csrf_ignore($method) { - $csrf_ignored = array("index", "getfeedtree", "savefeedorder", "uploadicon"); + $csrf_ignored = array("index", "getfeedtree", "savefeedorder"); return array_search($method, $csrf_ignored) !== false; } @@ -9,7 +9,7 @@ class Pref_Feeds extends Handler_Protected { public static function get_ts_languages() { $rv = []; - if (DB_TYPE == "pgsql") { + if (Config::get(Config::DB_TYPE) == "pgsql") { $dbh = Db::pdo(); $res = $dbh->query("SELECT cfgname FROM pg_ts_config"); @@ -22,11 +22,6 @@ class Pref_Feeds extends Handler_Protected { return $rv; } - function batch_edit_cbox($elem, $label = false) { - print "<input type=\"checkbox\" title=\"".__("Check to enable field")."\" - onchange=\"App.dialogOf(this).toggleField(this, '$elem', '$label')\">"; - } - function renamecat() { $title = clean($_REQUEST['title']); $id = clean($_REQUEST['id']); @@ -98,7 +93,7 @@ class Pref_Feeds extends Handler_Protected { $feed['checkbox'] = false; $feed['unread'] = -1; $feed['error'] = $feed_line['last_error']; - $feed['icon'] = Feeds::getFeedIcon($feed_line['id']); + $feed['icon'] = Feeds::_get_icon($feed_line['id']); $feed['param'] = TimeHelper::make_local_datetime( $feed_line['last_updated'], true); $feed['updates_disabled'] = (int)($feed_line['update_interval'] < 0); @@ -110,10 +105,10 @@ class Pref_Feeds extends Handler_Protected { } function getfeedtree() { - print json_encode($this->makefeedtree()); + print json_encode($this->_makefeedtree()); } - function makefeedtree() { + function _makefeedtree() { if (clean($_REQUEST['mode'] ?? 0) != 2) $search = $_SESSION["prefs_feed_search"] ?? ""; @@ -266,7 +261,7 @@ class Pref_Feeds extends Handler_Protected { $feed['name'] = $feed_line['title']; $feed['checkbox'] = false; $feed['error'] = $feed_line['last_error']; - $feed['icon'] = Feeds::getFeedIcon($feed_line['id']); + $feed['icon'] = Feeds::_get_icon($feed_line['id']); $feed['param'] = TimeHelper::make_local_datetime( $feed_line['last_updated'], true); $feed['unread'] = -1; @@ -301,7 +296,7 @@ class Pref_Feeds extends Handler_Protected { $feed['name'] = $feed_line['title']; $feed['checkbox'] = false; $feed['error'] = $feed_line['last_error']; - $feed['icon'] = Feeds::getFeedIcon($feed_line['id']); + $feed['icon'] = Feeds::_get_icon($feed_line['id']); $feed['param'] = TimeHelper::make_local_datetime( $feed_line['last_updated'], true); $feed['unread'] = -1; @@ -446,7 +441,7 @@ class Pref_Feeds extends Handler_Protected { $sth->execute([$feed_id, $_SESSION['uid']]); if ($row = $sth->fetch()) { - @unlink(ICONS_DIR . "/$feed_id.ico"); + @unlink(Config::get(Config::ICONS_DIR) . "/$feed_id.ico"); $sth = $this->pdo->prepare("UPDATE ttrss_feeds SET favicon_avg_color = NULL, favicon_last_checked = '1970-01-01' where id = ?"); @@ -458,10 +453,12 @@ class Pref_Feeds extends Handler_Protected { header("Content-type: text/html"); if (is_uploaded_file($_FILES['icon_file']['tmp_name'])) { - $tmp_file = tempnam(CACHE_DIR . '/upload', 'icon'); + $tmp_file = tempnam(Config::get(Config::CACHE_DIR) . '/upload', 'icon'); - $result = move_uploaded_file($_FILES['icon_file']['tmp_name'], - $tmp_file); + if (!$tmp_file) + return; + + $result = move_uploaded_file($_FILES['icon_file']['tmp_name'], $tmp_file); if (!$result) { return; @@ -474,7 +471,7 @@ class Pref_Feeds extends Handler_Protected { $feed_id = clean($_REQUEST["feed_id"]); $rc = 2; // failed - if (is_file($icon_file) && $feed_id) { + if ($icon_file && is_file($icon_file) && $feed_id) { if (filesize($icon_file) < 65535) { $sth = $this->pdo->prepare("SELECT id FROM ttrss_feeds @@ -482,15 +479,19 @@ class Pref_Feeds extends Handler_Protected { $sth->execute([$feed_id, $_SESSION['uid']]); if ($row = $sth->fetch()) { - @unlink(ICONS_DIR . "/$feed_id.ico"); - if (rename($icon_file, ICONS_DIR . "/$feed_id.ico")) { + $new_filename = Config::get(Config::ICONS_DIR) . "/$feed_id.ico"; + + if (file_exists($new_filename)) unlink($new_filename); + + if (rename($icon_file, $new_filename)) { + chmod($new_filename, 644); $sth = $this->pdo->prepare("UPDATE ttrss_feeds SET favicon_avg_color = '' WHERE id = ?"); $sth->execute([$feed_id]); - $rc = 0; + $rc = Feeds::_get_icon($feed_id); } } } else { @@ -498,7 +499,9 @@ class Pref_Feeds extends Handler_Protected { } } - if (is_file($icon_file)) @unlink($icon_file); + if ($icon_file && is_file($icon_file)) { + unlink($icon_file); + } print $rc; return; @@ -508,131 +511,25 @@ class Pref_Feeds extends Handler_Protected { global $purge_intervals; global $update_intervals; - $feed_id = clean($_REQUEST["id"]); + $feed_id = (int)clean($_REQUEST["id"]); $sth = $this->pdo->prepare("SELECT * FROM ttrss_feeds WHERE id = ? AND owner_uid = ?"); $sth->execute([$feed_id, $_SESSION['uid']]); - if ($row = $sth->fetch()) { - print '<div dojoType="dijit.layout.TabContainer" style="height : 450px"> - <div dojoType="dijit.layout.ContentPane" title="'.__('General').'">'; - - $title = htmlspecialchars($row["title"]); - - print_hidden("id", "$feed_id"); - print_hidden("op", "pref-feeds"); - print_hidden("method", "editSave"); - - print "<header>".__("Feed")."</header>"; - print "<section>"; - - /* Title */ - - print "<fieldset>"; - - print "<input dojoType='dijit.form.ValidationTextBox' required='1' - placeHolder=\"".__("Feed Title")."\" - style='font-size : 16px; width: 500px' name='title' value=\"$title\">"; - - print "</fieldset>"; - - /* Feed URL */ - - $feed_url = htmlspecialchars($row["feed_url"]); - - print "<fieldset>"; - - print "<label>" . __('URL:') . "</label> "; - print "<input dojoType='dijit.form.ValidationTextBox' required='1' - placeHolder=\"".__("Feed URL")."\" - regExp='^(http|https)://.*' style='width : 300px' - name='feed_url' value=\"$feed_url\">"; - - if (!empty($row["last_error"])) { - print " <i class=\"material-icons\" - title=\"".htmlspecialchars($row["last_error"])."\">error</i>"; - } - - print "</fieldset>"; - - /* Category */ - - if (get_pref('ENABLE_FEED_CATS')) { - - $cat_id = $row["cat_id"]; - - print "<fieldset>"; - - print "<label>" . __('Place in category:') . "</label> "; - - print_feed_cat_select("cat_id", $cat_id, - 'dojoType="fox.form.Select"'); - - print "</fieldset>"; - } - - /* Site URL */ - - $site_url = htmlspecialchars($row["site_url"]); - - print "<fieldset>"; - - print "<label>" . __('Site URL:') . "</label> "; - print "<input dojoType='dijit.form.ValidationTextBox' required='1' - placeHolder=\"".__("Site URL")."\" - regExp='^(http|https)://.*' style='width : 300px' - name='site_url' value=\"$site_url\">"; + if ($row = $sth->fetch(PDO::FETCH_ASSOC)) { - print "</fieldset>"; - - /* FTS Stemming Language */ - - if (DB_TYPE == "pgsql") { - $feed_language = $row["feed_language"]; - - if (!$feed_language) - $feed_language = get_pref('DEFAULT_SEARCH_LANGUAGE'); - - print "<fieldset>"; - - print "<label>" . __('Language:') . "</label> "; - print_select("feed_language", $feed_language, $this::get_ts_languages(), - 'dojoType="fox.form.Select"'); - - print "</fieldset>"; - } - - print "</section>"; - - print "<header>".__("Update")."</header>"; - print "<section>"; - - /* Update Interval */ - - $update_interval = $row["update_interval"]; - - print "<fieldset>"; + ob_start(); + PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_EDIT_FEED, $feed_id); + $plugin_data = trim((string)ob_get_contents()); + ob_end_clean(); - print "<label>".__("Interval:")."</label> "; + $row["icon"] = Feeds::_get_icon($feed_id); $local_update_intervals = $update_intervals; $local_update_intervals[0] .= sprintf(" (%s)", $update_intervals[get_pref("DEFAULT_UPDATE_INTERVAL")]); - print_select_hash("update_interval", $update_interval, $local_update_intervals, - 'dojoType="fox.form.Select"'); - - print "</fieldset>"; - - /* Purge intl */ - - $purge_interval = $row["purge_interval"]; - - print "<fieldset>"; - - print "<label>" . __('Article purging:') . "</label> "; - - if (FORCE_ARTICLE_PURGE == 0) { + if (Config::get(Config::FORCE_ARTICLE_PURGE) == 0) { $local_purge_intervals = $purge_intervals; $default_purge_interval = get_pref("PURGE_OLD_DAYS"); @@ -642,343 +539,142 @@ class Pref_Feeds extends Handler_Protected { $local_purge_intervals[0] .= " " . sprintf("(%s)", __("Disabled")); } else { - $purge_interval = FORCE_ARTICLE_PURGE; + $purge_interval = Config::get(Config::FORCE_ARTICLE_PURGE); $local_purge_intervals = [ T_nsprintf('%d day', '%d days', $purge_interval, $purge_interval) ]; } - print_select_hash("purge_interval", $purge_interval, $local_purge_intervals, - 'dojoType="fox.form.Select" ' . - ((FORCE_ARTICLE_PURGE == 0) ? "" : 'disabled="1"')); - - print "</fieldset>"; - - print "</section>"; - - $auth_login = htmlspecialchars($row["auth_login"]); - $auth_pass = htmlspecialchars($row["auth_pass"]); - - $auth_enabled = $auth_login !== '' || $auth_pass !== ''; - - $auth_style = $auth_enabled ? '' : 'display: none'; - print "<div id='feedEditDlg_loginContainer' style='$auth_style'>"; - print "<header>".__("Authentication")."</header>"; - print "<section>"; - - print "<fieldset>"; - - print "<input dojoType='dijit.form.TextBox' id='feedEditDlg_login' - placeHolder='".__("Login")."' - autocomplete='new-password' - name='auth_login' value=\"$auth_login\">"; - - print "</fieldset><fieldset>"; - - print "<input dojoType='dijit.form.TextBox' type='password' name='auth_pass' - autocomplete='new-password' - placeHolder='".__("Password")."' - value=\"$auth_pass\">"; - - print "<div dojoType='dijit.Tooltip' connectId='feedEditDlg_login' position='below'> - ".__('<b>Hint:</b> you need to fill in your login information if your feed requires authentication, except for Twitter feeds.')." - </div>"; - - print "</fieldset>"; - - print "</section></div>"; - - $auth_checked = $auth_enabled ? 'checked' : ''; - print "<label class='checkbox'> - <input type='checkbox' $auth_checked name='need_auth' dojoType='dijit.form.CheckBox' id='feedEditDlg_loginCheck' - onclick='App.displayIfChecked(this, \"feedEditDlg_loginContainer\")'> - ".__('This feed requires authentication.')."</label>"; - - print '</div><div dojoType="dijit.layout.ContentPane" title="'.__('Options').'">'; - - print "<section class='narrow'>"; - - $include_in_digest = $row["include_in_digest"]; - - if ($include_in_digest) { - $checked = "checked=\"1\""; - } else { - $checked = ""; - } - - print "<fieldset class='narrow'>"; - - print "<label class='checkbox'><input dojoType=\"dijit.form.CheckBox\" type=\"checkbox\" id=\"include_in_digest\" - name=\"include_in_digest\" - $checked> ".__('Include in e-mail digest')."</label>"; - - print "</fieldset>"; - - $always_display_enclosures = $row["always_display_enclosures"]; - - if ($always_display_enclosures) { - $checked = "checked"; - } else { - $checked = ""; - } - - print "<fieldset class='narrow'>"; - - print "<label class='checkbox'><input dojoType=\"dijit.form.CheckBox\" type=\"checkbox\" id=\"always_display_enclosures\" - name=\"always_display_enclosures\" - $checked> ".__('Always display image attachments')."</label>"; - - print "</fieldset>"; - - $hide_images = $row["hide_images"]; - - if ($hide_images) { - $checked = "checked=\"1\""; - } else { - $checked = ""; - } - - print "<fieldset class='narrow'>"; - - print "<label class='checkbox'><input dojoType='dijit.form.CheckBox' type='checkbox' id='hide_images' - name='hide_images' $checked> ".__('Do not embed media')."</label>"; - - print "</fieldset>"; - - $cache_images = $row["cache_images"]; - - if ($cache_images) { - $checked = "checked=\"1\""; - } else { - $checked = ""; - } - - print "<fieldset class='narrow'>"; - - print "<label class='checkbox'><input dojoType='dijit.form.CheckBox' type='checkbox' id='cache_images' - name='cache_images' $checked> ". __('Cache media')."</label>"; - - print "</fieldset>"; - - $mark_unread_on_update = $row["mark_unread_on_update"]; - - if ($mark_unread_on_update) { - $checked = "checked"; - } else { - $checked = ""; - } - - print "<fieldset class='narrow'>"; - - print "<label class='checkbox'><input dojoType='dijit.form.CheckBox' type='checkbox' id='mark_unread_on_update' - name='mark_unread_on_update' $checked> ".__('Mark updated articles as unread')."</label>"; - - print "</fieldset>"; - - print '</div><div dojoType="dijit.layout.ContentPane" title="'.__('Icon').'">'; - - /* Icon */ - - print "<img class='feedIcon feed-editor-icon' src=\"".Feeds::getFeedIcon($feed_id)."\">"; - - print "<form onsubmit='return false;' id='feed_icon_upload_form' - enctype='multipart/form-data' method='POST'> - <label class='dijitButton'>".__("Choose file...")." - <input style='display: none' id='icon_file' size='10' name='icon_file' type='file'> - </label> - <input type='hidden' name='op' value='pref-feeds'> - <input type='hidden' name='csrf_token' value='".$_SESSION['csrf_token']."'> - <input type='hidden' name='feed_id' value='$feed_id'> - <input type='hidden' name='method' value='uploadicon'> - <button dojoType='dijit.form.Button' onclick=\"return CommonDialogs.uploadFeedIcon();\" - type='submit'>".__('Replace')."</button> - <button class='alt-danger' dojoType='dijit.form.Button' onclick=\"return CommonDialogs.removeFeedIcon($feed_id);\" - type='submit'>".__('Remove')."</button> - </form>"; - - print "</section>"; - - print '</div><div dojoType="dijit.layout.ContentPane" title="'.__('Plugins').'">'; - - PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_EDIT_FEED, $feed_id); - - print "</div></div>"; - - $title = htmlspecialchars($title, ENT_QUOTES); - - print "<footer> - <button style='float : left' class='alt-danger' dojoType='dijit.form.Button' - onclick='App.dialogOf(this).unsubscribeFeed($feed_id, \"$title\")'>". - __('Unsubscribe')."</button> - <button dojoType='dijit.form.Button' class='alt-primary' type='submit'>".__('Save')."</button> - <button dojoType='dijit.form.Button' onclick='App.dialogOf(this).hide()'>".__('Cancel')."</button> - </footer>"; + print json_encode([ + "feed" => $row, + "cats" => [ + "enabled" => get_pref('ENABLE_FEED_CATS'), + "select" => \Controls\select_feeds_cats("cat_id", $row["cat_id"]), + ], + "plugin_data" => $plugin_data, + "force_purge" => (int)Config::get(Config::FORCE_ARTICLE_PURGE), + "intervals" => [ + "update" => $local_update_intervals, + "purge" => $local_purge_intervals, + ], + "lang" => [ + "enabled" => Config::get(Config::DB_TYPE) == "pgsql", + "default" => get_pref('DEFAULT_SEARCH_LANGUAGE'), + "all" => $this::get_ts_languages(), + ] + ]); } } + private function _batch_toggle_checkbox($name) { + return \Controls\checkbox_tag("", false, "", + ["data-control-for" => $name, "title" => __("Check to enable field"), "onchange" => "App.dialogOf(this).toggleField(this)"]); + } + function editfeeds() { global $purge_intervals; global $update_intervals; $feed_ids = clean($_REQUEST["ids"]); - print_notice("Enable the options you wish to apply using checkboxes on the right:"); - - print "<p>"; - - print_hidden("ids", "$feed_ids"); - print_hidden("op", "pref-feeds"); - print_hidden("method", "batchEditSave"); - - print "<header>".__("Feed")."</header>"; - print "<section>"; - - /* Category */ - - if (get_pref('ENABLE_FEED_CATS')) { - - print "<fieldset>"; - - print "<label>" . __('Place in category:') . "</label> "; - - print_feed_cat_select("cat_id", false, - 'disabled="1" dojoType="fox.form.Select"'); - - $this->batch_edit_cbox("cat_id"); - - print "</fieldset>"; - } - - /* FTS Stemming Language */ - - if (DB_TYPE == "pgsql") { - print "<fieldset>"; - - print "<label>" . __('Language:') . "</label> "; - print_select("feed_language", "", $this::get_ts_languages(), - 'disabled="1" dojoType="fox.form.Select"'); - - $this->batch_edit_cbox("feed_language"); - - print "</fieldset>"; - } - - print "</section>"; - - print "<header>".__("Update")."</header>"; - print "<section>"; - - /* Update Interval */ - - print "<fieldset>"; - - print "<label>".__("Interval:")."</label> "; - $local_update_intervals = $update_intervals; $local_update_intervals[0] .= sprintf(" (%s)", $update_intervals[get_pref("DEFAULT_UPDATE_INTERVAL")]); - print_select_hash("update_interval", "", $local_update_intervals, - 'disabled="1" dojoType="fox.form.Select"'); - - $this->batch_edit_cbox("update_interval"); - - print "</fieldset>"; - - /* Purge intl */ - - if (FORCE_ARTICLE_PURGE == 0) { - - print "<fieldset>"; - - print "<label>" . __('Article purging:') . "</label> "; - - $local_purge_intervals = $purge_intervals; - $default_purge_interval = get_pref("PURGE_OLD_DAYS"); - - if ($default_purge_interval > 0) - $local_purge_intervals[0] .= " " . T_sprintf("(%d days)", $default_purge_interval); - else - $local_purge_intervals[0] .= " " . sprintf("(%s)", __("Disabled")); - - print_select_hash("purge_interval", "", $local_purge_intervals, - 'disabled="1" dojoType="fox.form.Select"'); - - $this->batch_edit_cbox("purge_interval"); - - print "</fieldset>"; - } - - print "</section>"; - print "<header>".__("Authentication")."</header>"; - print "<section>"; - - print "<fieldset>"; - - print "<input dojoType='dijit.form.TextBox' - placeHolder=\"".__("Login")."\" disabled='1' - autocomplete='new-password' - name='auth_login' value=''>"; - - $this->batch_edit_cbox("auth_login"); - - print "<input dojoType='dijit.form.TextBox' type='password' name='auth_pass' - autocomplete='new-password' - placeHolder=\"".__("Password")."\" disabled='1' - value=''>"; - - $this->batch_edit_cbox("auth_pass"); - - print "</fieldset>"; - - print "</section>"; - print "<header>".__("Options")."</header>"; - print "<section>"; - - print "<fieldset class='narrow'>"; - print "<label class='checkbox'><input disabled='1' type='checkbox' id='include_in_digest' - name='include_in_digest' dojoType='dijit.form.CheckBox'> ".__('Include in e-mail digest')."</label>"; - - print " "; $this->batch_edit_cbox("include_in_digest", "include_in_digest_l"); - - print "</fieldset><fieldset class='narrow'>"; - - print "<label class='checkbox'><input disabled='1' type='checkbox' id='always_display_enclosures' - name='always_display_enclosures' dojoType='dijit.form.CheckBox'> ".__('Always display image attachments')."</label>"; - - print " "; $this->batch_edit_cbox("always_display_enclosures", "always_display_enclosures_l"); - - print "</fieldset><fieldset class='narrow'>"; - - print "<label class='checkbox'><input disabled='1' type='checkbox' id='hide_images' - name='hide_images' dojoType='dijit.form.CheckBox'> ". __('Do not embed media')."</label>"; - - print " "; $this->batch_edit_cbox("hide_images", "hide_images_l"); - - print "</fieldset><fieldset class='narrow'>"; + $local_purge_intervals = $purge_intervals; + $default_purge_interval = get_pref("PURGE_OLD_DAYS"); - print "<label class='checkbox'><input disabled='1' type='checkbox' id='cache_images' - name='cache_images' dojoType='dijit.form.CheckBox'> ".__('Cache media')."</label>"; - - print " "; $this->batch_edit_cbox("cache_images", "cache_images_l"); - - print "</fieldset><fieldset class='narrow'>"; - - print "<label class='checkbox'><input disabled='1' type='checkbox' id='mark_unread_on_update' - name='mark_unread_on_update' dojoType='dijit.form.CheckBox'> ".__('Mark updated articles as unread')."</label>"; - - print " "; $this->batch_edit_cbox("mark_unread_on_update", "mark_unread_on_update_l"); - - print "</fieldset>"; - - print "</section>"; - - print "<footer> - <button dojoType='dijit.form.Button' type='submit' class='alt-primary' type='submit'>". - __('Save')."</button> - <button dojoType='dijit.form.Button' - onclick='App.dialogOf(this).hide()'>". - __('Cancel')."</button> - </footer>"; + if ($default_purge_interval > 0) + $local_purge_intervals[0] .= " " . T_sprintf("(%d days)", $default_purge_interval); + else + $local_purge_intervals[0] .= " " . sprintf("(%s)", __("Disabled")); + + $options = [ + "include_in_digest" => __('Include in e-mail digest'), + "always_display_enclosures" => __('Always display image attachments'), + "hide_images" => __('Do not embed media'), + "cache_images" => __('Cache media'), + "mark_unread_on_update" => __('Mark updated articles as unread') + ]; + + print_notice("Enable the options you wish to apply using checkboxes on the right."); + ?> + + <?= \Controls\hidden_tag("ids", $feed_ids) ?> + <?= \Controls\hidden_tag("op", "pref-feeds") ?> + <?= \Controls\hidden_tag("method", "batchEditSave") ?> + + <div dojoType="dijit.layout.TabContainer" style="height : 450px"> + <div dojoType="dijit.layout.ContentPane" title="<?= __('General') ?>"> + <section> + <?php if (get_pref('ENABLE_FEED_CATS')) { ?> + <fieldset> + <label><?= __('Place in category:') ?></label> + <?= \Controls\select_feeds_cats("cat_id", null, ['disabled' => '1']) ?> + <?= $this->_batch_toggle_checkbox("cat_id") ?> + </fieldset> + <?php } ?> + + <?php if (Config::get(Config::DB_TYPE) == "pgsql") { ?> + <fieldset> + <label><?= __('Language:') ?></label> + <?= \Controls\select_tag("feed_language", "", $this::get_ts_languages(), ["disabled"=> 1]) ?> + <?= $this->_batch_toggle_checkbox("feed_language") ?> + </fieldset> + <?php } ?> + </section> + + <hr/> + + <section> + <fieldset> + <label><?= __("Update interval:") ?></label> + <?= \Controls\select_hash("update_interval", "", $local_update_intervals, ["disabled" => 1]) ?> + <?= $this->_batch_toggle_checkbox("update_interval") ?> + </fieldset> + + <?php if (Config::get(Config::FORCE_ARTICLE_PURGE) == 0) { ?> + <fieldset> + <label><?= __('Article purging:') ?></label> + <?= \Controls\select_hash("purge_interval", "", $local_purge_intervals, ["disabled" => 1]) ?> + <?= $this->_batch_toggle_checkbox("purge_interval") ?> + </fieldset> + <?php } ?> + </section> + </div> + <div dojoType="dijit.layout.ContentPane" title="<?= __('Authentication') ?>"> + <section> + <fieldset> + <label><?= __("Login:") ?></label> + <input dojoType='dijit.form.TextBox' + disabled='1' autocomplete='new-password' name='auth_login' value=''> + <?= $this->_batch_toggle_checkbox("auth_login") ?> + </fieldset> + <fieldset> + <label><?= __("Password:") ?></label> + <input dojoType='dijit.form.TextBox' type='password' name='auth_pass' + autocomplete='new-password' disabled='1' value=''> + <?= $this->_batch_toggle_checkbox("auth_pass") ?> + </fieldset> + </section> + </div> + <div dojoType="dijit.layout.ContentPane" title="<?= __('Options') ?>"> + <?php + foreach ($options as $name => $caption) { + ?> + <fieldset class='narrow'> + <label class="checkbox text-muted"> + <?= \Controls\checkbox_tag($name, false, "", ["disabled" => "1"]) ?> + <?= $caption ?> + <?= $this->_batch_toggle_checkbox($name) ?> + </label> + </fieldset> + <?php } ?> + </div> + </div> - return; + <footer> + <?= \Controls\submit_tag(__("Save")) ?> + <?= \Controls\cancel_dialog_tag(__("Cancel")) ?> + </footer> + <?php } function batchEditSave() { @@ -989,7 +685,7 @@ class Pref_Feeds extends Handler_Protected { return $this->editsaveops(false); } - function editsaveops($batch) { + private function editsaveops($batch) { $feed_title = clean($_POST["title"]); $feed_url = clean($_POST["feed_url"]); @@ -1017,10 +713,6 @@ class Pref_Feeds extends Handler_Protected { $feed_language = clean($_POST["feed_language"]); if (!$batch) { - if (clean($_POST["need_auth"] ?? "") !== 'on') { - $auth_login = ''; - $auth_pass = ''; - } /* $sth = $this->pdo->prepare("SELECT feed_url FROM ttrss_feeds WHERE id = ?"); $sth->execute([$feed_id]); @@ -1189,7 +881,7 @@ class Pref_Feeds extends Handler_Protected { function addCat() { $feed_cat = clean($_REQUEST["cat"]); - Feeds::add_feed_category($feed_cat); + Feeds::_add_cat($feed_cat); } function importOpml() { @@ -1197,33 +889,15 @@ class Pref_Feeds extends Handler_Protected { $opml->opml_import($_SESSION["uid"]); } - function index() { - - print "<div dojoType='dijit.layout.AccordionContainer' region='center'>"; - print "<div style='padding : 0px' dojoType='dijit.layout.AccordionPane' - title=\"<i class='material-icons'>rss_feed</i> ".__('Feeds')."\">"; - - $sth = $this->pdo->prepare("SELECT COUNT(id) AS num_errors - FROM ttrss_feeds WHERE last_error != '' AND owner_uid = ?"); - $sth->execute([$_SESSION['uid']]); - - if ($row = $sth->fetch()) { - $num_errors = $row["num_errors"]; - } else { - $num_errors = 0; - } + private function index_feeds() { + $error_button = "<button dojoType='dijit.form.Button' + id='pref_feeds_errors_btn' style='display : none' + onclick='CommonDialogs.showFeedsWithErrors()'>". + __("Feeds with errors")."</button>"; - if ($num_errors > 0) { - $error_button = "<button dojoType=\"dijit.form.Button\" - onclick=\"CommonDialogs.showFeedsWithErrors()\" id=\"errorButton\">" . - __("Feeds with errors") . "</button>"; - } else { - $error_button = ""; - } - - $inactive_button = "<button dojoType=\"dijit.form.Button\" - id=\"pref_feeds_inactive_btn\" - style=\"display : none\" + $inactive_button = "<button dojoType='dijit.form.Button' + id='pref_feeds_inactive_btn' + style='display : none' onclick=\"dijit.byId('feedTree').showInactiveFeeds()\">" . __("Inactive feeds") . "</button>"; @@ -1235,175 +909,201 @@ class Pref_Feeds extends Handler_Protected { $feed_search = $_SESSION["prefs_feed_search"] ?? ""; } - print '<div dojoType="dijit.layout.BorderContainer" gutters="false">'; - - print "<div region='top' dojoType=\"fox.Toolbar\">"; #toolbar - - print "<div style='float : right; padding-right : 4px;'> - <input dojoType=\"dijit.form.TextBox\" id=\"feed_search\" size=\"20\" type=\"search\" - value=\"$feed_search\"> - <button dojoType=\"dijit.form.Button\" onclick=\"dijit.byId('feedTree').reload()\">". - __('Search')."</button> - </div>"; - - print "<div dojoType=\"fox.form.DropDownButton\">". - "<span>" . __('Select')."</span>"; - print "<div dojoType=\"dijit.Menu\" style=\"display: none;\">"; - print "<div onclick=\"dijit.byId('feedTree').model.setAllChecked(true)\" - dojoType=\"dijit.MenuItem\">".__('All')."</div>"; - print "<div onclick=\"dijit.byId('feedTree').model.setAllChecked(false)\" - dojoType=\"dijit.MenuItem\">".__('None')."</div>"; - print "</div></div>"; - - print "<div dojoType=\"fox.form.DropDownButton\">". - "<span>" . __('Feeds')."</span>"; - print "<div dojoType=\"dijit.Menu\" style=\"display: none;\">"; - print "<div onclick=\"CommonDialogs.quickAddFeed()\" - dojoType=\"dijit.MenuItem\">".__('Subscribe to feed')."</div>"; - print "<div onclick=\"dijit.byId('feedTree').editSelectedFeed()\" - dojoType=\"dijit.MenuItem\">".__('Edit selected feeds')."</div>"; - print "<div onclick=\"dijit.byId('feedTree').resetFeedOrder()\" - dojoType=\"dijit.MenuItem\">".__('Reset sort order')."</div>"; - print "<div onclick=\"dijit.byId('feedTree').batchSubscribe()\" - dojoType=\"dijit.MenuItem\">".__('Batch subscribe')."</div>"; - print "<div dojoType=\"dijit.MenuItem\" onclick=\"dijit.byId('feedTree').removeSelectedFeeds()\">" - .__('Unsubscribe')."</div> "; - print "</div></div>"; - - if (get_pref('ENABLE_FEED_CATS')) { - print "<div dojoType=\"fox.form.DropDownButton\">". - "<span>" . __('Categories')."</span>"; - print "<div dojoType=\"dijit.Menu\" style=\"display: none;\">"; - print "<div onclick=\"dijit.byId('feedTree').createCategory()\" - dojoType=\"dijit.MenuItem\">".__('Add category')."</div>"; - print "<div onclick=\"dijit.byId('feedTree').resetCatOrder()\" - dojoType=\"dijit.MenuItem\">".__('Reset sort order')."</div>"; - print "<div onclick=\"dijit.byId('feedTree').removeSelectedCategories()\" - dojoType=\"dijit.MenuItem\">".__('Remove selected')."</div>"; - print "</div></div>"; - - } - - print $error_button; - print $inactive_button; - - print "</div>"; # toolbar - - //print '</div>'; - print '<div style="padding : 0px" dojoType="dijit.layout.ContentPane" region="center">'; - - print "<div id=\"feedlistLoading\"> - <img src='images/indicator_tiny.gif'>". - __("Loading, please wait...")."</div>"; - - $auto_expand = $feed_search != "" ? "true" : "false"; - - print "<div dojoType=\"fox.PrefFeedStore\" jsId=\"feedStore\" - url=\"backend.php?op=pref-feeds&method=getfeedtree\"> - </div> - <div dojoType=\"lib.CheckBoxStoreModel\" jsId=\"feedModel\" store=\"feedStore\" - query=\"{id:'root'}\" rootId=\"root\" rootLabel=\"Feeds\" - childrenAttrs=\"items\" checkboxStrict=\"false\" checkboxAll=\"false\"> + ?> + + <div dojoType="dijit.layout.BorderContainer" gutters="false"> + <div region='top' dojoType="fox.Toolbar"> + <div style='float : right'> + <input dojoType="dijit.form.TextBox" id="feed_search" size="20" type="search" + value="<?= htmlspecialchars($feed_search) ?>"> + <button dojoType="dijit.form.Button" onclick="dijit.byId('feedTree').reload()"> + <?= __('Search') ?></button> + </div> + + <div dojoType="fox.form.DropDownButton"> + <span><?= __('Select') ?></span> + <div dojoType="dijit.Menu" style="display: none;"> + <div onclick="dijit.byId('feedTree').model.setAllChecked(true)" + dojoType="dijit.MenuItem"><?= __('All') ?></div> + <div onclick="dijit.byId('feedTree').model.setAllChecked(false)" + dojoType="dijit.MenuItem"><?= __('None') ?></div> + </div> + </div> + + <div dojoType="fox.form.DropDownButton"> + <span><?= __('Feeds') ?></span> + <div dojoType="dijit.Menu" style="display: none"> + <div onclick="CommonDialogs.subscribeToFeed()" + dojoType="dijit.MenuItem"><?= __('Subscribe to feed') ?></div> + <div onclick="dijit.byId('feedTree').editSelectedFeed()" + dojoType="dijit.MenuItem"><?= __('Edit selected feeds') ?></div> + <div onclick="dijit.byId('feedTree').resetFeedOrder()" + dojoType="dijit.MenuItem"><?= __('Reset sort order') ?></div> + <div onclick="dijit.byId('feedTree').batchSubscribe()" + dojoType="dijit.MenuItem"><?= __('Batch subscribe') ?></div> + <div dojoType="dijit.MenuItem" onclick="dijit.byId('feedTree').removeSelectedFeeds()"> + <?= __('Unsubscribe') ?></div> + </div> + </div> + + <?php if (get_pref('ENABLE_FEED_CATS')) { ?> + <div dojoType="fox.form.DropDownButton"> + <span><?= __('Categories') ?></span> + <div dojoType="dijit.Menu" style="display: none"> + <div onclick="dijit.byId('feedTree').createCategory()" + dojoType="dijit.MenuItem"><?= __('Add category') ?></div> + <div onclick="dijit.byId('feedTree').resetCatOrder()" + dojoType="dijit.MenuItem"><?= __('Reset sort order') ?></div> + <div onclick="dijit.byId('feedTree').removeSelectedCategories()" + dojoType="dijit.MenuItem"><?= __('Remove selected') ?></div> + </div> + </div> + <?php } ?> + <?= $error_button ?> + <?= $inactive_button ?> + </div> + <div style="padding : 0px" dojoType="dijit.layout.ContentPane" region="center"> + <div dojoType="fox.PrefFeedStore" jsId="feedStore" + url="backend.php?op=pref-feeds&method=getfeedtree"> + </div> + + <div dojoType="lib.CheckBoxStoreModel" jsId="feedModel" store="feedStore" + query="{id:'root'}" rootId="root" rootLabel="Feeds" childrenAttrs="items" + checkboxStrict="false" checkboxAll="false"> + </div> + + <div dojoType="fox.PrefFeedTree" id="feedTree" + dndController="dijit.tree.dndSource" + betweenThreshold="5" + autoExpand="<?= (!empty($feed_search) ? "true" : "false") ?>" + persist="true" + model="feedModel" + openOnClick="false"> + <script type="dojo/method" event="onClick" args="item"> + var id = String(item.id); + var bare_id = id.substr(id.indexOf(':')+1); + + if (id.match('FEED:')) { + CommonDialogs.editFeed(bare_id); + } else if (id.match('CAT:')) { + dijit.byId('feedTree').editCategory(bare_id, item); + } + </script> + <script type="dojo/method" event="onLoad" args="item"> + dijit.byId('feedTree').checkInactiveFeeds(); + dijit.byId('feedTree').checkErrorFeeds(); + </script> + </div> + </div> </div> - <div dojoType=\"fox.PrefFeedTree\" id=\"feedTree\" - dndController=\"dijit.tree.dndSource\" - betweenThreshold=\"5\" - autoExpand='$auto_expand' - model=\"feedModel\" openOnClick=\"false\"> - <script type=\"dojo/method\" event=\"onClick\" args=\"item\"> - var id = String(item.id); - var bare_id = id.substr(id.indexOf(':')+1); - - if (id.match('FEED:')) { - CommonDialogs.editFeed(bare_id); - } else if (id.match('CAT:')) { - dijit.byId('feedTree').editCategory(bare_id, item); - } - </script> - <script type=\"dojo/method\" event=\"onLoad\" args=\"item\"> - Element.hide(\"feedlistLoading\"); + <?php - dijit.byId('feedTree').checkInactiveFeeds(); - </script> - </div>"; - -# print "<div dojoType=\"dijit.Tooltip\" connectId=\"feedTree\" position=\"below\"> -# ".__('<b>Hint:</b> you can drag feeds and categories around.')." -# </div>"; - - print '</div>'; - print '</div>'; - - print "</div>"; # feeds pane + } - print "<div dojoType='dijit.layout.AccordionPane' - title='<i class=\"material-icons\">import_export</i> ".__('OPML')."'>"; + private function index_opml() { + ?> - print "<h3>" . __("Using OPML you can export and import your feeds, filters, labels and Tiny Tiny RSS settings.") . "</h3>"; + <h3><?= __("Using OPML you can export and import your feeds, filters, labels and Tiny Tiny RSS settings.") ?></h3> - print_notice("Only main settings profile can be migrated using OPML."); + <?php print_notice("Only main settings profile can be migrated using OPML.") ?> - print "<form id='opml_import_form' method='post' enctype='multipart/form-data' > - <label class='dijitButton'>".__("Choose file...")." - <input style='display : none' id='opml_file' name='opml_file' type='file'> + <form id='opml_import_form' method='post' enctype='multipart/form-data'> + <label class='dijitButton'><?= __("Choose file...") ?> + <input style='display : none' id='opml_file' name='opml_file' type='file'> </label> <input type='hidden' name='op' value='pref-feeds'> - <input type='hidden' name='csrf_token' value='".$_SESSION['csrf_token']."'> + <input type='hidden' name='csrf_token' value="<?= $_SESSION['csrf_token'] ?>"> <input type='hidden' name='method' value='importOpml'> - <button dojoType='dijit.form.Button' class='alt-primary' onclick=\"return Helpers.OPML.import();\" type=\"submit\">" . - __('Import OPML') . "</button>"; - - print "</form>"; + <button dojoType='dijit.form.Button' class='alt-primary' onclick="return Helpers.OPML.import()" type="submit"> + <?= __('Import OPML') ?> + </button> + </form> - print "<form dojoType='dijit.form.Form' id='opmlExportForm' style='display : inline-block'>"; + <hr/> - print "<button dojoType='dijit.form.Button' - onclick='Helpers.OPML.export()' >" . - __('Export OPML') . "</button>"; + <form dojoType='dijit.form.Form' id='opmlExportForm' style='display : inline-block'> + <button dojoType='dijit.form.Button' onclick='Helpers.OPML.export()'> + <?= __('Export OPML') ?> + </button> - print " <label class='checkbox'>"; - print_checkbox("include_settings", true, "1", ""); - print " " . __("Include settings"); - print "</label>"; - - print "</form>"; + <label class='checkbox'> + <?= \Controls\checkbox_tag("include_settings", true, "1") ?> + <?= __("Include settings") ?> + </label> + </form> - print "<p/>"; + <hr/> - print "<h2>" . __("Published OPML") . "</h2>"; + <h2><?= __("Published OPML") ?></h2> - print "<p>" . __('Your OPML can be published publicly and can be subscribed by anyone who knows the URL below.') . - " " . - __("Published OPML does not include your Tiny Tiny RSS settings, feeds that require authentication or feeds hidden from Popular feeds.") . "</p>"; + <p> + <?= __('Your OPML can be published publicly and can be subscribed by anyone who knows the URL below.') ?> + <?= __("Published OPML does not include your Tiny Tiny RSS settings, feeds that require authentication or feeds hidden from Popular feeds.") ?> + </p> - print "<button dojoType='dijit.form.Button' class='alt-primary' onclick=\"return CommonDialogs.publishedOPML()\">". - __('Display published OPML URL')."</button> "; + <button dojoType='dijit.form.Button' class='alt-primary' onclick="return Helpers.OPML.publish()"> + <?= __('Display published OPML URL') ?> + </button> + <?php PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, "prefFeedsOPML"); + } - print "</div>"; # pane - - print "<div dojoType=\"dijit.layout.AccordionPane\" - title=\"<i class='material-icons'>share</i> ".__('Published & shared articles / Generated feeds')."\">"; + private function index_shared() { + ?> - print "<h3>" . __('Published articles can be subscribed by anyone who knows the following URL:') . "</h3>"; + <h3><?= __('Published articles can be subscribed by anyone who knows the following URL:') ?></h3> - $rss_url = htmlspecialchars(get_self_url_prefix() . - "/public.php?op=rss&id=-2&view-mode=all_articles");; + <button dojoType='dijit.form.Button' class='alt-primary' + onclick="CommonDialogs.generatedFeed(-2, false)"> + <?= __('Display URL') ?> + </button> - print "<button dojoType='dijit.form.Button' class='alt-primary' - onclick='CommonDialogs.generatedFeed(-2, false, \"$rss_url\", \"".__("Published articles")."\")'>". - __('Display URL')."</button> - <button class='alt-danger' dojoType='dijit.form.Button' onclick='return Helpers.clearFeedAccessKeys()'>". - __('Clear all generated URLs')."</button> "; + <button class='alt-danger' dojoType='dijit.form.Button' onclick='return Helpers.Feeds.clearFeedAccessKeys()'> + <?= __('Clear all generated URLs') ?> + </button> + <?php PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, "prefFeedsPublishedGenerated"); + } - print "</div>"; #pane - - PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB, "prefFeeds"); - - print "</div>"; #container + function index() { + ?> + + <div dojoType='dijit.layout.TabContainer' tabPosition='left-h'> + <div style='padding : 0px' dojoType='dijit.layout.ContentPane' + title="<i class='material-icons'>rss_feed</i> <?= __('My feeds') ?>"> + <?php $this->index_feeds() ?> + </div> + + <div dojoType='dijit.layout.ContentPane' + title="<i class='material-icons'>import_export</i> <?= __('OPML') ?>"> + <?php $this->index_opml() ?> + </div> + + <div dojoType="dijit.layout.ContentPane" + title="<i class='material-icons'>share</i> <?= __('Sharing') ?>"> + <?php $this->index_shared() ?> + </div> + + <?php + ob_start(); + PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB, "prefFeeds"); + $plugin_data = trim((string)ob_get_contents()); + ob_end_clean(); + ?> + + <?php if ($plugin_data) { ?> + <div dojoType='dijit.layout.ContentPane' + title="<i class='material-icons'>extension</i> <?= __('Plugins') ?>"> + + <div dojoType='dijit.layout.AccordionContainer' region='center'> + <?= $plugin_data ?> + </div> + </div> + <?php } ?> + </div> + <?php } private function feedlist_init_cat($cat_id) { @@ -1412,9 +1112,9 @@ class Pref_Feeds extends Handler_Protected { $obj['id'] = 'CAT:' . $cat_id; $obj['items'] = array(); - $obj['name'] = Feeds::getCategoryTitle($cat_id); + $obj['name'] = Feeds::_get_cat_title($cat_id); $obj['type'] = 'category'; - $obj['unread'] = -1; //(int) Feeds::getCategoryUnread($cat_id); + $obj['unread'] = -1; //(int) Feeds::_get_cat_unread($cat_id); $obj['bare_id'] = $cat_id; return $obj; @@ -1425,7 +1125,7 @@ class Pref_Feeds extends Handler_Protected { $feed_id = (int) $feed_id; if (!$title) - $title = Feeds::getFeedTitle($feed_id, false); + $title = Feeds::_get_title($feed_id, false); if ($unread === false) $unread = getFeedUnread($feed_id, false); @@ -1436,7 +1136,7 @@ class Pref_Feeds extends Handler_Protected { $obj['type'] = 'feed'; $obj['error'] = $error; $obj['updated'] = $updated; - $obj['icon'] = Feeds::getFeedIcon($feed_id); + $obj['icon'] = Feeds::_get_icon($feed_id); $obj['bare_id'] = $feed_id; $obj['auxcounter'] = 0; @@ -1445,7 +1145,7 @@ class Pref_Feeds extends Handler_Protected { function inactiveFeeds() { - if (DB_TYPE == "pgsql") { + if (Config::get(Config::DB_TYPE) == "pgsql") { $interval_qpart = "NOW() - INTERVAL '3 months'"; } else { $interval_qpart = "DATE_SUB(NOW(), INTERVAL 3 MONTH)"; @@ -1464,56 +1164,14 @@ class Pref_Feeds extends Handler_Protected { ORDER BY last_article"); $sth->execute([$_SESSION['uid']]); - print "<div dojoType='fox.Toolbar'>"; - print "<div dojoType='fox.form.DropDownButton'>". - "<span>" . __('Select')."</span>"; - print "<div dojoType='dijit.Menu' style='display: none'>"; - print "<div onclick=\"Tables.select('inactive-feeds-list', true)\" - dojoType='dijit.MenuItem'>".__('All')."</div>"; - print "<div onclick=\"Tables.select('inactive-feeds-list', false)\" - dojoType='dijit.MenuItem'>".__('None')."</div>"; - print "</div></div>"; - print "</div>"; #toolbar - - print "<div class='panel panel-scrollable'>"; - print "<table width='100%' id='inactive-feeds-list'>"; - - $lnum = 1; - - while ($line = $sth->fetch()) { - - $feed_id = $line["id"]; - - print "<tr data-row-id='$feed_id'>"; - - print "<td width='5%' align='center'><input - onclick='Tables.onRowChecked(this);' dojoType='dijit.form.CheckBox' - type='checkbox'></td>"; - print "<td>"; - - print "<a href='#' ". - "title=\"".__("Click to edit feed")."\" ". - "onclick=\"CommonDialogs.editFeed(".$line["id"].")\">". - htmlspecialchars($line["title"])."</a>"; - - print "</td><td class='text-muted' align='right'>"; - print TimeHelper::make_local_datetime($line['last_article'], false); - print "</td>"; - print "</tr>"; + $rv = []; - ++$lnum; + while ($row = $sth->fetch(PDO::FETCH_ASSOC)) { + $row['last_article'] = TimeHelper::make_local_datetime($row['last_article'], false); + array_push($rv, $row); } - print "</table>"; - print "</div>"; - - print "<footer> - <button style='float : left' class='alt-danger' dojoType='dijit.form.Button' onclick='App.dialogOf(this).removeSelected()'>" - .__('Unsubscribe from selected feeds')."</button> - <button dojoType='dijit.form.Button' class='alt-primary' type='submit'>" - .__('Close this window')."</button> - </footer>"; - + print json_encode($rv); } function feedsWithErrors() { @@ -1521,58 +1179,13 @@ class Pref_Feeds extends Handler_Protected { FROM ttrss_feeds WHERE last_error != '' AND owner_uid = ?"); $sth->execute([$_SESSION['uid']]); - print "<div dojoType=\"fox.Toolbar\">"; - print "<div dojoType=\"fox.form.DropDownButton\">". - "<span>" . __('Select')."</span>"; - print "<div dojoType=\"dijit.Menu\" style=\"display: none;\">"; - print "<div onclick=\"Tables.select('error-feeds-list', true)\" - dojoType=\"dijit.MenuItem\">".__('All')."</div>"; - print "<div onclick=\"Tables.select('error-feeds-list', false)\" - dojoType=\"dijit.MenuItem\">".__('None')."</div>"; - print "</div></div>"; - print "</div>"; #toolbar - - print "<div class='panel panel-scrollable'>"; - print "<table width='100%' id='error-feeds-list'>"; - - $lnum = 1; - - while ($line = $sth->fetch()) { - - $feed_id = $line["id"]; - - print "<tr data-row-id='$feed_id'>"; - - print "<td width='5%' align='center'><input - onclick='Tables.onRowChecked(this);' dojoType=\"dijit.form.CheckBox\" - type=\"checkbox\"></td>"; - print "<td>"; - - print "<a class=\"visibleLink\" href=\"#\" ". - "title=\"".__("Click to edit feed")."\" ". - "onclick=\"CommonDialogs.editFeed(".$line["id"].")\">". - htmlspecialchars($line["title"])."</a>: "; - - print "<span class=\"text-muted\">"; - print htmlspecialchars($line["last_error"]); - print "</span>"; - - print "</td>"; - print "</tr>"; + $rv = []; - ++$lnum; + while ($row = $sth->fetch()) { + array_push($rv, $row); } - print "</table>"; - print "</div>"; - - print "<footer>"; - print "<button style='float : left' class='alt-danger' dojoType='dijit.form.Button' onclick='App.dialogOf(this).removeSelected()'>" - .__('Unsubscribe from selected feeds')."</button> "; - print "<button dojoType='dijit.form.Button' class='alt-primary' type='submit'>". - __('Close this window')."</button>"; - - print "</footer>"; + print json_encode($rv); } private function remove_feed_category($id, $owner_uid) { @@ -1613,8 +1226,8 @@ class Pref_Feeds extends Handler_Protected { $pdo->commit(); - if (file_exists(ICONS_DIR . "/$id.ico")) { - unlink(ICONS_DIR . "/$id.ico"); + if (file_exists(Config::get(Config::ICONS_DIR) . "/$id.ico")) { + unlink(Config::get(Config::ICONS_DIR) . "/$id.ico"); } } else { @@ -1623,52 +1236,10 @@ class Pref_Feeds extends Handler_Protected { } function batchSubscribe() { - print "<form onsubmit='return false'>"; - - print_hidden("op", "pref-feeds"); - print_hidden("method", "batchaddfeeds"); - - print "<header class='horizontal'>".__("One valid feed per line (no detection is done)")."</header>"; - print "<section>"; - - print "<textarea - style='font-size : 12px; width : 98%; height: 200px;' - dojoType='fox.form.ValidationTextArea' required='1' name='feeds'></textarea>"; - - if (get_pref('ENABLE_FEED_CATS')) { - print "<fieldset>"; - print "<label>" . __('Place in category:') . "</label> "; - print_feed_cat_select("cat", false, 'dojoType="fox.form.Select"'); - print "</fieldset>"; - } - - print "</section>"; - - print "<div id='feedDlg_loginContainer' style='display : none'>"; - - print "<header>" . __("Authentication") . "</header>"; - print "<section>"; - - print "<input dojoType='dijit.form.TextBox' name='login' placeHolder=\"".__("Login")."\"> - <input placeHolder=\"".__("Password")."\" dojoType=\"dijit.form.TextBox\" type='password' - autocomplete='new-password' name='pass''></div>"; - - print "</section>"; - print "</div>"; - - print "<fieldset class='narrow'> - <label class='checkbox'><input type='checkbox' name='need_auth' dojoType='dijit.form.CheckBox' - onclick='App.displayIfChecked(this, \"feedDlg_loginContainer\")'> ". - __('Feeds require authentication.')."</label></div>"; - print "</fieldset>"; - - print "<footer> - <button dojoType='dijit.form.Button' onclick='App.dialogOf(this).execute()' type='submit' class='alt-primary'>". - __('Subscribe')."</button> - <button dojoType='dijit.form.Button' onclick='App.dialogOf(this).hide()'>".__('Cancel')."</button> - </footer>"; - - print "</form>"; + print json_encode([ + "enable_cats" => (int)get_pref('ENABLE_FEED_CATS'), + "cat_select" => \Controls\select_feeds_cats("cat") + ]); } function batchAddFeeds() { @@ -1703,14 +1274,14 @@ class Pref_Feeds extends Handler_Protected { } function getOPMLKey() { - print json_encode(["link" => OPML::opml_publish_url()]); + print json_encode(["link" => OPML::get_publish_url()]); } function regenOPMLKey() { $this->update_feed_access_key('OPML:Publish', false, $_SESSION["uid"]); - print json_encode(["link" => OPML::opml_publish_url()]); + print json_encode(["link" => OPML::get_publish_url()]); } function regenFeedKey() { @@ -1722,11 +1293,23 @@ class Pref_Feeds extends Handler_Protected { print json_encode(["link" => $new_key]); } - function getFeedKey() { + function getsharedurl() { $feed_id = clean($_REQUEST['id']); - $is_cat = clean($_REQUEST['is_cat']); - - print json_encode(["link" => Feeds::get_feed_access_key($feed_id, $is_cat, $_SESSION["uid"])]); + $is_cat = clean($_REQUEST['is_cat']) == "true"; + $search = clean($_REQUEST['search']); + + $link = get_self_url_prefix() . "/public.php?" . http_build_query([ + 'op' => 'rss', + 'id' => $feed_id, + 'is_cat' => (int)$is_cat, + 'q' => $search, + 'key' => Feeds::_get_access_key($feed_id, $is_cat, $_SESSION["uid"]) + ]); + + print json_encode([ + "title" => Feeds::_get_title($feed_id, $is_cat), + "link" => $link + ]); } private function update_feed_access_key($feed_id, $is_cat, $owner_uid) { @@ -1736,7 +1319,7 @@ class Pref_Feeds extends Handler_Protected { WHERE feed_id = ? AND is_cat = ? AND owner_uid = ?"); $sth->execute([$feed_id, bool_to_sql_bool($is_cat), $owner_uid]); - return Feeds::get_feed_access_key($feed_id, $is_cat, $owner_uid); + return Feeds::_get_access_key($feed_id, $is_cat, $owner_uid); } // Silent @@ -1760,29 +1343,4 @@ class Pref_Feeds extends Handler_Protected { return $c; } - function getinactivefeeds() { - if (DB_TYPE == "pgsql") { - $interval_qpart = "NOW() - INTERVAL '3 months'"; - } else { - $interval_qpart = "DATE_SUB(NOW(), INTERVAL 3 MONTH)"; - } - - $sth = $this->pdo->prepare("SELECT COUNT(id) AS num_inactive FROM ttrss_feeds WHERE - (SELECT MAX(updated) FROM ttrss_entries, ttrss_user_entries WHERE - ttrss_entries.id = ref_id AND - ttrss_user_entries.feed_id = ttrss_feeds.id) < $interval_qpart AND - ttrss_feeds.owner_uid = ?"); - $sth->execute([$_SESSION['uid']]); - - if ($row = $sth->fetch()) { - print (int)$row["num_inactive"]; - } - } - - static function subscribe_to_feed_url() { - $url_path = get_self_url_prefix() . - "/public.php?op=subscribe&feed_url=%s"; - return $url_path; - } - } |