From b8b4dfb4969e1baf84a14fb65a5dc153b0f5fae4 Mon Sep 17 00:00:00 2001 From: Bernhard Posselt Date: Thu, 9 May 2013 12:57:35 +0200 Subject: only make one request for mark all read and mark folder read, fix #171, fix a bug that prevented readding of feeds when its folder was deleted, fix a bug that would not allow mark read for feeds when the app was started for the first time --- CHANGELOG | 3 + appinfo/api.php | 15 ++ appinfo/routes.php | 14 +- businesslayer/itembusinesslayer.php | 10 ++ controller/feedcontroller.php | 30 +++- controller/foldercontroller.php | 28 +++- controller/itemcontroller.php | 16 +- db/itemmapper.php | 46 ++++-- dependencyinjection/dicontainer.php | 14 +- external/folderapi.php | 16 +- external/itemapi.php | 9 ++ .../businesslayer/feedbusinesslayer.coffee | 7 +- .../businesslayer/folderbusinesslayer.coffee | 29 +++- .../subscriptionsbusinesslayer.coffee | 20 ++- js/app/services/persistence.coffee | 24 +++ js/public/app.js | 124 ++++++++++++---- .../businesslayer/feedbusinesslayerSpec.coffee | 18 +-- .../businesslayer/folderbusinesslayerSpec.coffee | 13 +- .../subsriptionsbusinesslayerSpec.coffee | 16 +- js/tests/services/persistenceSpec.coffee | 24 ++- templates/part.feed.unread.php | 2 +- templates/part.listfeed.php | 2 +- templates/part.listfolder.php | 2 +- tests/acceptance/features/support/env.rb | 4 + tests/acceptance/run.sh | 2 +- tests/acceptance/static/kernel.org.atom | 165 +++++++++++++++++++++ tests/unit/businesslayer/ItemBusinessLayerTest.php | 26 ++++ tests/unit/controller/FeedControllerTest.php | 81 +++++++++- tests/unit/controller/FolderControllerTest.php | 52 ++++++- tests/unit/controller/ItemControllerTest.php | 38 +++-- tests/unit/db/ItemMapperTest.php | 44 ++++-- tests/unit/external/FolderAPITest.php | 86 +++++++---- tests/unit/external/ItemAPITest.php | 28 ++++ 33 files changed, 829 insertions(+), 179 deletions(-) create mode 100644 tests/acceptance/static/kernel.org.atom diff --git a/CHANGELOG b/CHANGELOG index cd5389d0a..abf6c4d3f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -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 . 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 . 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 . 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 . } }; - 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 . __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.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; angular.module('News').factory('FolderBusinessLayer', [ - '_BusinessLayer', 'FolderModel', 'FeedBusinessLayer', 'Persistence', 'FeedType', 'ActiveFeed', 'ItemModel', 'ShowAll', '_ExistsError', 'OPMLParser', 'UndoQueue', function(_BusinessLayer, FolderModel, FeedBusinessLayer, Persistence, FeedType, ActiveFeed, ItemModel, ShowAll, _ExistsError, OPMLParser, UndoQueue) { + '_BusinessLayer', 'FolderModel', 'FeedBusinessLayer', 'Persistence', 'FeedType', 'ActiveFeed', 'ItemModel', 'ShowAll', '_ExistsError', 'OPMLParser', 'UndoQueue', 'NewestItem', 'FeedModel', function(_BusinessLayer, FolderModel, FeedBusinessLayer, Persistence, FeedType, ActiveFeed, ItemModel, ShowAll, _ExistsError, OPMLParser, UndoQueue, NewestItem, FeedModel) { var FolderBusinessLayer; FolderBusinessLayer = (function(_super) { __extends(FolderBusinessLayer, _super); - function FolderBusinessLayer(_folderModel, _feedBusinessLayer, _showAll, activeFeed, persistence, _feedType, itemModel, _opmlParser, _undoQueue) { + function FolderBusinessLayer(_folderModel, _feedBusinessLayer, _showAll, activeFeed, persistence, _feedType, itemModel, _opmlParser, _undoQueue, _newestItem, _feedModel) { this._folderModel = _folderModel; this._feedBusinessLayer = _feedBusinessLayer; this._showAll = _showAll; this._feedType = _feedType; this._opmlParser = _opmlParser; this._undoQueue = _undoQueue; + this._newestItem = _newestItem; + this._feedModel = _feedModel; FolderBusinessLayer.__super__.constructor.call(this, activeFeed, persistence, itemModel, this._feedType.Folder); } @@ -1082,15 +1072,29 @@ License along with this library. If not, see . }; FolderBusinessLayer.prototype["delete"] = function(folderId) { - var callback, folder, undoCallback, + var callback, feed, feeds, folder, undoCallback, _i, _len, _ref, _this = this; + feeds = []; folder = this._folderModel.removeById(folderId); + _ref = this._feedBusinessLayer.getFeedsOfFolder(folderId); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + feed = _ref[_i]; + feeds.push(this._feedModel.removeById(feed.id)); + } callback = function() { return _this._persistence.deleteFolder(folderId); }; undoCallback = function() { - return _this._folderModel.add(folder); + var _j, _len1, _results; + + _this._folderModel.add(folder); + _results = []; + for (_j = 0, _len1 = feeds.length; _j < _len1; _j++) { + feed = feeds[_j]; + _results.push(_this._feedModel.create(feed)); + } + return _results; }; return this._undoQueue.add(folder.name, callback, 10 * 1000, undoCallback); }; @@ -1125,16 +1129,24 @@ License along with this library. If not, see . } }; - FolderBusinessLayer.prototype.markFolderRead = function(folderId) { - var feed, _i, _len, _ref, _results; + FolderBusinessLayer.prototype.markRead = function(folderId) { + var feed, folder, item, newestItemId, _i, _j, _len, _len1, _ref, _ref1; - _ref = this._feedBusinessLayer.getFeedsOfFolder(folderId); - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - feed = _ref[_i]; - _results.push(this._feedBusinessLayer.markFeedRead(feed.id)); + newestItemId = this._newestItem.getId(); + folder = this._folderModel.getById(folderId); + if (newestItemId !== 0 && angular.isDefined(folder)) { + _ref = this._feedBusinessLayer.getFeedsOfFolder(folderId); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + feed = _ref[_i]; + feed.unreadCount = 0; + } + _ref1 = this._itemModel.getAll(); + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + item = _ref1[_j]; + item.setRead(); + } + return this._persistence.setFolderRead(folderId, newestItemId); } - return _results; }; FolderBusinessLayer.prototype.getUnreadCount = function(folderId) { @@ -1261,7 +1273,7 @@ License along with this library. If not, see . return FolderBusinessLayer; })(_BusinessLayer); - return new FolderBusinessLayer(FolderModel, FeedBusinessLayer, ShowAll, ActiveFeed, Persistence, FeedType, ItemModel, OPMLParser, UndoQueue); + return new FolderBusinessLayer(FolderModel, FeedBusinessLayer, ShowAll, ActiveFeed, Persistence, FeedType, ItemModel, OPMLParser, UndoQueue, NewestItem, FeedModel); } ]); @@ -1516,15 +1528,17 @@ License along with this library. If not, see . __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.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; angular.module('News').factory('SubscriptionsBusinessLayer', [ - '_BusinessLayer', 'FeedBusinessLayer', 'Persistence', 'ShowAll', 'ActiveFeed', 'FeedType', 'ItemModel', function(_BusinessLayer, FeedBusinessLayer, Persistence, ShowAll, ActiveFeed, FeedType, ItemModel) { + '_BusinessLayer', 'FeedBusinessLayer', 'Persistence', 'ShowAll', 'ActiveFeed', 'FeedType', 'ItemModel', 'FeedModel', 'NewestItem', function(_BusinessLayer, FeedBusinessLayer, Persistence, ShowAll, ActiveFeed, FeedType, ItemModel, FeedModel, NewestItem) { var SubscriptionsBusinessLayer; SubscriptionsBusinessLayer = (function(_super) { __extends(SubscriptionsBusinessLayer, _super); - function SubscriptionsBusinessLayer(_feedBusinessLayer, _showAll, feedType, persistence, activeFeed, itemModel) { + function SubscriptionsBusinessLayer(_feedBusinessLayer, _showAll, feedType, persistence, activeFeed, itemModel, _feedModel, _newestItem) { this._feedBusinessLayer = _feedBusinessLayer; this._showAll = _showAll; + this._feedModel = _feedModel; + this._newestItem = _newestItem; SubscriptionsBusinessLayer.__super__.constructor.call(this, activeFeed, persistence, itemModel, feedType.Subscriptions); } @@ -1542,8 +1556,23 @@ License along with this library. If not, see . } }; - SubscriptionsBusinessLayer.prototype.markAllRead = function() { - return this._feedBusinessLayer.markAllRead(); + SubscriptionsBusinessLayer.prototype.markRead = function() { + var feed, item, newestItemId, _i, _j, _len, _len1, _ref, _ref1; + + newestItemId = this._newestItem.getId(); + if (newestItemId !== 0) { + _ref = this._feedModel.getAll(); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + feed = _ref[_i]; + feed.unreadCount = 0; + } + _ref1 = this._itemModel.getAll(); + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + item = _ref1[_j]; + item.setRead(); + } + return this._persistence.setAllRead(newestItemId); + } }; SubscriptionsBusinessLayer.prototype.getUnreadCount = function() { @@ -1553,7 +1582,7 @@ License along with this library. If not, see . return SubscriptionsBusinessLayer; })(_BusinessLayer); - return new SubscriptionsBusinessLayer(FeedBusinessLayer, ShowAll, FeedType, Persistence, ActiveFeed, ItemModel); + return new SubscriptionsBusinessLayer(FeedBusinessLayer, ShowAll, FeedType, Persistence, ActiveFeed, ItemModel, FeedModel, NewestItem); } ]); @@ -2530,6 +2559,21 @@ License along with this library. If not, see . return this._request.post('news_items_unread', params); }; + Persistence.prototype.setAllRead = function(highestItemId) { + /* + sets all items as read + */ + + var params; + + params = { + data: { + highestItemId: highestItemId + } + }; + return this._request.post('news_items_all_read', params); + }; + /* FEED CONTROLLER */ @@ -2803,6 +2847,24 @@ License along with this library. If not, see . return this._request.post('news_folders_rename', params); }; + Persistence.prototype.setFolderRead = function(folderId, highestItemId) { + /* + sets all items of a folder as read + */ + + var params; + + params = { + routeParams: { + folderId: folderId + }, + data: { + highestItemId: highestItemId + } + }; + return this._request.post('news_folders_read', params); + }; + /* EXPORT CONTROLLER */ diff --git a/js/tests/services/businesslayer/feedbusinesslayerSpec.coffee b/js/tests/services/businesslayer/feedbusinesslayerSpec.coffee index 63268224e..a41426922 100644 --- a/js/tests/services/businesslayer/feedbusinesslayerSpec.coffee +++ b/js/tests/services/businesslayer/feedbusinesslayerSpec.coffee @@ -95,7 +95,7 @@ describe 'FeedBusinessLayer', -> it 'should not mark feed read when no highest item id', => @persistence.setFeedRead = jasmine.createSpy('setFeedRead') - @FeedBusinessLayer.markFeedRead(5) + @FeedBusinessLayer.markRead(5) expect(@persistence.setFeedRead).not.toHaveBeenCalled() @@ -107,7 +107,7 @@ describe 'FeedBusinessLayer', -> @ItemModel.add({id: 6, feedId: 5, guidHash: 'a1'}) @ItemModel.add({id: 3, feedId: 5, guidHash: 'a2'}) @ItemModel.add({id: 2, feedId: 5, guidHash: 'a3'}) - @FeedBusinessLayer.markFeedRead(5) + @FeedBusinessLayer.markRead(5) expect(@persistence.setFeedRead).toHaveBeenCalledWith(5, 25) expect(@FeedModel.getById(5).unreadCount).toBe(0) @@ -116,20 +116,6 @@ describe 'FeedBusinessLayer', -> expect(@ItemModel.getById(2).isRead()).toBeTruthy() - it 'should mark all as read', => - @NewestItem.handle(25) - @persistence.setFeedRead = jasmine.createSpy('setFeedRead') - @FeedModel.add({id: 3, unreadCount:134, folderId: 3, url: 'a1'}) - @FeedModel.add({id: 5, unreadCount:2, folderId: 2, url: 'a2'}) - @FeedModel.add({id: 1, unreadCount:12, folderId: 3, url: 'a3'}) - - @FeedBusinessLayer.markAllRead() - - expect(@FeedModel.getById(3).unreadCount).toBe(0) - expect(@FeedModel.getById(1).unreadCount).toBe(0) - expect(@FeedModel.getById(5).unreadCount).toBe(0) - - it 'should get the correct unread count for subscribtions', => @FeedModel.add({id: 3, unreadCount:134, url: 'a1'}) @FeedModel.add({id: 5, unreadCount:2, url: 'a2'}) diff --git a/js/tests/services/businesslayer/folderbusinesslayerSpec.coffee b/js/tests/services/businesslayer/folderbusinesslayerSpec.coffee index 56d90de86..4d23d5b8d 100644 --- a/js/tests/services/businesslayer/folderbusinesslayerSpec.coffee +++ b/js/tests/services/businesslayer/folderbusinesslayerSpec.coffee @@ -46,13 +46,18 @@ describe 'FolderBusinessLayer', -> it 'should delete folders', => + @FeedModel.add({id: 5, unreadCount:2, folderId: 3, url: 'a1'}) @FolderModel.removeById = jasmine.createSpy('remove').andCallFake -> return {id: 3, name: 'test'} + @FeedModel.removeById = jasmine.createSpy('remove').andCallFake -> + return {id: 5, name: 'test', folderId: 3} + @persistence.deleteFolder = jasmine.createSpy('deletequery') @FolderBusinessLayer.delete(3) @$timeout.flush() expect(@FolderModel.removeById).toHaveBeenCalledWith(3) + expect(@FeedModel.removeById).toHaveBeenCalledWith(5) expect(@persistence.deleteFolder).toHaveBeenCalledWith(3) @@ -83,17 +88,21 @@ describe 'FolderBusinessLayer', -> it 'should mark folder as read', => @NewestItem.handle(25) - @persistence.setFeedRead = jasmine.createSpy('setFeedRead') + @FolderModel.add({id: 3, opened: false, name: 'ho'}) + + @persistence.setFolderRead = jasmine.createSpy('setFeedRead') @FeedModel.add({id: 3, unreadCount:134, folderId: 3, url: 'a1'}) @FeedModel.add({id: 5, unreadCount:2, folderId: 2, url: 'a2'}) @FeedModel.add({id: 1, unreadCount:12, folderId: 3, url: 'a3'}) - @FolderBusinessLayer.markFolderRead(3) + @FolderBusinessLayer.markRead(3) expect(@FeedModel.getById(3).unreadCount).toBe(0) expect(@FeedModel.getById(1).unreadCount).toBe(0) expect(@FeedModel.getById(5).unreadCount).toBe(2) + expect(@persistence.setFolderRead).toHaveBeenCalledWith(3, 25) + it 'should get the correct unread count', => @FeedModel.add({id: 5, unreadCount:2, folderId: 2, url: 'a1'}) diff --git a/js/tests/services/businesslayer/subsriptionsbusinesslayerSpec.coffee b/js/tests/services/businesslayer/subsriptionsbusinesslayerSpec.coffee index 6193a9795..9e3437b3c 100644 --- a/js/tests/services/businesslayer/subsriptionsbusinesslayerSpec.coffee +++ b/js/tests/services/businesslayer/subsriptionsbusinesslayerSpec.coffee @@ -68,15 +68,19 @@ describe 'SubscriptionsBusinessLayer', -> expect(@SubscriptionsBusinessLayer.isVisible()).toBe(true) - it 'should mark all feeds as read', => + it 'should mark all as read', => @NewestItem.handle(25) - item = {id: 3, unreadCount: 132, url: 'hi'} - @FeedModel.add(item) + @persistence.setAllRead = jasmine.createSpy('setFeedRead') + @FeedModel.add({id: 3, unreadCount:134, folderId: 3, url: 'a1'}) + @FeedModel.add({id: 5, unreadCount:2, folderId: 2, url: 'a2'}) + @FeedModel.add({id: 1, unreadCount:12, folderId: 3, url: 'a3'}) - @SubscriptionsBusinessLayer.markAllRead() + @SubscriptionsBusinessLayer.markRead() - expect(item.unreadCount).toBe(0) - expect(@persistence.setFeedRead).toHaveBeenCalled() + expect(@FeedModel.getById(3).unreadCount).toBe(0) + expect(@FeedModel.getById(1).unreadCount).toBe(0) + expect(@FeedModel.getById(5).unreadCount).toBe(0) + expect(@persistence.setAllRead).toHaveBeenCalledWith(25) it 'should get the correct unread count', => diff --git a/js/tests/services/persistenceSpec.coffee b/js/tests/services/persistenceSpec.coffee index e42d3bb17..16f8cbd69 100644 --- a/js/tests/services/persistenceSpec.coffee +++ b/js/tests/services/persistenceSpec.coffee @@ -117,6 +117,14 @@ describe 'Persistence', -> expect(@req.post).toHaveBeenCalledWith('news_items_unread', params) + it 'shoud send a correct request for marking all items read', => + params = + data: + highestItemId: 4 + + @Persistence.setAllRead(params.data.highestItemId) + + ### FEED CONTROLLER @@ -153,7 +161,7 @@ describe 'Persistence', -> expect(@req.post).toHaveBeenCalledWith('news_feeds_move', params) - it 'shoud send a correct request for marking all items read', => + it 'shoud send a correct request for marking all items of a feed read', => params = data: highestItemId: 4 @@ -298,6 +306,20 @@ describe 'Persistence', -> expect(@req.post).toHaveBeenCalledWith('news_folders_rename', params) + it 'shoud send a correct request for marking all items of a folders read', => + params = + data: + highestItemId: 4 + routeParams: + folderId: 3 + + @Persistence.setFolderRead(params.routeParams.folderId, + params.data.highestItemId) + + + expect(@req.post).toHaveBeenCalledWith('news_folders_read', params) + + ### EXPORT CONTROLLER ### diff --git a/templates/part.feed.unread.php b/templates/part.feed.unread.php index 96df79af4..a933a2f75 100644 --- a/templates/part.feed.unread.php +++ b/templates/part.feed.unread.php @@ -22,7 +22,7 @@ {{ unreadCountFormatter(getTotalUnreadCount()) }} diff --git a/templates/part.listfeed.php b/templates/part.listfeed.php index 971f0b922..ca49823f6 100644 --- a/templates/part.listfeed.php +++ b/templates/part.listfeed.php @@ -45,7 +45,7 @@ diff --git a/templates/part.listfolder.php b/templates/part.listfolder.php index fb30f1d55..23775f971 100644 --- a/templates/part.listfolder.php +++ b/templates/part.listfolder.php @@ -39,7 +39,7 @@ diff --git a/tests/acceptance/features/support/env.rb b/tests/acceptance/features/support/env.rb index ab2d6b3c6..cef0d2d92 100644 --- a/tests/acceptance/features/support/env.rb +++ b/tests/acceptance/features/support/env.rb @@ -17,8 +17,12 @@ end # host = ENV['HOST'] host ||= '33.33.33.10' + Capybara.app = host Capybara.run_server = false Capybara.app_host = "http://#{host}" Capybara.default_selector = :css Capybara.default_driver = :selenium + +# serve static files +run Rack::Directory.new Dir.pwd.concat('./static') \ No newline at end of file diff --git a/tests/acceptance/run.sh b/tests/acceptance/run.sh index 0cdad3ad3..734504e65 100644 --- a/tests/acceptance/run.sh +++ b/tests/acceptance/run.sh @@ -67,7 +67,7 @@ fi # Set the gemset and ruby version rvm install 2.0.0 -rvm use ruby-2.0.0@oc_acceptance --create +rvm use ruby-2.0.0@oc_news_acceptance --create # install dep libraries bundle install diff --git a/tests/acceptance/static/kernel.org.atom b/tests/acceptance/static/kernel.org.atom new file mode 100644 index 000000000..dd89453ec --- /dev/null +++ b/tests/acceptance/static/kernel.org.atom @@ -0,0 +1,165 @@ + +The Linux Kernel Archives + + +https://www.kernel.org/ +2013-05-07T00:00:00+00:00 + +Fifty shades of Tux + +2013-05-07T00:00:00+00:00 + + + + +tag:https://www.kernel.org,2013-05-07:fifty-shades-of-tux.html + + +

Special thanks to Benoît Monin for donating a MIT-licensed CSS theme to the kernel.org project to replace the one we hastily put together. Though the Pelican authors have since obtained a free-license commitment from the copyright owners of the CSS files shipping with Pelican, we wanted to have something that looked a bit less like the default theme anyway.

If anyone else wants to participate, full sources of the kernel.org website are available from the git repository.

+
+
+ +Frequently asked questions + +2013-04-02T22:13:02+00:00 + + + +tag:https://www.kernel.org,2013-04-02:faq.html + +

If you have questions, comments or concerns about the F.A.Q. please contact us at webmaster@kernel.org.

Is Linux Kernel Free Software?

Linux kernel is released under GNU GPL version 2 and is therefore Free Software as defined by the Free Software Foundation. You may read the entire copy of the license in the COPYING file distributed with each release of the Linux kernel.

There are a number of kernels marked as 'stable', which one is stable?

There are a number of reasons there are multiple kernels marked as 'stable'. The stable series kernels stem from a conversation that happened in 2004, it has evolved into a number of kernels that are currently being maintained under the 'stable' moniker.

These kernels have patches that are backported to them, mainly in the form of driver updates and security fixes. Some of these trees have been declared to have longer life cycles than others.

Please check the Releases page for more info.

What does "stable/EOL" and "longterm" mean?

As kernels move from the "mainline" into the "stable" category, two things can happen:

  1. They can reach "End of Life" after a few bugfix revisions, which means that kernel maintainers will release no more bugfixes for this kernel version, or
  2. They can be put into "longterm" maintenance, which means that maintainers will provide bugfixes for this kernel revision for a much longer period of time.

If the kernel version you are using is marked "EOL," you should consider upgrading to the next major version as there will be no more bugfixes provided for the kernel version you are using.

Please check the Releases page for more info.

Is there an RSS feed for the latest kernel version?

Yes, and you can find it at https://www.kernel.org/feeds/kdist.xml.

We also publish a .json file with the latest release information, which you can pull from here: https://www.kernel.org/releases.json.

Why are there files that are dated tomorrow?

All timestamps on kernel.org are in UTC (Coordinated Universal Time). If you live in the western hemisphere your local time lags behind UTC. Under Linux/Unix, type date -u to get the current time in UTC.

Can I get an account on kernel.org?

Kernel.org accounts are not given away very often, usually you need to be making some reasonable amount of contributions to the Linux kernel and have a good reason for wanting / needing an account. If you really feel that you should have an account please e-mail the following to keys@kernel.org:

  • full name
  • email address
  • desired username
  • reason for account
  • reference to work you've done
  • PGP/GPG public key fingerprint (NOT an ssh key)
    • Key should be signed by as many kernel developers as you can get
    • Accounts will not issued until key is suffciently signed
    • Key must have been uploaded to public key servers

The Kernel.org admin team will then review your request and let you know the decision.

Please note that The Linux Kernel Organization, Inc. reserves the right to refuse service to anyone, for any reason.

I have cool project X, can you guys mirror it for me?

Probably not. Kernel.org deals with the Linux kernel, various distributions of the kernel and larger repositories of packages. We do not mirror individual projects, software, etc as we feel there are better places providing mirrors for those kinds of repositories. If you feel that kernel.org should mirror your project, please contact ftpadmin@kernel.org with the following information:

  • name
  • project name
  • project website
  • detailed project description
  • reason for wanting us to mirror

The Kernel.org admin team will then review your request and talk to you about it. As with any kind of account on kernel.org it's up to the discretion of the admin team.

How does kernel.org provide its users access to the git trees?

We are using an access control system called gitolite, originally written and maintained by Sitaram Chamarty. We choose gitolite for a number of reasons:

  • Limiting of ssh access to the system
  • Fine grained control over repository access
  • Well maintained and supported code base
  • Responsive development
  • Broad and diverse install base

As well at the time of deployment the code had undergone an external code review.

How do I create an -rc kernel? I get "Reversed patch detected!"

-rc kernel patches are generated from the base stable release.

For example: to create the 2.6.14-rc5 kernel, you must:

  • download 2.6.13 (not 2.6.13.4)
  • and then apply the 2.6.14-rc5 patch.

Yes, you want 2.6.13, not 2.6.14. Remember, that's an -rc kernel, as in, 2.6.14 doesn't exist yet. :)

Where can I find kernel 2.4.20-3.16?

Kernel version numbers of this form are distribution kernels, meaning they are modified kernels produced by distributions. Please contact the relevant distributor; or check out http://mirrors.kernel.org/.

See the Releases page for more info on distribution kernels.

I need help building/patching/fixing Linux kernel/modules/drivers!

Please see the Kernel Newbies website.

There is also a wealth of knowledge on many topics involving Linux at The Linux Documentation Project (http://www.tldp.org)

For finding or reporting bugs, look through the archives for the various Linux mailing lists, and if no specific list seems appropriate, try the browsing the Linux Kernel Mailing List.

When will the next kernel be released?

The next kernel will be released when it is ready. There is no strict timeline for making releases, but if you really need an educated guess, visit the Linux kernel PHB Crystal Ball -- it tries to provide a ballpark guess based on previous kernel release schedule.

What will go into the next release?

It is hard to predict with certainty, but you can either take a peek at linux-next or read the Linux Weather Forecast, where Jonathan Corbet provides a broad forecast of what will likely be included into the next mainline release.

+
+
+ +The Linux Kernel Organization + +2013-03-12T19:56:43+00:00 + + + + +tag:https://www.kernel.org,2013-03-12:nonprofit.html + + +

The Linux Kernel Organization is a California Public Benefit Corporation established in 2002 to distribute the Linux kernel and other Open Source software to the public without charge. We are recognized by the IRS as a 501(c)3 private operating foundation.

The Linux Kernel Organization is managed by The Linux Foundation, which provides full technical, financial and staffing support for running and maintaining the kernel.org infrastructure.

+
+
+ +Active kernel releases + +2013-03-12T19:56:43+00:00 + + + + +tag:https://www.kernel.org,2013-03-12:releases.html + + +

There are several main categories into which kernel releases may fall:

Prepatch
Prepatch or "RC" kernels are mainline kernel pre-releases that are mostly aimed at other kernel developers and Linux enthusiasts. They must be compiled from source and usually contain new features that must be tested before they can be put into a stable release. Prepatch kernels are maintained and released by Linus Torvalds.
Mainline
Mainline tree is maintained by Linus Torvalds. It's the tree where all new features are introduced and where all the exciting new development happens. New mainline kernels are released every 2-3 months.
Stable
After each mainline kernel is released, it is considered "stable." Any bug fixes for a stable kernel are backported from the mainline tree and applied by a designated stable kernel maintainer. There are usually only a few bugfix kernel releases until next mainline kernel becomes available -- unless it is designated a "longterm maintenance kernel." Stable kernel updates are released on as-needed basis, usually 2-3 a month.
Longterm
There are usually several "longterm maintenance" kernel releases provided for the purposes of backporting bugfixes for older kernel trees. Only important bugfixes are applied to such kernels and they don't usually see very frequent releases, especially for older trees.
Longterm release kernels
Version Maintainer Projected EOL
3.4 Greg Kroah-Hartman Oct, 2014
3.2 Ben Hutchings 2016
3.0 Greg Kroah-Hartman Oct, 2013
2.6.34 Paul Gortmaker Mid-2013
2.6.32 Willy Tarreau Mid-2014

Distribution kernels

Many Linux distributions provide their own "longterm maintenance" kernels that may or may not be based on those maintained by kernel developers. These kernel releases are not hosted at kernel.org and kernel developers can provide no support for them.

It is easy to tell if you are running a distribution kernel. Unless you downloaded, compiled and installed your own version of kernel from kernel.org, you are running a distribution kernel. To find out the version of your kernel, run uname -r:

 # uname -r 3.7.5-201.fc18.x86_64 

If you see anything at all after the dash, you are running a distribution kernel. Please use the support channels offered by your distribution vendor to obtain kernel support.

+
+
+ +About Linux Kernel + +2013-03-12T19:56:43+00:00 + + + +tag:https://www.kernel.org,2013-03-12:linux.html + +

What is Linux?

Linux is a clone of the operating system Unix, written from scratch by Linus Torvalds with assistance from a loosely-knit team of hackers across the Net. It aims towards POSIX and Single UNIX Specification compliance.

It has all the features you would expect in a modern fully-fledged Unix, including true multitasking, virtual memory, shared libraries, demand loading, shared copy-on-write executables, proper memory management, and multistack networking including IPv4 and IPv6.

Although originally developed first for 32-bit x86-based PCs (386 or higher), today Linux also runs on a multitude of other processor architectures, in both 32- and 64-bit variants.

New to Linux?

If you're new to Linux, you don't want to download the kernel, which is just a component in a working Linux system. Instead, you want what is called a distribution of Linux, which is a complete Linux system. There are numerous distributions available for download on the Internet as well as for purchase from various vendors; some are general-purpose, and some are optimized for specific uses. We currently have mirrors of several distributions available at http://mirrors.kernel.org/.

Note, however, that most distributions are very large (several gigabytes), so unless you have a fast Internet link you may want to save yourself some hassle and purchase a CD-ROM with a distribution; such CD-ROMs are available from a number of vendors.

Mailing lists

The Linux kernel is discussed on the linux-kernel mailing list at vger.kernel.org. Please read the FAQ before subscribing.

Although there is no official archive site, unofficial archives of the list can be found at:

+
+
+ +Contacts + +2013-03-12T19:56:43+00:00 + + + +tag:https://www.kernel.org,2013-03-12:contact.html + +

Email is the only reliable way of contacting Kernel.org administrators.

General contacts

webmaster@kernel.org:
General requests and comments about kernel.org infrastructure.
ftpadmin@kernel.org:
Questions or comments about kernel.org mirrors.
keys@kernel.org:
Account requests (see FAQ)

Please do not send general Linux questions or bug reports to these addresses. We do not have the resources to reply to them.

Please try the following sites for general Linux help:

Linux Foundation also offers training opportunities if you are interested in learning more about Linux, want to become a more proficient Linux systems administrator, or want to know more about how Linux can help your company succeed.

Mailing address

Please send any mail correspondence to the Linux Foundation:

The Linux Foundation
660 York Street, Suite 102
San Francisco, CA 94110
Phone/Fax: +1 415 723 9709
+
+
+ +XZ by default and JSON + +2013-03-11T00:00:00+00:00 + + + + +tag:https://www.kernel.org,2013-03-11:xz-by-default-and-json.html + + +

We've implemented two oft-requested features today:

  1. The download links now default to .tar.xz versions of archives
  2. There is now a JSON file with the release information located in https://www.kernel.org/releases.json. If you've been screen-scraping the front page, please use this instead.

If you have any other feature suggestions, please send them to webmaster@kernel.org.