From e04c18a2c29d10184417d853391ae1d2708d4f4f Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Mon, 28 Dec 2009 17:23:01 +0300 Subject: [PATCH] implement archived articles feed; bump schema --- backend.php | 7 +- functions.php | 129 +++++++++++++++++++++++++--------- modules/backend-rpc.php | 51 ++++++++++++++ schema/ttrss_schema_mysql.sql | 7 +- schema/ttrss_schema_pgsql.sql | 5 +- schema/versions/mysql/60.sql | 12 ++++ schema/versions/pgsql/60.sql | 12 ++++ viewfeed.js | 100 ++++++++++++++++++++++++++ 8 files changed, 281 insertions(+), 42 deletions(-) create mode 100644 schema/versions/mysql/60.sql create mode 100644 schema/versions/pgsql/60.sql diff --git a/backend.php b/backend.php index b4b58a787..cee8c26ce 100644 --- a/backend.php +++ b/backend.php @@ -211,7 +211,6 @@ case "view": $id = db_escape_string($_GET["id"]); - $feed_id = db_escape_string($_GET["feed"]); $cids = split(",", db_escape_string($_GET["cids"])); $mode = db_escape_string($_GET["mode"]); $omode = db_escape_string($_GET["omode"]); @@ -224,9 +223,9 @@ // just gets marked as read (it already exists in client cache) if ($mode == "") { - outputArticleXML($link, $id, $feed_id); + outputArticleXML($link, $id, false); } else if ($mode == "zoom") { - outputArticleXML($link, $id, $feed_id, true, true); + outputArticleXML($link, $id, false, true, true); } else { catchupArticleById($link, $id, 0); ccache_update($link, $feed_id, $_SESSION["uid"]); @@ -235,7 +234,7 @@ if (!$_SESSION["bw_limit"]) { foreach ($cids as $cid) { if ($cid) { - outputArticleXML($link, $cid, $feed_id, false); + outputArticleXML($link, $cid, false, false); } } } diff --git a/functions.php b/functions.php index 02521b313..5c285c4e2 100644 --- a/functions.php +++ b/functions.php @@ -754,9 +754,8 @@ foreach ($iterator as $item) { - if ($_GET['xdebug']) { + if ($_GET['xdebug'] == 2) { print_r($item); - } if ($use_simplepie) { @@ -857,7 +856,7 @@ } } - if ($_GET["xdebug"]) { + if ($_GET["xdebug"] == 2) { print "update_rss_feed: content: "; print_r(htmlspecialchars($entry_content)); } @@ -1135,7 +1134,7 @@ // do we allow duplicate posts with same GUID in different feeds? if (get_pref($link, "ALLOW_DUPLICATE_POSTS", $owner_uid, false)) { - $dupcheck_qpart = "AND feed_id = '$feed'"; + $dupcheck_qpart = "AND (feed_id = '$feed' OR feed_id IS NULL)"; } else { $dupcheck_qpart = ""; } @@ -1213,6 +1212,10 @@ $entry_int_id = db_fetch_result($result, 0, "int_id"); } } else { + if (defined('DAEMON_EXTENDED_DEBUG') || $_GET['xdebug']) { + _debug("update_rss_feed: user record FOUND"); + } + $entry_ref_id = db_fetch_result($result, 0, "ref_id"); $entry_int_id = db_fetch_result($result, 0, "int_id"); } @@ -1589,6 +1592,8 @@ $rtl_content = false, $last_updated = false, $last_error = false, $fg_content = false, $bg_content = false) { + if (!$feed_title) $feed_title = getFeedTitle($link, $feed_id, false); + if (file_exists($icon_file) && filesize($icon_file) > 0) { $feed_icon = ""; } else { @@ -2467,7 +2472,7 @@ } } else if ($n_feed == -4) { $match_part = "true"; - } else if ($n_feed > 0) { + } else if ($n_feed >= 0) { $result = db_query($link, "SELECT id FROM ttrss_feeds WHERE parent_feed = '$n_feed' @@ -2503,7 +2508,11 @@ return $unread; } else { - $match_part = "feed_id = '$n_feed'"; + if ($n_feed != 0) { + $match_part = "feed_id = '$n_feed'"; + } else { + $match_part = "feed_id IS NULL"; + } } } else if ($feed < -10) { @@ -2514,12 +2523,18 @@ } if ($match_part) { - + + if ($n_feed != 0) { + $from_qpart = "ttrss_user_entries,ttrss_feeds,ttrss_entries"; + $feeds_qpart = "ttrss_feeds.hidden = false AND + ttrss_user_entries.feed_id = ttrss_feeds.id AND"; + } else { + $from_qpart = "ttrss_user_entries,ttrss_entries"; + } + $result = db_query($link, "SELECT count(int_id) AS unread - FROM ttrss_user_entries,ttrss_feeds,ttrss_entries WHERE - ttrss_user_entries.feed_id = ttrss_feeds.id AND + FROM $from_qpart WHERE ttrss_user_entries.ref_id = ttrss_entries.id AND - ttrss_feeds.hidden = false AND $age_qpart AND $unread_qpart AND ($match_part) AND ttrss_user_entries.owner_uid = " . $owner_uid); @@ -2633,7 +2648,7 @@ $ret_arr = array(); - for ($i = -1; $i >= -4; $i--) { + for ($i = 0; $i >= -4; $i--) { $count = getFeedUnread($link, $i); @@ -2969,6 +2984,8 @@ return __("Fresh articles"); } else if ($id == -4) { return __("All articles"); + } else if ($id == 0) { + return __("Archived articles"); } else if ($id < -10) { $label_id = -$id - 11; $result = db_query($link, "SELECT caption FROM ttrss_labels2 WHERE id = '$label_id'"); @@ -3231,7 +3248,7 @@ $query_strategy_part = "ttrss_entries.id > 0"; $vfeed_query_part = "(SELECT title FROM ttrss_feeds WHERE id = feed_id) as feed_title,"; - } else if ($feed >= 0 && $search && $search_mode == "this_cat") { + } else if ($feed > 0 && $search && $search_mode == "this_cat") { $vfeed_query_part = "ttrss_feeds.title AS feed_title,"; @@ -3260,7 +3277,7 @@ $query_strategy_part = "ttrss_entries.id > 0"; } - } else if ($feed >= 0) { + } else if ($feed > 0) { if ($cat_view) { @@ -3292,6 +3309,8 @@ $query_strategy_part = "feed_id = '$feed'"; } } + } else if ($feed == 0) { // starred virtual feed + $query_strategy_part = "feed_id IS NULL"; } else if ($feed == -1) { // starred virtual feed $query_strategy_part = "marked = true"; $vfeed_query_part = "ttrss_feeds.title AS feed_title,"; @@ -3450,6 +3469,16 @@ } */ } + if ($feed != "0") { + $from_qpart = "ttrss_entries,ttrss_user_entries,ttrss_feeds$ext_tables_part"; + $feed_check_qpart = "ttrss_feeds.hidden = false AND + ttrss_user_entries.feed_id = ttrss_feeds.id AND"; + + } else { + $from_qpart = "ttrss_entries,ttrss_user_entries$ext_tables_part + LEFT JOIN ttrss_feeds ON (feed_id = ttrss_feeds.id)"; + } + $query = "SELECT DISTINCT guid, ttrss_entries.id,ttrss_entries.title, @@ -3462,11 +3491,10 @@ ".SUBSTRING_FOR_DATE."(updated,1,19) as updated_noms, author,score FROM - ttrss_entries,ttrss_user_entries,ttrss_feeds$ext_tables_part + $from_qpart WHERE $group_limit_part - ttrss_feeds.hidden = false AND - ttrss_user_entries.feed_id = ttrss_feeds.id AND + $feed_check_qpart ttrss_user_entries.ref_id = ttrss_entries.id AND ttrss_user_entries.owner_uid = '$owner_uid' AND $search_query_part @@ -3507,6 +3535,8 @@ $limit_query_part"); } + if (!$feed_title) $feed_title = getFeedTitle($link, $feed_id); + return array($result, $feed_title, $feed_site_url, $last_error); } @@ -4017,6 +4047,9 @@ $catchup_feed_link = "javascript:catchupCurrentFeed()"; $catchup_sel_link = "javascript:catchupSelection()"; + $archive_sel_link = "javascript:archiveSelection()"; + $delete_sel_link = "javascript:deleteSelection()"; + if (!get_pref($link, 'COMBINED_DISPLAY_MODE')) { $sel_all_link = "javascript:selectTableRowsByIdPrefix('headlinesList', 'RROW-', 'RCHK-', true, '', true)"; @@ -4116,6 +4149,15 @@ print "
  •   ".__('Entire feed'). "
  • "; + if ($feed_id != "0") { + print "
  • ".__('Selection:')."
  • +
  •   ".__('Archive')."
  • "; + } else { + print "
  • ".__('Selection:')."
  • +
  •   ".__('Move back')."
  • +
  •   ".__('Delete')."
  • "; + } + //print "
  • --------
  • "; print "
  • ".__('Assign label:')."
  • "; @@ -4194,41 +4236,41 @@ $num_published = getFeedUnread($link, -2); $num_fresh = getFeedUnread($link, -3); $num_total = getFeedUnread($link, -4); + $num_archive = getFeedUnread($link, 0); $class = "virt"; if ($num_total > 0) $class .= "Unread"; - printFeedEntry(-4, $class, __("All articles"), $num_total, + printFeedEntry(-4, $class, false, $num_total, + "images/tag.png", $link); + + $class = "virt"; + + if ($num_archive > 0) $class .= "Unread"; + + printFeedEntry(0, $class, false, $num_archive, "images/tag.png", $link); $class = "virt"; if ($num_fresh > 0) $class .= "Unread"; - printFeedEntry(-3, $class, __("Fresh articles"), $num_fresh, + printFeedEntry(-3, $class, false, $num_fresh, "images/fresh.png", $link); $class = "virt"; if ($num_starred > 0) $class .= "Unread"; - $is_ie = (strpos($_SESSION["client.userAgent"], "MSIE") !== false); - - if ($is_ie) { - $mark_img_ext = "gif"; - } else { - $mark_img_ext = "png"; - } - - printFeedEntry(-1, $class, __("Starred articles"), $num_starred, - "images/mark_set.$mark_img_ext", $link); + printFeedEntry(-1, $class, false, $num_starred, + "images/mark_set.png", $link); $class = "virt"; if ($num_published > 0) $class .= "Unread"; - printFeedEntry(-2, $class, __("Published articles"), $num_published, + printFeedEntry(-2, $class, false, $num_published, "images/pub_set.gif", $link); if (get_pref($link, 'ENABLE_FEED_CATS')) { @@ -4616,12 +4658,12 @@ $zoom_mode = false) { /* we can figure out feed_id from article id anyway, why do we - * pass feed_id here? */ + * pass feed_id here? let's ignore the argument :( */ $result = db_query($link, "SELECT feed_id FROM ttrss_user_entries WHERE ref_id = '$id'"); - $feed_id = db_fetch_result($result, 0, "feed_id"); + $feed_id = (int) db_fetch_result($result, 0, "feed_id"); if (!$zoom_mode) { print "
     "; # } else { - print ""; + print ""; print "$updated_fmt "; + print "$updated_fmt "; print "$score_pic"; @@ -5600,8 +5642,14 @@ * @return void */ function clear_feed_articles($link, $id) { - $result = db_query($link, "DELETE FROM ttrss_user_entries + + if ($id != 0) { + $result = db_query($link, "DELETE FROM ttrss_user_entries WHERE feed_id = '$id' AND marked = false AND owner_uid = " . $_SESSION["uid"]); + } else { + $result = db_query($link, "DELETE FROM ttrss_user_entries + WHERE feed_id IS NULL AND marked = false AND owner_uid = " . $_SESSION["uid"]); + } $result = db_query($link, "DELETE FROM ttrss_entries WHERE (SELECT COUNT(int_id) FROM ttrss_user_entries WHERE ref_id = id) = 0"); @@ -6320,9 +6368,22 @@ function remove_feed($link, $id, $owner_uid) { if ($id > 0) { + + /* save starred articles in Archived feed */ + + db_query($link, "BEGIN"); + + db_query($link, "UPDATE ttrss_user_entries SET feed_id = NULL + WHERE feed_id = '$id' AND + marked = true AND owner_uid = $owner_uid"); + + /* remove the feed */ + db_query($link, "DELETE FROM ttrss_feeds WHERE id = '$id' AND owner_uid = $owner_uid"); + db_query($link, "COMMIT"); + if (file_exists(ICONS_DIR . "/$id.ico")) { unlink(ICONS_DIR . "/$id.ico"); } diff --git a/modules/backend-rpc.php b/modules/backend-rpc.php index 686602d6f..326c669fb 100644 --- a/modules/backend-rpc.php +++ b/modules/backend-rpc.php @@ -86,6 +86,57 @@ return; } + if ($subop == "delete") { + $ids = db_escape_string($_GET["ids"]); + + $result = db_query($link, "DELETE FROM ttrss_user_entries + WHERE ref_id IN ($ids) AND owner_uid = " . $_SESSION["uid"]); + + print ""; + getGlobalCounters($link); + if (get_pref($link, 'ENABLE_FEED_CATS')) { + getCategoryCounters($link); + } + print ""; + + return; + } + + if ($subop == "unarchive") { + $ids = db_escape_string($_GET["ids"]); + + $result = db_query($link, "UPDATE ttrss_user_entries + SET feed_id = orig_feed_id + WHERE ref_id IN ($ids) AND owner_uid = " . $_SESSION["uid"]); + + print ""; + getGlobalCounters($link); + if (get_pref($link, 'ENABLE_FEED_CATS')) { + getCategoryCounters($link); + } + print ""; + + return; + } + + if ($subop == "archive") { + $ids = db_escape_string($_GET["ids"]); + + $result = db_query($link, "UPDATE ttrss_user_entries + SET orig_feed_id = feed_id, feed_id = NULL, marked = true + WHERE ref_id IN ($ids) AND owner_uid = " . $_SESSION["uid"]); + + print ""; + getGlobalCounters($link); + if (get_pref($link, 'ENABLE_FEED_CATS')) { + getCategoryCounters($link); + } + print ""; + + return; + } + + if ($subop == "publ") { $pub = $_REQUEST["pub"]; $id = db_escape_string($_REQUEST["id"]); diff --git a/schema/ttrss_schema_mysql.sql b/schema/ttrss_schema_mysql.sql index 95edaffdd..c6de60287 100644 --- a/schema/ttrss_schema_mysql.sql +++ b/schema/ttrss_schema_mysql.sql @@ -133,7 +133,8 @@ create index ttrss_entries_date_entered_index on ttrss_entries(date_entered); create table ttrss_user_entries ( int_id integer not null primary key auto_increment, ref_id integer not null, - feed_id int not null, + feed_id int, + orig_feed_id int, owner_uid integer not null, marked bool not null default 0, published bool not null default 0, @@ -145,6 +146,8 @@ create table ttrss_user_entries ( foreign key (ref_id) references ttrss_entries(id) ON DELETE CASCADE, index (feed_id), foreign key (feed_id) references ttrss_feeds(id) ON DELETE CASCADE, + index (orig_feed_id), + foreign key (orig_feed_id) references ttrss_feeds(id) ON DELETE SET NULL, index (owner_uid), foreign key (owner_uid) references ttrss_users(id) ON DELETE CASCADE) TYPE=InnoDB; @@ -226,7 +229,7 @@ create table ttrss_tags (id integer primary key auto_increment, create table ttrss_version (schema_version int not null) TYPE=InnoDB; -insert into ttrss_version values (59); +insert into ttrss_version values (60); create table ttrss_enclosures (id serial not null primary key, content_url text not null, diff --git a/schema/ttrss_schema_pgsql.sql b/schema/ttrss_schema_pgsql.sql index 0b6f719e1..7afebb5d9 100644 --- a/schema/ttrss_schema_pgsql.sql +++ b/schema/ttrss_schema_pgsql.sql @@ -121,7 +121,8 @@ create index ttrss_entries_date_entered_index on ttrss_entries(date_entered); create table ttrss_user_entries ( int_id serial not null primary key, ref_id integer not null references ttrss_entries(id) ON DELETE CASCADE, - feed_id int references ttrss_feeds(id) ON DELETE CASCADE not null, + feed_id int references ttrss_feeds(id) ON DELETE CASCADE, + orig_feed_id int references ttrss_feeds(id) ON DELETE SET NULL, owner_uid integer not null references ttrss_users(id) ON DELETE CASCADE, marked boolean not null default false, published boolean not null default false, @@ -202,7 +203,7 @@ create index ttrss_tags_owner_uid_index on ttrss_tags(owner_uid); create table ttrss_version (schema_version int not null); -insert into ttrss_version values (59); +insert into ttrss_version values (60); create table ttrss_enclosures (id serial not null primary key, content_url text not null, diff --git a/schema/versions/mysql/60.sql b/schema/versions/mysql/60.sql new file mode 100644 index 000000000..a2c023354 --- /dev/null +++ b/schema/versions/mysql/60.sql @@ -0,0 +1,12 @@ +begin; + +alter table ttrss_user_entries change feed_id feed_id integer null; + +alter table ttrss_user_entries add column orig_feed_id integer; +update ttrss_user_entries set orig_feed_id = NULL; + +alter table ttrss_user_entries add constraint FOREIGN KEY (orig_feed_id) REFERENCES ttrss_feeds(id) ON DELETE SET NULL; + +update ttrss_version set schema_version = 60; + +commit; diff --git a/schema/versions/pgsql/60.sql b/schema/versions/pgsql/60.sql new file mode 100644 index 000000000..39a2e202b --- /dev/null +++ b/schema/versions/pgsql/60.sql @@ -0,0 +1,12 @@ +begin; + +alter table ttrss_user_entries alter column feed_id drop not null; + +alter table ttrss_user_entries add column orig_feed_id integer; +update ttrss_user_entries set orig_feed_id = NULL; + +alter table ttrss_user_entries add constraint "$4" FOREIGN KEY (orig_feed_id) REFERENCES ttrss_feeds(id) ON DELETE SET NULL; + +update ttrss_version set schema_version = 60; + +commit; diff --git a/viewfeed.js b/viewfeed.js index 9515cca6d..ef3ab2c6c 100644 --- a/viewfeed.js +++ b/viewfeed.js @@ -1321,6 +1321,106 @@ function catchupPage() { } } +function deleteSelection() { + + try { + + var rows; + + if ($("headlinesList")) { + rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK"); + } else { + rows = cdmGetSelectedArticles(); + } + + if (rows.length == 0) { + alert(__("No articles are selected.")); + return; + } + + + var fn = getFeedName(getActiveFeedId(), activeFeedIsCat()); + var str; + var op; + + if (getActiveFeedId() != 0) { + str = __("Delete %d selected articles in %s?"); + } else { + str = __("Delete %d selected articles?"); + } + + str = str.replace("%d", rows.length); + str = str.replace("%s", fn); + + if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) { + return; + } + + query = "backend.php?op=rpc&subop=delete&ids=" + param_escape(rows); + + debug(query); + + new Ajax.Request(query, { + onComplete: function(transport) { + viewCurrentFeed(); + } }); + + } catch (e) { + exception_error("archiveSelection", e); + } +} + +function archiveSelection() { + + try { + + var rows; + + if ($("headlinesList")) { + rows = getSelectedTableRowIds("headlinesList", "RROW", "RCHK"); + } else { + rows = cdmGetSelectedArticles(); + } + + if (rows.length == 0) { + alert(__("No articles are selected.")); + return; + } + + + var fn = getFeedName(getActiveFeedId(), activeFeedIsCat()); + var str; + var op; + + if (getActiveFeedId() != 0) { + str = __("Archive %d selected articles in %s?"); + op = "archive"; + } else { + str = __("Move %d archived articles back?"); + op = "unarchive"; + } + + str = str.replace("%d", rows.length); + str = str.replace("%s", fn); + + if (getInitParam("confirm_feed_catchup") == 1 && !confirm(str)) { + return; + } + + query = "backend.php?op=rpc&subop="+op+"&ids=" + param_escape(rows); + + debug(query); + + new Ajax.Request(query, { + onComplete: function(transport) { + viewCurrentFeed(); + } }); + + } catch (e) { + exception_error("archiveSelection", e); + } +} + function catchupSelection() { try {