diff options
33 files changed, 829 insertions, 179 deletions
@@ -6,6 +6,9 @@ ownCloud-news (0.99) * More accurate padding when hovering over a feed * Require 5.0.6 which includes a fix for the core API * Don't highlight the tab title when there are no new unread feeds +* Make only one http request for reading all items and all items of a folder +* Fix bug that would prevent marking a feed as read when its created and no other feeds are there +* Fix bug that would prevent readding of a feed when a folder containing the feed was deleted ownCloud-news (0.98) diff --git a/appinfo/api.php b/appinfo/api.php index 2c9c7b24b..a2adcf373 100644 --- a/appinfo/api.php +++ b/appinfo/api.php @@ -75,6 +75,13 @@ use \OCA\AppFramework\External\External; \OC_API::USER_AUTH ); +\OCP\API::register('put', '/apps/news/folders/{folderId}/read', + function($params) { + return External::main('FolderAPI', 'read', $params, new DIContainer()); + }, + 'news', + \OC_API::USER_AUTH +); /** * Feed API @@ -168,4 +175,12 @@ use \OCA\AppFramework\External\External; }, 'news', \OC_API::USER_AUTH +); + +\OCP\API::register('put', '/apps/news/items/read', + function($params) { + return External::main('ItemAPI', 'readAll', $params, new DIContainer()); + }, + 'news', + \OC_API::USER_AUTH );
\ No newline at end of file diff --git a/appinfo/routes.php b/appinfo/routes.php index 1acf11334..28a6cadff 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -77,6 +77,12 @@ $this->create('news_folders_rename', '/folders/{folderId}/rename')->post()->acti } ); +$this->create('news_folders_read', '/folders/{folderId}/read')->post()->action( + function($params){ + App::main('FolderController', 'read', $params, new DIContainer()); + } +); + /** * Feeds */ @@ -118,7 +124,7 @@ $this->create('news_feeds_move', '/feeds/{feedId}/move')->post()->action( $this->create('news_feeds_read', '/feeds/{feedId}/read')->post()->action( function($params){ - App::main('ItemController', 'readFeed', $params, new DIContainer()); + App::main('FeedController', 'read', $params, new DIContainer()); } ); @@ -163,6 +169,12 @@ $this->create('news_items_unstar', '/items/{feedId}/{guidHash}/unstar')->post()- } ); +$this->create('news_items_all_read', '/items/read')->post()->action( + function($params){ + App::main('ItemController', 'readAll', $params, new DIContainer()); + } +); + /** * Export */ diff --git a/businesslayer/itembusinesslayer.php b/businesslayer/itembusinesslayer.php index 176669971..03b4c1498 100644 --- a/businesslayer/itembusinesslayer.php +++ b/businesslayer/itembusinesslayer.php @@ -127,6 +127,16 @@ class ItemBusinessLayer extends BusinessLayer { } + public function readAll($highestItemId, $userId){ + $this->mapper->readAll($highestItemId, $userId); + } + + + public function readFolder($folderId, $highestItemId, $userId){ + $this->mapper->readFolder($folderId, $highestItemId, $userId); + } + + public function readFeed($feedId, $highestItemId, $userId){ $this->mapper->readFeed($feedId, $highestItemId, $userId); } diff --git a/controller/feedcontroller.php b/controller/feedcontroller.php index 63a2c3122..b453338d0 100644 --- a/controller/feedcontroller.php +++ b/controller/feedcontroller.php @@ -43,8 +43,8 @@ class FeedController extends Controller { private $itemBusinessLayer; public function __construct(API $api, Request $request, - FeedBusinessLayer $feedBusinessLayer, FolderBusinessLayer $folderBusinessLayer, + FeedBusinessLayer $feedBusinessLayer, ItemBusinessLayer $itemBusinessLayer){ parent::__construct($api, $request); $this->feedBusinessLayer = $feedBusinessLayer; @@ -138,6 +138,11 @@ class FeedController extends Controller { 'feeds' => array($feed) ); + try { + $params['newestItemId'] = + $this->itemBusinessLayer->getNewestItemId($userId); + } catch (BusinessLayerException $ex) {} + return $this->renderJSON($params); } catch(BusinessLayerException $ex) { return $this->renderJSON(array(), $ex->getMessage()); @@ -230,5 +235,28 @@ class FeedController extends Controller { return $this->renderJSON($params); } + /** + * @IsAdminExemption + * @IsSubAdminExemption + * @Ajax + */ + public function read(){ + $userId = $this->api->getUserId(); + $feedId = (int) $this->params('feedId'); + $highestItemId = (int) $this->params('highestItemId'); + + $this->itemBusinessLayer->readFeed($feedId, $highestItemId, $userId); + + $params = array( + 'feeds' => array( + array( + 'id' => $feedId, + 'unreadCount' => 0 + ) + ) + ); + return $this->renderJSON($params); + } + }
\ No newline at end of file diff --git a/controller/foldercontroller.php b/controller/foldercontroller.php index a2e0d028b..7542a5260 100644 --- a/controller/foldercontroller.php +++ b/controller/foldercontroller.php @@ -30,17 +30,25 @@ use \OCA\AppFramework\Core\API; use \OCA\AppFramework\Http\Request; use \OCA\News\BusinessLayer\FolderBusinessLayer; +use \OCA\News\BusinessLayer\FeedBusinessLayer; +use \OCA\News\BusinessLayer\ItemBusinessLayer; use \OCA\News\BusinessLayer\BusinessLayerException; class FolderController extends Controller { private $folderBusinessLayer; + private $feedBusinessLayer; + private $itemBusinessLayer; public function __construct(API $api, Request $request, - FolderBusinessLayer $folderBusinessLayer){ + FolderBusinessLayer $folderBusinessLayer, + FeedBusinessLayer $feedBusinessLayer, + ItemBusinessLayer $itemBusinessLayer){ parent::__construct($api, $request); $this->folderBusinessLayer = $folderBusinessLayer; + $this->feedBusinessLayer = $feedBusinessLayer; + $this->itemBusinessLayer = $itemBusinessLayer; } @@ -161,5 +169,23 @@ class FolderController extends Controller { } } + /** + * @IsAdminExemption + * @IsSubAdminExemption + * @Ajax + */ + public function read(){ + $userId = $this->api->getUserId(); + $folderId = (int) $this->params('folderId'); + $highestItemId = (int) $this->params('highestItemId'); + + $this->itemBusinessLayer->readFolder($folderId, $highestItemId, $userId); + + $params = array( + 'feeds' => $this->feedBusinessLayer->findAll($userId) + ); + return $this->renderJSON($params); + } + }
\ No newline at end of file diff --git a/controller/itemcontroller.php b/controller/itemcontroller.php index d19707f90..698c7a093 100644 --- a/controller/itemcontroller.php +++ b/controller/itemcontroller.php @@ -40,8 +40,8 @@ class ItemController extends Controller { private $feedBusinessLayer; public function __construct(API $api, Request $request, - ItemBusinessLayer $itemBusinessLayer, - FeedBusinessLayer $feedBusinessLayer){ + FeedBusinessLayer $feedBusinessLayer, + ItemBusinessLayer $itemBusinessLayer){ parent::__construct($api, $request); $this->itemBusinessLayer = $itemBusinessLayer; $this->feedBusinessLayer = $feedBusinessLayer; @@ -171,20 +171,14 @@ class ItemController extends Controller { * @IsSubAdminExemption * @Ajax */ - public function readFeed(){ + public function readAll(){ $userId = $this->api->getUserId(); - $feedId = (int) $this->params('feedId'); $highestItemId = (int) $this->params('highestItemId'); - $this->itemBusinessLayer->readFeed($feedId, $highestItemId, $userId); + $this->itemBusinessLayer->readAll($highestItemId, $userId); $params = array( - 'feeds' => array( - array( - 'id' => $feedId, - 'unreadCount' => 0 - ) - ) + 'feeds' => $this->feedBusinessLayer->findAll($userId) ); return $this->renderJSON($params); } diff --git a/db/itemmapper.php b/db/itemmapper.php index 097479ecc..11f917270 100644 --- a/db/itemmapper.php +++ b/db/itemmapper.php @@ -114,26 +114,48 @@ class ItemMapper extends Mapper implements IMapper { } - public function readFeed($feedId, $highestItemId, $userId){ - // its 0 when the feed was not loaded or the loaded feed - // does not contain any items - if($highestItemId !== 0){ - $params = array(~StatusFlag::UNREAD, $feedId, $highestItemId, $userId, - $feedId); - $lowerSql = 'AND `id` <= ? '; - } else { - $lowerSql = ''; - $params = array(~StatusFlag::UNREAD, $feedId, $userId, $feedId); - } + public function readAll($highestItemId, $userId) { + $sql = 'UPDATE `*PREFIX*news_items` ' . + 'SET `status` = `status` & ? ' . + 'WHERE `id` IN (' . + 'SELECT `items`.`id` FROM `*PREFIX*news_items` `items` ' . + 'JOIN `*PREFIX*news_feeds` `feeds` ' . + 'ON `feeds`.`id` = `items`.`feed_id` '. + 'AND `items`.`id` <= ? ' . + 'AND `feeds`.`user_id` = ? ' . + ') '; + $params = array(~StatusFlag::UNREAD, $highestItemId, $userId); + $this->execute($sql, $params); + } + + public function readFolder($folderId, $highestItemId, $userId) { + $sql = 'UPDATE `*PREFIX*news_items` ' . + 'SET `status` = `status` & ? ' . + 'WHERE `id` IN (' . + 'SELECT `items`.`id` FROM `*PREFIX*news_items` `items` ' . + 'JOIN `*PREFIX*news_feeds` `feeds` ' . + 'ON `feeds`.`id` = `items`.`feed_id` '. + 'AND `feeds`.`folder_id` = ? ' . + 'AND `items`.`id` <= ? ' . + 'AND `feeds`.`user_id` = ? ' . + ') '; + $params = array(~StatusFlag::UNREAD, $folderId, $highestItemId, $userId); + $this->execute($sql, $params); + } + + + public function readFeed($feedId, $highestItemId, $userId){ $sql = 'UPDATE `*PREFIX*news_items` ' . 'SET `status` = `status` & ? ' . 'WHERE `feed_id` = ? ' . - $lowerSql . + 'AND `id` <= ? ' . 'AND EXISTS (' . 'SELECT * FROM `*PREFIX*news_feeds` ' . 'WHERE `user_id` = ? ' . 'AND `id` = ? ) '; + $params = array(~StatusFlag::UNREAD, $feedId, $highestItemId, $userId, + $feedId); $this->execute($sql, $params); } diff --git a/dependencyinjection/dicontainer.php b/dependencyinjection/dicontainer.php index cee84f35e..8334a40ad 100644 --- a/dependencyinjection/dicontainer.php +++ b/dependencyinjection/dicontainer.php @@ -110,18 +110,22 @@ class DIContainer extends BaseContainer { $this['FolderController'] = $this->share(function($c){ return new FolderController($c['API'], $c['Request'], - $c['FolderBusinessLayer']); + $c['FolderBusinessLayer'], + $c['FeedBusinessLayer'], + $c['ItemBusinessLayer']); }); $this['FeedController'] = $this->share(function($c){ return new FeedController($c['API'], $c['Request'], - $c['FeedBusinessLayer'], $c['FolderBusinessLayer'], + $c['FolderBusinessLayer'], + $c['FeedBusinessLayer'], $c['ItemBusinessLayer']); }); $this['ItemController'] = $this->share(function($c){ return new ItemController($c['API'], $c['Request'], - $c['ItemBusinessLayer'], $c['FeedBusinessLayer']); + $c['FeedBusinessLayer'], + $c['ItemBusinessLayer']); }); $this['ExportController'] = $this->share(function($c){ @@ -181,7 +185,8 @@ class DIContainer extends BaseContainer { $this['FolderAPI'] = $this->share(function($c){ return new FolderAPI($c['API'], $c['Request'], - $c['FolderBusinessLayer']); + $c['FolderBusinessLayer'], + $c['ItemBusinessLayer']); }); $this['FeedAPI'] = $this->share(function($c){ @@ -193,6 +198,7 @@ class DIContainer extends BaseContainer { $this['ItemAPI'] = $this->share(function($c){ return new ItemAPI($c['API'], $c['Request'], + $c['FeedBusinessLayer'], $c['ItemBusinessLayer']); }); diff --git a/external/folderapi.php b/external/folderapi.php index 642ca1968..879d62b5a 100644 --- a/external/folderapi.php +++ b/external/folderapi.php @@ -30,6 +30,7 @@ use \OCA\AppFramework\Controller\Controller; use \OCA\AppFramework\Http\Request; use \OCA\News\BusinessLayer\FolderBusinessLayer; +use \OCA\News\BusinessLayer\ItemBusinessLayer; use \OCA\News\BusinessLayer\BusinessLayerException; use \OCA\News\BusinessLayer\BusinessLayerExistsException; @@ -37,12 +38,15 @@ use \OCA\News\BusinessLayer\BusinessLayerExistsException; class FolderAPI extends Controller { private $folderBusinessLayer; + private $itemBusinessLayer; public function __construct(API $api, Request $request, - FolderBusinessLayer $folderBusinessLayer){ + FolderBusinessLayer $folderBusinessLayer, + ItemBusinessLayer $itemBusinessLayer){ parent::__construct($api, $request); $this->folderBusinessLayer = $folderBusinessLayer; + $this->itemBusinessLayer = $itemBusinessLayer; } @@ -113,4 +117,14 @@ class FolderAPI extends Controller { } + public function read() { + $userId = $this->api->getUserId(); + $folderId = (int) $this->params('folderId'); + $newestItemId = (int) $this->params('newestItemId'); + + $this->itemBusinessLayer->readFolder($folderId, $newestItemId, $userId); + return new NewsAPIResult(); + } + + } diff --git a/external/itemapi.php b/external/itemapi.php index 9699b4371..2ba1fcaed 100644 --- a/external/itemapi.php +++ b/external/itemapi.php @@ -147,4 +147,13 @@ class ItemAPI extends Controller { } + public function readAll() { + $userId = $this->api->getUserId(); + $newestItemId = (int) $this->params('newestItemId'); + + $this->itemBusinessLayer->readAll($newestItemId, $userId); + return new NewsAPIResult(); + } + + } diff --git a/js/app/services/businesslayer/feedbusinesslayer.coffee b/js/app/services/businesslayer/feedbusinesslayer.coffee index eb8d27de6..b2eb4f293 100644 --- a/js/app/services/businesslayer/feedbusinesslayer.coffee +++ b/js/app/services/businesslayer/feedbusinesslayer.coffee @@ -64,7 +64,7 @@ FeedModel, NewLoading, _ExistsError, Utils, $rootScope, UndoQueue, NewestItem)-> @_undoQueue.add(feed.title, callback, 10*1000, undoCallback) - markFeedRead: (feedId) -> + markRead: (feedId) -> feed = @_feedModel.getById(feedId) newestItemId = @_newestItem.getId() @@ -75,11 +75,6 @@ FeedModel, NewLoading, _ExistsError, Utils, $rootScope, UndoQueue, NewestItem)-> item.setRead() - markAllRead: -> - for feed in @_feedModel.getAll() - @markFeedRead(feed.id) - - getNumberOfFeeds: -> return @_feedModel.size() diff --git a/js/app/services/businesslayer/folderbusinesslayer.coffee b/js/app/services/businesslayer/folderbusinesslayer.coffee index e35866f21..53b434154 100644 --- a/js/app/services/businesslayer/folderbusinesslayer.coffee +++ b/js/app/services/businesslayer/folderbusinesslayer.coffee @@ -24,15 +24,16 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>. angular.module('News').factory 'FolderBusinessLayer', ['_BusinessLayer', 'FolderModel', 'FeedBusinessLayer', 'Persistence', 'FeedType', 'ActiveFeed', 'ItemModel', 'ShowAll', '_ExistsError', 'OPMLParser', -'UndoQueue', +'UndoQueue', 'NewestItem', 'FeedModel', (_BusinessLayer, FolderModel, FeedBusinessLayer, Persistence, FeedType, -ActiveFeed, ItemModel, ShowAll, _ExistsError, OPMLParser, UndoQueue) -> +ActiveFeed, ItemModel, ShowAll, _ExistsError, OPMLParser, UndoQueue, +NewestItem, FeedModel) -> class FolderBusinessLayer extends _BusinessLayer constructor: (@_folderModel, @_feedBusinessLayer, @_showAll, activeFeed, persistence, @_feedType, itemModel, @_opmlParser, - @_undoQueue) -> + @_undoQueue, @_newestItem, @_feedModel) -> super(activeFeed, persistence, itemModel, @_feedType.Folder) @@ -41,12 +42,19 @@ ActiveFeed, ItemModel, ShowAll, _ExistsError, OPMLParser, UndoQueue) -> delete: (folderId) -> + feeds = [] folder = @_folderModel.removeById(folderId) + + # also delete feeds + for feed in @_feedBusinessLayer.getFeedsOfFolder(folderId) + feeds.push(@_feedModel.removeById(feed.id)) callback = => @_persistence.deleteFolder(folderId) undoCallback = => @_folderModel.add(folder) + for feed in feeds + @_feedModel.create(feed) @_undoQueue.add(folder.name, callback, 10*1000, undoCallback) @@ -74,9 +82,16 @@ ActiveFeed, ItemModel, ShowAll, _ExistsError, OPMLParser, UndoQueue) -> @_persistence.collapseFolder(folder.id) - markFolderRead: (folderId) -> - for feed in @_feedBusinessLayer.getFeedsOfFolder(folderId) - @_feedBusinessLayer.markFeedRead(feed.id) + markRead: (folderId) -> + newestItemId = @_newestItem.getId() + folder = @_folderModel.getById(folderId) + + if newestItemId != 0 and angular.isDefined(folder) + for feed in @_feedBusinessLayer.getFeedsOfFolder(folderId) + feed.unreadCount = 0 + for item in @_itemModel.getAll() + item.setRead() + @_persistence.setFolderRead(folderId, newestItemId) getUnreadCount: (folderId) -> @@ -164,6 +179,6 @@ ActiveFeed, ItemModel, ShowAll, _ExistsError, OPMLParser, UndoQueue) -> return new FolderBusinessLayer(FolderModel, FeedBusinessLayer, ShowAll, ActiveFeed, Persistence, FeedType, ItemModel, - OPMLParser, UndoQueue) + OPMLParser, UndoQueue, NewestItem, FeedModel) ]
\ No newline at end of file diff --git a/js/app/services/businesslayer/subscriptionsbusinesslayer.coffee b/js/app/services/businesslayer/subscriptionsbusinesslayer.coffee index 23cedc955..8c0025946 100644 --- a/js/app/services/businesslayer/subscriptionsbusinesslayer.coffee +++ b/js/app/services/businesslayer/subscriptionsbusinesslayer.coffee @@ -23,14 +23,14 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>. angular.module('News').factory 'SubscriptionsBusinessLayer', ['_BusinessLayer', 'FeedBusinessLayer', 'Persistence', 'ShowAll', 'ActiveFeed', -'FeedType', 'ItemModel', +'FeedType', 'ItemModel', 'FeedModel', 'NewestItem', (_BusinessLayer, FeedBusinessLayer, Persistence, ShowAll, ActiveFeed, FeedType, -ItemModel) -> +ItemModel, FeedModel, NewestItem) -> class SubscriptionsBusinessLayer extends _BusinessLayer constructor: (@_feedBusinessLayer, @_showAll, feedType, - persistence, activeFeed, itemModel) -> + persistence, activeFeed, itemModel, @_feedModel, @_newestItem) -> super(activeFeed, persistence, itemModel, feedType.Subscriptions) isVisible: -> @@ -45,8 +45,15 @@ ItemModel) -> return visible - markAllRead: -> - @_feedBusinessLayer.markAllRead() + markRead: -> + newestItemId = @_newestItem.getId() + + if newestItemId != 0 + for feed in @_feedModel.getAll() + feed.unreadCount = 0 + for item in @_itemModel.getAll() + item.setRead() + @_persistence.setAllRead(newestItemId) getUnreadCount: -> @@ -54,5 +61,6 @@ ItemModel) -> return new SubscriptionsBusinessLayer(FeedBusinessLayer, ShowAll, FeedType, - Persistence, ActiveFeed, ItemModel) + Persistence, ActiveFeed, ItemModel, + FeedModel, NewestItem) ] diff --git a/js/app/services/persistence.coffee b/js/app/services/persistence.coffee index 771f6a5fb..a5905e745 100644 --- a/js/app/services/persistence.coffee +++ b/js/app/services/persistence.coffee @@ -126,6 +126,17 @@ $rootScope) -> @_request.post 'news_items_unread', params + setAllRead: (highestItemId) -> + ### + sets all items as read + ### + params = + data: + highestItemId: highestItemId + + @_request.post 'news_items_all_read', params + + ### FEED CONTROLLER ### @@ -325,6 +336,19 @@ $rootScope) -> @_request.post 'news_folders_rename', params + setFolderRead: (folderId, highestItemId) -> + ### + sets all items of a folder as read + ### + params = + routeParams: + folderId: folderId + data: + highestItemId: highestItemId + + @_request.post 'news_folders_read', params + + ### EXPORT CONTROLLER diff --git a/js/public/app.js b/js/public/app.js index 91a50de34..482a42104 100644 --- a/js/public/app.js +++ b/js/public/app.js @@ -859,7 +859,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>. return this._undoQueue.add(feed.title, callback, 10 * 1000, undoCallback); }; - FeedBusinessLayer.prototype.markFeedRead = function(feedId) { + FeedBusinessLayer.prototype.markRead = function(feedId) { var feed, item, newestItemId, _i, _len, _ref, _results; feed = this._feedModel.getById(feedId); @@ -877,18 +877,6 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>. } }; - FeedBusinessLayer.prototype.markAllRead = function() { - var feed, _i, _len, _ref, _results; - - _ref = this._feedModel.getAll(); - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - feed = _ref[_i]; - _results.push(this.markFeedRead(feed.id)); - } - return _results; - }; - FeedBusinessLayer.prototype.getNumberOfFeeds = function() { return this._feedModel.size(); }; @@ -1061,19 +1049,21 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>. __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.pro |