diff options
-rw-r--r-- | bl/feedbl.php | 2 | ||||
-rw-r--r-- | controller/exportcontroller.php | 21 | ||||
-rw-r--r-- | controller/feedcontroller.php | 2 | ||||
-rw-r--r-- | css/feeds.css | 2 | ||||
-rw-r--r-- | css/settings.css | 7 | ||||
-rw-r--r-- | dependencyinjection/dicontainer.php | 10 | ||||
-rw-r--r-- | js/app/controllers/controllers.coffee | 8 | ||||
-rw-r--r-- | js/app/controllers/settingscontroller.coffee | 15 | ||||
-rw-r--r-- | js/app/services/opmlparser.coffee | 2 | ||||
-rw-r--r-- | js/public/app.js | 35 | ||||
-rw-r--r-- | templates/main.php | 13 | ||||
-rw-r--r-- | templates/part.settings.php | 52 | ||||
-rw-r--r-- | tests/unit/bl/FeedBlTest.php | 4 | ||||
-rw-r--r-- | tests/unit/controller/ExportControllerTest.php | 45 | ||||
-rw-r--r-- | tests/unit/controller/FeedControllerTest.php | 2 | ||||
-rw-r--r-- | utility/opmlexporter.php | 120 |
16 files changed, 190 insertions, 150 deletions
diff --git a/bl/feedbl.php b/bl/feedbl.php index b70d95342..97deaeff0 100644 --- a/bl/feedbl.php +++ b/bl/feedbl.php @@ -49,7 +49,7 @@ class FeedBl extends Bl { } - public function findAllFromUser($userId){ + public function findAll($userId){ return $this->mapper->findAllFromUser($userId); } diff --git a/controller/exportcontroller.php b/controller/exportcontroller.php index 013626938..960748d3e 100644 --- a/controller/exportcontroller.php +++ b/controller/exportcontroller.php @@ -28,23 +28,38 @@ namespace OCA\News\Controller; use \OCA\AppFramework\Controller\Controller; use \OCA\AppFramework\Core\API; use \OCA\AppFramework\Http\Request; +use \OCA\AppFramework\Http\TextDownloadResponse; +use \OCA\News\Bl\FeedBl; +use \OCA\News\Bl\FolderBl; +use \OCA\News\Utility\OPMLExporter; class ExportController extends Controller { + private $opmlExporter; + private $folderBl; + private $feedBl; - public function __construct(API $api, Request $request){ + public function __construct(API $api, Request $request, FeedBl $feedBl, + FolderBl $folderBl, OPMLExporter $opmlExporter){ parent::__construct($api, $request); + $this->feedBl = $feedBl; + $this->folderBl = $folderBl; + $this->opmlExporter = $opmlExporter; } /** * @IsAdminExemption * @IsSubAdminExemption - * @Ajax + * @CSRFExemption */ public function opml(){ - // TODO + $user = $this->api->getUserId(); + $feeds = $this->feedBl->findAll($user); + $folders = $this->folderBl->findAll($user); + $opml = $this->opmlExporter->build($folders, $feeds)->saveXML(); + return new TextDownloadResponse($opml, 'subscriptions.opml', 'text/xml'); } diff --git a/controller/feedcontroller.php b/controller/feedcontroller.php index c542ea1d8..5e2a91f24 100644 --- a/controller/feedcontroller.php +++ b/controller/feedcontroller.php @@ -55,7 +55,7 @@ class FeedController extends Controller { */ public function feeds(){ $userId = $this->api->getUserId(); - $result = $this->feedBl->findAllFromUser($userId); + $result = $this->feedBl->findAll($userId); $params = array( 'feeds' => $result diff --git a/css/feeds.css b/css/feeds.css index f2667b326..d8b8481ce 100644 --- a/css/feeds.css +++ b/css/feeds.css @@ -96,7 +96,7 @@ button.action:hover { } .mark-read-icon { - background-image: url('%appswebroot%/news/img/mark_read.svg') !important; + background-image: url('%appswebroot%/news/img/mark_read.svg'); } .rss-icon { diff --git a/css/settings.css b/css/settings.css index 972659a3a..8adec8885 100644 --- a/css/settings.css +++ b/css/settings.css @@ -9,13 +9,6 @@ background-color: transparent !important; } -.opml-icon { - background-image: url('%appswebroot%/news/img/opml-icon.svg'); - background-repeat: no-repeat; - background-position: 5px center; - padding-left: 28px; - padding-right: 10px; -} #app-settings-content { padding-bottom: 25px; diff --git a/dependencyinjection/dicontainer.php b/dependencyinjection/dicontainer.php index e26e57f4d..c2d4b44e4 100644 --- a/dependencyinjection/dicontainer.php +++ b/dependencyinjection/dicontainer.php @@ -46,6 +46,7 @@ use OCA\News\Db\StatusFlag; use OCA\News\Utility\Fetcher; use OCA\News\Utility\FeedFetcher; use OCA\News\Utility\TwitterFetcher; +use OCA\News\Utility\OPMLExporter; require_once __DIR__ . '/../3rdparty/SimplePie/autoloader.php'; @@ -90,8 +91,8 @@ class DIContainer extends BaseContainer { }); $this['ExportController'] = $this->share(function($c){ - return new ExportController($c['API'], $c['Request'], - $c['FolderBl'], $c['FeedBl']); + return new ExportController($c['API'], $c['Request'], $c['FeedBl'], + $c['FolderBl'], $c['OPMLExporter']); }); $this['UserSettingsController'] = $this->share(function($c){ @@ -161,6 +162,11 @@ class DIContainer extends BaseContainer { return new StatusFlag(); }); + $this['OPMLExporter'] = $this->share(function($c){ + return new OPMLExporter(); + }); + + } } diff --git a/js/app/controllers/controllers.coffee b/js/app/controllers/controllers.coffee index 02d5f5e6c..8a73549cf 100644 --- a/js/app/controllers/controllers.coffee +++ b/js/app/controllers/controllers.coffee @@ -20,14 +20,6 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>. ### -angular.module('News').controller 'SettingsController', -['$scope', '_SettingsController', -($scope, _SettingsController)-> - - return new _SettingsController($scope) -] - - angular.module('News').controller 'FeedController', ['$scope', '_FeedController', 'Persistence', 'FolderBl', 'FeedBl', 'SubscriptionsBl', 'StarredBl', 'unreadCountFormatter', diff --git a/js/app/controllers/settingscontroller.coffee b/js/app/controllers/settingscontroller.coffee index ec94b843c..07cf7360a 100644 --- a/js/app/controllers/settingscontroller.coffee +++ b/js/app/controllers/settingscontroller.coffee @@ -21,15 +21,12 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>. ### -angular.module('News').factory '_SettingsController', -> +angular.module('News').controller 'SettingsController', +['$scope', 'FeedBl', ($scope, FeedBl) -> - class SettingsController + $scope.import = (fileContent) -> + console.log fileContent - constructor: (@$scope) -> + $scope.feedBl = FeedBl - @$scope.import = (fileContent) => - console.log 'hi' - console.log fileContent - - - return SettingsController
\ No newline at end of file +]
\ No newline at end of file diff --git a/js/app/services/opmlparser.coffee b/js/app/services/opmlparser.coffee index 5154e423c..9586cbaf2 100644 --- a/js/app/services/opmlparser.coffee +++ b/js/app/services/opmlparser.coffee @@ -66,7 +66,7 @@ angular.module('News').factory '_OPMLParser', -> _recursivelyParse: ($xml, structure) -> for outline in $xml.children('outline') $outline = $(outline) - if angular.isDefined($outline.attr('type')) + if angular.isDefined($outline.attr('xmlUrl')) feed = new Feed($outline.attr('text'), $outline.attr('xmlUrl')) structure.add(feed) else diff --git a/js/public/app.js b/js/public/app.js index e11c2e976..741188cb4 100644 --- a/js/public/app.js +++ b/js/public/app.js @@ -217,12 +217,6 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>. (function() { - angular.module('News').controller('SettingsController', [ - '$scope', '_SettingsController', function($scope, _SettingsController) { - return new _SettingsController($scope); - } - ]); - angular.module('News').controller('FeedController', [ '$scope', '_FeedController', 'Persistence', 'FolderBl', 'FeedBl', 'SubscriptionsBl', 'StarredBl', 'unreadCountFormatter', function($scope, _FeedController, Persistence, FolderBl, FeedBl, SubscriptionsBl, StarredBl, unreadCountFormatter) { return new _FeedController($scope, Persistence, FolderBl, FeedBl, SubscriptionsBl, StarredBl, unreadCountFormatter); @@ -460,25 +454,14 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>. (function() { - angular.module('News').factory('_SettingsController', function() { - var SettingsController; - - SettingsController = (function() { - function SettingsController($scope) { - var _this = this; - - this.$scope = $scope; - this.$scope["import"] = function(fileContent) { - console.log('hi'); - return console.log(fileContent); - }; - } - - return SettingsController; - - })(); - return SettingsController; - }); + angular.module('News').controller('SettingsController', [ + '$scope', 'FeedBl', function($scope, FeedBl) { + $scope["import"] = function(fileContent) { + return console.log(fileContent); + }; + return $scope.feedBl = FeedBl; + } + ]); }).call(this); @@ -1966,7 +1949,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>. for (_i = 0, _len = _ref.length; _i < _len; _i++) { outline = _ref[_i]; $outline = $(outline); - if (angular.isDefined($outline.attr('type'))) { + if (angular.isDefined($outline.attr('xmlUrl'))) { feed = new Feed($outline.attr('text'), $outline.attr('xmlUrl')); _results.push(structure.add(feed)); } else { diff --git a/templates/main.php b/templates/main.php index f70ade37f..e6c964c74 100644 --- a/templates/main.php +++ b/templates/main.php @@ -30,18 +30,7 @@ </ul> <div id="app-settings" ng-controller="SettingsController"> - <div id="app-settings-header"> - <button name="app settings" - class="settings-button" - oc-click-slide-toggle="{ - selector: '#app-settings-content', - hideOnFocusLost: true, - cssClass: 'opened' - }"></button> - </div> - <div id="app-settings-content"> - <?php print_unescaped($this->inc('part.settings')) ?> - </div> + <?php print_unescaped($this->inc('part.settings')) ?> </div> </div> diff --git a/templates/part.settings.php b/templates/part.settings.php index 436a575eb..263e4b3a8 100644 --- a/templates/part.settings.php +++ b/templates/part.settings.php @@ -1,20 +1,32 @@ -<fieldset class="personalblock"> - <legend><strong><?php p($l->t('Import / Export OPML')); ?></strong></legend> - <input type="file" id="opml-upload" name="import" - oc-read-file="import($fileContent)"/> - <button title="<?php p($l->t('Import')); ?>" - oc-forward-click="{selector:'#opml-upload'}" - class="opml-icon"> - <?php p($l->t('Import')); ?> - </button> - <button ng-disabled="feeds.length==0" title="<?php p($l->t('Export')); ?>" - ng-click="export()" - class="opml-icon"> - <?php p($l->t('Export')); ?> - </button> -</fieldset> -<fieldset class="personalblock"> - <legend><strong><?php p($l->t('Subscribelet')); ?></strong></legend> - <p><?php print_unescaped($this->inc('part.subscribelet'));?> - </p> -</fieldset> +<div id="app-settings-header"> +<button name="app settings" + class="settings-button" + oc-click-slide-toggle="{ + selector: '#app-settings-content', + hideOnFocusLost: true, + cssClass: 'opened' + }"></button> +</div> + +<div id="app-settings-content"> + <fieldset class="personalblock"> + <legend><strong><?php p($l->t('Import / Export OPML')); ?></strong></legend> + <input type="file" id="opml-upload" name="import" + oc-read-file="import($fileContent)"/> + <button title="<?php p($l->t('Import')); ?>" + oc-forward-click="{selector:'#opml-upload'}"> + <?php p($l->t('Import')); ?> + </button> + <a title="<?php p($l->t('Export')); ?>" class="button" + href="<?php p(\OCP\Util::linkToRoute('news_export_opml')); ?>" + target="_blank" + ng-show="feedBl.getNumberOfFeeds() > 0"> + <?php p($l->t('Export')); ?> + </a> + </fieldset> + <fieldset class="personalblock"> + <legend><strong><?php p($l->t('Subscribelet')); ?></strong></legend> + <p><?php print_unescaped($this->inc('part.subscribelet'));?> + </p> + </fieldset> +</div>
\ No newline at end of file diff --git a/tests/unit/bl/FeedBlTest.php b/tests/unit/bl/FeedBlTest.php index 0fadf2c24..a5ce1c624 100644 --- a/tests/unit/bl/FeedBlTest.php +++ b/tests/unit/bl/FeedBlTest.php @@ -64,13 +64,13 @@ class FeedBlTest extends \OCA\AppFramework\Utility\TestUtility { } - public function testFindAllFromUser(){ + public function testFindAll(){ $this->mapper->expects($this->once()) ->method('findAllFromUser') ->with($this->equalTo($this->user)) ->will($this->returnValue($this->response)); - $result = $this->bl->findAllFromUser($this->user); + $result = $this->bl->findAll($this->user); $this->assertEquals($this->response, $result); } diff --git a/tests/unit/controller/ExportControllerTest.php b/tests/unit/controller/ExportControllerTest.php index 913b091c6..b835e585a 100644 --- a/tests/unit/controller/ExportControllerTest.php +++ b/tests/unit/controller/ExportControllerTest.php @@ -26,11 +26,12 @@ namespace OCA\News\Controller; use \OCA\AppFramework\Http\Request; -use \OCA\AppFramework\Http\JSONResponse; +use \OCA\AppFramework\Http\TextDownloadResponse; use \OCA\AppFramework\Utility\ControllerTestUtility; use \OCA\AppFramework\Db\DoesNotExistException; use \OCA\AppFramework\Db\MultipleObjectsReturnedException; +use \OCA\News\Utility\OPMLExporter; require_once(__DIR__ . "/../../classloader.php"); @@ -40,22 +41,58 @@ class ExportControllerTest extends ControllerTestUtility { private $api; private $request; private $controller; - + private $user; + private $feedBl; + private $folderBl; + private $opmlExporter; /** * Gets run before each test */ public function setUp(){ $this->api = $this->getAPIMock(); + $this->feedBl = $this->getMockBuilder('\OCA\News\Bl\FeedBl') + ->disableOriginalConstructor() + ->getMock(); + $this->folderBl = $this->getMockBuilder('\OCA\News\Bl\FolderBl') + ->disableOriginalConstructor() + ->getMock(); $this->request = new Request(); - $this->controller = new ExportController($this->api, $this->request); + $this->opmlExporter = new OPMLExporter(); + $this->controller = new ExportController($this->api, $this->request, + $this->feedBl, $this->folderBl, $this->opmlExporter); + $this->user = 'john'; } public function testOpmlAnnotations(){ - $annotations = array('IsAdminExemption', 'IsSubAdminExemption', 'Ajax'); + $annotations = array('IsAdminExemption', 'IsSubAdminExemption', + 'CSRFExemption'); $this->assertAnnotations($this->controller, 'opml', $annotations); } + public function testOpmlExportNoFeeds(){ + $this->api->expects($this->once()) + ->method('getUserId') + ->will($this->returnValue($this->user)); + $this->feedBl->expects($this->once()) + ->method('findAll') + ->with($this->equalTo($this->user)) + ->will($this->returnValue(array())); + $this->folderBl->expects($this->once()) + ->method('findAll') + ->with($this->equalTo($this->user)) + ->will($this->returnValue(array())); + + $return = $this->controller->opml(); + $this->assertTrue($return instanceof TextDownloadResponse); + + // TODO: check if its empty xml structure + } + + + // TODO more tests for this + + }
\ No newline at end of file diff --git a/tests/unit/controller/FeedControllerTest.php b/tests/unit/controller/FeedControllerTest.php index e3dc60a28..e7c7c29e3 100644 --- a/tests/unit/controller/FeedControllerTest.php +++ b/tests/unit/controller/FeedControllerTest.php @@ -122,7 +122,7 @@ class FeedControllerTest extends ControllerTestUtility { ->method('getUserId') ->will($this->returnValue($this->user)); $this->bl->expects($this->once()) - ->method('findAllFromUser') + ->method('findAll') ->with($this->equalTo($this->user)) ->will($this->returnValue($result['feeds'])); diff --git a/utility/opmlexporter.php b/utility/opmlexporter.php index d9d404ff1..630b2aba8 100644 --- a/utility/opmlexporter.php +++ b/utility/opmlexporter.php @@ -1,82 +1,98 @@ <?php /** -* ownCloud - News app +* ownCloud - News * * @author Alessandro Cosentino -* Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com> +* @author Bernhard Posselt +* @copyright 2012 Alessandro Cosentino cosenal@gmail.com +* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com * -* This file is licensed under the Affero General Public License version 3 or later. -* See the COPYING-README file +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. If not, see <http://www.gnu.org/licenses/>. * */ -namespace OCA\News; +namespace OCA\News\Utility; /** * Exports the OPML */ class OPMLExporter { - private $api; - private $trans; - - public function __construct($api){ - $this->api = $api; - $this->trans = $api->getTrans(); - } - - /** * Generates the OPML for the active user * @return the OPML as string */ - public function buildOPML($feeds){ - $dom = new \DomDocument('1.0', 'UTF-8'); - $dom->formatOutput = true; - - $opml_el = $dom->createElement('opml'); - $opml_el->setAttribute('version', '2.0'); - - $head_el = $dom->createElement('head'); + public function build($folders, $feeds){ + $document = new \DomDocument('1.0', 'UTF-8'); + $document->formatOutput = true; + + $root = $document->createElement('opml'); + $root->setAttribute('version', '2.0'); + + // head + $head = $document->createElement('head'); + + $title = $document->createElement('title', 'Subscriptions'); + $head->appendChild( $title ); + + $root->appendChild($head); + + // body + $body = $document->createElement('body'); + + // feeds with folders + foreach($folders as $folder) { + $folderOutline = $document->createElement('outline'); + $folderOutline->setAttribute('title', $folder->getName()); + $folderOutline->setAttribute('text', $folder->getName()); + + // feeds in folders + foreach ($feeds as $feed) { + if ($feed->getFolderId() === $folder->getId()) { + $feedOutline = $this->createFeedOutline($feed, $document); + $folderOutline->appendChild($feedOutline); + } + } - $title = $this->api->getUserId() . ' ' . - $this->trans->t('subscriptions in ownCloud - News'); - $title_el = $dom->createElement('title', $title); + $body->appendChild($folderOutline); + } - $head_el->appendChild( $title_el ); - $opml_el->appendChild( $head_el ); - $body_el = $dom->createElement('body'); + // feeds without folders + foreach ($feeds as $feed) { + if ($feed->getFolderId() === 0) { + $feedOutline = $this->createFeedOutline($feed, $document); + $body->appendChild($feedOutline); + } + } - $this->feedsToXML($feeds, $body_el, $dom); + $root->appendChild($body); - $opml_el->appendChild( $body_el ); - $dom->appendChild( $opml_el ); + $document->appendChild($root); - return $dom->saveXML(); + return $document; } - /** - * Creates the OPML content recursively - */ - protected function feedsToXML($data, $xml_el, $dom) { - - foreach($data as $collection) { - $outline_el = $dom->createElement('outline'); - if ($collection instanceOf Folder) { - $outline_el->setAttribute('title', $collection->getName()); - $outline_el->setAttribute('text', $collection->getName()); - $this->feedsToXML($collection->getChildren(), $outline_el, $dom); - } - elseif ($collection instanceOf Feed) { - $outline_el->setAttribute('title', $collection->getTitle()); - $outline_el->setAttribute('text', $collection->getTitle()); - $outline_el->setAttribute('type', 'rss'); - $outline_el->setAttribute('xmlUrl', $collection->getUrl()); - } - $xml_el->appendChild( $outline_el ); - } + protected function createFeedOutline($feed, $document) { + $feedOutline = $document->createElement('outline'); + $feedOutline->setAttribute('title', $feed->getTitle()); + $feedOutline->setAttribute('text', $feed->getTitle()); + $feedOutline->setAttribute('type', 'rss'); + $feedOutline->setAttribute('xmlUrl', $feed->getUrl()); + $feedOutline->setAttribute('htmlUrl', $feed->getLink()); + return $feedOutline; } |