feedItems.js (5153B)
1 /* 2 ***** BEGIN LICENSE BLOCK ***** 3 4 Copyright © 2015 Center for History and New Media 5 George Mason University, Fairfax, Virginia, USA 6 http://zotero.org 7 8 This file is part of Zotero. 9 10 Zotero is free software: you can redistribute it and/or modify 11 it under the terms of the GNU Affero General Public License as published by 12 the Free Software Foundation, either version 3 of the License, or 13 (at your option) any later version. 14 15 Zotero is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 GNU Affero General Public License for more details. 19 20 You should have received a copy of the GNU Affero General Public License 21 along with Zotero. If not, see <http://www.gnu.org/licenses/>. 22 23 ***** END LICENSE BLOCK ***** 24 */ 25 26 27 /* 28 * Primary interface for accessing Zotero feed items 29 */ 30 Zotero.FeedItems = new Proxy(function() { 31 let _idCache = {}, 32 _guidCache = {}; 33 34 // Teach Zotero.Items about Zotero.FeedItem 35 36 // This one is a lazy getter, so we don't patch it up until first access 37 let zi_primaryDataSQLParts = Object.getOwnPropertyDescriptor(Zotero.Items, '_primaryDataSQLParts').get; 38 Zotero.defineProperty(Zotero.Items, '_primaryDataSQLParts', { 39 get: function() { 40 let obj = zi_primaryDataSQLParts.call(this); 41 obj.feedItemGUID = "FI.guid AS feedItemGUID"; 42 obj.feedItemReadTime = "FI.readTime AS feedItemReadTime"; 43 obj.feedItemTranslatedTime = "FI.translatedTime AS feedItemTranslatedTime"; 44 return obj; 45 } 46 }, {lazy: true}); 47 Zotero.Items._primaryDataSQLFrom += " LEFT JOIN feedItems FI ON (FI.itemID=O.itemID)"; 48 49 let zi_getObjectForRow = Zotero.Items._getObjectForRow; 50 Zotero.Items._getObjectForRow = function(row) { 51 if (row.feedItemGUID) { 52 return new Zotero.FeedItem(); 53 } 54 55 return zi_getObjectForRow.apply(Zotero.Items, arguments); 56 } 57 58 this.getIDFromGUID = Zotero.Promise.coroutine(function* (guid) { 59 if (_idCache[guid] !== undefined) return _idCache[guid]; 60 61 let id = yield Zotero.DB.valueQueryAsync('SELECT itemID FROM feedItems WHERE guid=?', [guid]); 62 if (!id) return false; 63 64 this._setGUIDMapping(guid, id); 65 return id; 66 }); 67 68 this._setGUIDMapping = function(guid, id) { 69 _idCache[guid] = id; 70 _guidCache[id] = guid; 71 }; 72 73 this._deleteGUIDMapping = function(guid, id) { 74 if (!id) id = _idCache[guid]; 75 if (!guid) guid = _guidCache[id]; 76 77 if (!guid || !id) return; 78 79 delete _idCache[guid]; 80 delete _guidCache[id]; 81 }; 82 83 this.unload = function() { 84 Zotero.Items.unload.apply(Zotero.Items, arguments); 85 let ids = Zotero.flattenArguments(arguments); 86 for (let i=0; i<ids.length; i++) { 87 this._deleteGUIDMapping(null, ids[i]); 88 } 89 }; 90 91 this.getAsyncByGUID = Zotero.Promise.coroutine(function* (guid) { 92 let id = yield this.getIDFromGUID(guid); 93 if (id === false) return false; 94 95 return this.getAsync(id); 96 }); 97 98 this.getMarkedAsRead = Zotero.Promise.coroutine(function* (libraryID, onlyGUIDs=false) { 99 let sql = "SELECT " + (onlyGUIDs ? "guid " : "itemID ") + 100 "FROM feedItems FI " + 101 "JOIN items I USING (itemID) " + 102 "WHERE libraryID=? AND readTime IS NOT NULL"; 103 let ids = yield Zotero.DB.columnQueryAsync(sql, [libraryID]); 104 if (onlyGUIDs) { 105 return ids; 106 } 107 return Zotero.FeedItems.getAsync(ids); 108 109 }); 110 111 /** 112 * Currently not used 113 */ 114 this.markAsReadByGUID = Zotero.Promise.coroutine(function* (guids) { 115 if (! Array.isArray(guids)) { 116 throw new Error('guids must be an array in Zotero.FeedItems.toggleReadByID'); 117 } 118 let ids = []; 119 Zotero.debug("Marking items as read"); 120 Zotero.debug(guids); 121 for (let guid of guids) { 122 let id = yield this.getIDFromGUID(guid); 123 if (id) { 124 ids.push(id); 125 } 126 } 127 return this.toggleReadByID(ids, true); 128 }); 129 130 this.toggleReadByID = Zotero.Promise.coroutine(function* (ids, state) { 131 if (!Array.isArray(ids)) { 132 if (typeof ids != 'string') throw new Error('ids must be a string or array in Zotero.FeedItems.toggleReadByID'); 133 134 ids = [ids]; 135 } 136 let items = yield this.getAsync(ids); 137 138 if (state == undefined) { 139 // If state undefined, toggle read if at least one unread 140 state = false; 141 for (let item of items) { 142 if (!item.isRead) { 143 state = true; 144 break; 145 } 146 } 147 } 148 149 let feedsToUpdate = new Set(); 150 let readTime = state ? Zotero.Date.dateToSQL(new Date(), true) : null; 151 for (let i=0; i<items.length; i++) { 152 items[i]._feedItemReadTime = readTime; 153 154 let feed = Zotero.Feeds.get(items[i].libraryID); 155 feedsToUpdate.add(feed); 156 } 157 158 yield Zotero.DB.queryAsync(`UPDATE feedItems SET readTime=? WHERE itemID IN (${ids.join(', ')})`, readTime); 159 yield Zotero.Notifier.trigger('modify', 'item', ids, {}); 160 161 for (let feed of feedsToUpdate) { 162 yield feed.updateUnreadCount(); 163 } 164 }); 165 166 return this; 167 }.call({}), 168 169 // Proxy handler 170 { 171 get: function(target, name) { 172 return name in target 173 ? target[name] 174 : Zotero.Items[name]; 175 }, 176 has: function(target, name) { 177 return name in target || name in Zotero.Items; 178 } 179 });