From 13eed83a10cfb5e2fa67e1039e12f3ccdf91a57d Mon Sep 17 00:00:00 2001 From: Bernhard Posselt Date: Fri, 22 Mar 2013 11:18:16 +0100 Subject: renamed utils into something more accurated --- README.rst | 18 ++-- bl/feedbl.php | 7 +- bl/folderbl.php | 2 + dependencyinjection/dicontainer.php | 15 ++- tests/bl/FeedBlTest.php | 6 +- utility/feedfetcher.php | 187 ++++++++++++++++++++++++++++++++ utility/utils.php | 208 ------------------------------------ 7 files changed, 220 insertions(+), 223 deletions(-) create mode 100644 utility/feedfetcher.php delete mode 100644 utility/utils.php diff --git a/README.rst b/README.rst index 015979834..6c0d26622 100644 --- a/README.rst +++ b/README.rst @@ -1,17 +1,11 @@ README ====== +App is not finished yet and in rewrite -CoffeeScript ------------- -To install the nodejs dependencies run :: +TODO +---- - make deps - -inside the **coffee/** directory. - -To compile and run all unittests run:: - - make - -inside the **coffee/** directory. \ No newline at end of file +* Referential integrity (delete items and feeds when feed or folder with FK was deleted) +* Port coffeescript +* Dont allow multiple feeds with the same name diff --git a/bl/feedbl.php b/bl/feedbl.php index be63862e4..da6c602bf 100644 --- a/bl/feedbl.php +++ b/bl/feedbl.php @@ -27,12 +27,17 @@ namespace OCA\News\Bl; use \OCA\News\Db\Feed; use \OCA\News\Db\FeedMapper; +use \OCA\News\Utility\FeedFetcher; class FeedBl extends Bl { - public function __construct(FeedMapper $feedMapper){ + private $feedFetcher; + + public function __construct(FeedMapper $feedMapper, + FeedFetcher $feedFetcher){ parent::__construct($feedMapper); + $this->feedFetcher = $feedFetcher; } diff --git a/bl/folderbl.php b/bl/folderbl.php index 19c31657c..638f10bd3 100644 --- a/bl/folderbl.php +++ b/bl/folderbl.php @@ -40,6 +40,7 @@ class FolderBl extends Bl { return $this->mapper->findAllFromUser($userId); } + private function allowNoNameTwice($folderName, $userId){ $existingFolders = $this->mapper->findByName($folderName, $userId); if(count($existingFolders) > 0){ @@ -48,6 +49,7 @@ class FolderBl extends Bl { } } + public function create($folderName, $userId, $parentId=0) { $this->allowNoNameTwice($folderName, $userId); diff --git a/dependencyinjection/dicontainer.php b/dependencyinjection/dicontainer.php index 4027f5589..fd6f36dac 100644 --- a/dependencyinjection/dicontainer.php +++ b/dependencyinjection/dicontainer.php @@ -43,6 +43,9 @@ use OCA\News\Db\FeedMapper; use OCA\News\Db\ItemMapper; +require_once __DIR__ . '/../3rdparty/SimplePie/autoloader.php'; + + class DIContainer extends BaseContainer { @@ -90,7 +93,7 @@ class DIContainer extends BaseContainer { }); $this['FeedBl'] = $this->share(function($c){ - return new FeedBl($c['FeedMapper']); + return new FeedBl($c['FeedMapper'], $c['Utils']); }); $this['ItemBl'] = $this->share(function($c){ @@ -112,6 +115,16 @@ class DIContainer extends BaseContainer { $this['ItemMapper'] = $this->share(function($c){ return new ItemMapper($c['API']); }); + + + /** + * Utility + */ + $this['Utils'] = $this->share(function($c){ + return new Utils(); + }); + + } } diff --git a/tests/bl/FeedBlTest.php b/tests/bl/FeedBlTest.php index 444018349..33bf5704c 100644 --- a/tests/bl/FeedBlTest.php +++ b/tests/bl/FeedBlTest.php @@ -38,13 +38,17 @@ class FeedBlTest extends \OCA\AppFramework\Utility\TestUtility { protected $feedBl; protected $user; protected $response; + protected $utils; protected function setUp(){ $this->api = $this->getAPIMock(); $this->feedMapper = $this->getMockBuilder('\OCA\News\Db\FeedMapper') ->disableOriginalConstructor() ->getMock(); - $this->feedBl = new FeedBl($this->feedMapper); + $this->utils = $this->getMockBuilder('\OCA\News\Utility\FeedFetcher') + ->disableOriginalConstructor() + ->getMock(); + $this->feedBl = new FeedBl($this->feedMapper, $this->utils); $this->user = 'jack'; $response = 'hi'; } diff --git a/utility/feedfetcher.php b/utility/feedfetcher.php new file mode 100644 index 000000000..f33f8a82e --- /dev/null +++ b/utility/feedfetcher.php @@ -0,0 +1,187 @@ +. +* +*/ + +namespace OCA\News\Utility; + + +class FeedFetcher { + + + /** + * @brief Fetch a feed from remote + * @param url remote url of the feed + * @returns an instance of OC_News_Feed + */ + public function fetch($url) { + $spfeed = new \SimplePie_Core(); + $spfeed->set_feed_url( $url ); + $spfeed->enable_cache( false ); + + if (!$spfeed->init()) { + return null; + } + + //temporary try-catch to bypass SimplePie bugs + try { + $spfeed->handle_content_type(); + $title = $spfeed->get_title(); + + $items = array(); + if ($spitems = $spfeed->get_items()) { + foreach($spitems as $spitem) { + $itemUrl = $spitem->get_permalink(); + $itemTitle = $spitem->get_title(); + $itemGUID = $spitem->get_id(); + $itemBody = $spitem->get_content(); + $item = new Item($itemUrl, $itemTitle, $itemGUID, $itemBody); + + $spAuthor = $spitem->get_author(); + if ($spAuthor !== null) { + $item->setAuthor($spAuthor->get_name()); + } + + //date in Item is stored in UNIX timestamp format + $itemDate = $spitem->get_date('U'); + $item->setDate($itemDate); + + // associated media file, for podcasts + $itemEnclosure = $spitem->get_enclosure(); + if($itemEnclosure !== null) { + $enclosureType = $itemEnclosure->get_type(); + $enclosureLink = $itemEnclosure->get_link(); + if(stripos($enclosureType, "audio/") !== FALSE) { + $enclosure = new Enclosure(); + $enclosure->setMimeType($enclosureType); + $enclosure->setLink($enclosureLink); + $item->setEnclosure($enclosure); + } + } + + $items[] = $item; + } + } + + $feed = new Feed($url, $title, $items); + + $favicon = $spfeed->get_image_url(); + + if ($favicon !== null && $this->checkFavicon($favicon)) { // use favicon from feed + $feed->setFavicon($favicon); + } + else { // try really hard to find a favicon + $webFavicon = $this->discoverFavicon($url); + if ($webFavicon !== null) { + $feed->setFavicon($webFavicon); + } + } + return $feed; + } + catch (Exception $e) { + return null; + } + } + + /** + * Perform a "slim" fetch of a feed from remote. + * Differently from Utils::fetch(), it doesn't retrieve items nor a favicon + * + * @param url remote url of the feed + * @returns an instance of OC_News_Feed + */ + public function slimFetch($url) { + $spfeed = new \SimplePie_Core(); + $spfeed->set_feed_url( $url ); + $spfeed->enable_cache( false ); + $spfeed->set_stupidly_fast( true ); + + if (!$spfeed->init()) { + return null; + } + + //temporary try-catch to bypass SimplePie bugs + try { + $title = $spfeed->get_title(); + + $feed = new Feed($url, $title); + + return $feed; + } + catch (Exception $e) { + return null; + } + } + + public function checkFavicon($favicon) { + if ($favicon === null || $favicon == false) + return false; + + $file = new \SimplePie_File($favicon); + // size in bytes + $filesize = strlen($file->body); + + if($file->success && $filesize > 0 && $filesize < 50000) { //bigger files are not considered favicons + $sniffer = new \SimplePie_Content_Type_Sniffer($file); + if(substr($sniffer->get_type(), 0, 6) === 'image/') { + $imgsize = getimagesize($favicon); + if ($imgsize['0'] <= 32 && $imgsize['1'] <= 32) { //bigger images are not considered favicons + return true; + } + } + } + return false; + } + + public function discoverFavicon($url) { + //try webroot favicon + $favicon = \SimplePie_Misc::absolutize_url('/favicon.ico', $url); + + if($this->checkFavicon($favicon)) + return $favicon; + + //try to extract favicon from web page + $absoluteUrl = \SimplePie_Misc::absolutize_url('/', $url); + + $handle = curl_init ( ); + curl_setopt ( $handle, CURLOPT_URL, $absoluteUrl ); + curl_setopt ( $handle, CURLOPT_RETURNTRANSFER, 1 ); + curl_setopt ( $handle, CURLOPT_FOLLOWLOCATION, TRUE ); + curl_setopt ( $handle, CURLOPT_MAXREDIRS, 10 ); + + if ( FALSE!==($page=curl_exec($handle)) ) { + preg_match ( '/<[^>]*link[^>]*(rel=["\']icon["\']|rel=["\']shortcut icon["\']) .*href=["\']([^>]*)["\'].*>/iU', $page, $match ); + if (1checkFavicon($favicon)) + return $favicon; + } + } + } + return null; + } +} \ No newline at end of file diff --git a/utility/utils.php b/utility/utils.php deleted file mode 100644 index 560114ca7..000000000 --- a/utility/utils.php +++ /dev/null @@ -1,208 +0,0 @@ - -* -* This file is licensed under the Affero General Public License version 3 or later. -* See the COPYING-README file -* -*/ - -namespace OCA\News; - -// load SimplePie library -//TODO: is this a suitable place for the following require? -require_once 'news/3rdparty/SimplePie/autoloader.php'; - -class Utils { - - /** - * @brief Transform a date from UNIX timestamp format to MDB2 timestamp format - * @param dbtimestamp a date in the UNIX timestamp format - * @returns a date in the MDB2 timestamp format, or NULL if an error occurred - */ - public static function unixtimeToDbtimestamp($unixtime) { - if ($unixtime === null) { - return null; - } - $dt = \DateTime::createFromFormat('U', $unixtime); - if ($dt === false) { - return null; - } - return $dt->format('Y-m-d H:i:s'); - } - - /** - * @brief Transform a date from MDB2 timestamp format to UNIX timestamp format - * @param dbtimestamp a date in the MDB2 timestamp format - * @returns a date in the UNIX timestamp format, or NULL if an error occurred - */ - public static function dbtimestampToUnixtime($dbtimestamp) { - if ($dbtimestamp === null) { - return null; - } - $dt = \DateTime::createFromFormat('Y-m-d H:i:s', $dbtimestamp); - if ($dt === false) { - return null; - } - return $dt->format('U'); - } - - /** - * @brief Fetch a feed from remote - * @param url remote url of the feed - * @returns an instance of OC_News_Feed - */ - public static function fetch($url) { - $spfeed = new \SimplePie_Core(); - $spfeed->set_feed_url( $url ); - $spfeed->enable_cache( false ); - - if (!$spfeed->init()) { - return null; - } - - //temporary try-catch to bypass SimplePie bugs - try { - $spfeed->handle_content_type(); - $title = $spfeed->get_title(); - - $items = array(); - if ($spitems = $spfeed->get_items()) { - foreach($spitems as $spitem) { - $itemUrl = $spitem->get_permalink(); - $itemTitle = $spitem->get_title(); - $itemGUID = $spitem->get_id(); - $itemBody = $spitem->get_content(); - $item = new Item($itemUrl, $itemTitle, $itemGUID, $itemBody); - - $spAuthor = $spitem->get_author(); - if ($spAuthor !== null) { - $item->setAuthor($spAuthor->get_name()); - } - - //date in Item is stored in UNIX timestamp format - $itemDate = $spitem->get_date('U'); - $item->setDate($itemDate); - - // associated media file, for podcasts - $itemEnclosure = $spitem->get_enclosure(); - if($itemEnclosure !== null) { - $enclosureType = $itemEnclosure->get_type(); - $enclosureLink = $itemEnclosure->get_link(); - if(stripos($enclosureType, "audio/") !== FALSE) { - $enclosure = new Enclosure(); - $enclosure->setMimeType($enclosureType); - $enclosure->setLink($enclosureLink); - $item->setEnclosure($enclosure); - } - } - - $items[] = $item; - } - } - - $feed = new Feed($url, $title, $items); - - $favicon = $spfeed->get_image_url(); - - if ($favicon !== null && self::checkFavicon($favicon)) { // use favicon from feed - $feed->setFavicon($favicon); - } - else { // try really hard to find a favicon - $webFavicon = self::discoverFavicon($url); - if ($webFavicon !== null) { - $feed->setFavicon($webFavicon); - } - } - return $feed; - } - catch (Exception $e) { - return null; - } - } - - /** - * Perform a "slim" fetch of a feed from remote. - * Differently from Utils::fetch(), it doesn't retrieve items nor a favicon - * - * @param url remote url of the feed - * @returns an instance of OC_News_Feed - */ - public static function slimFetch($url) { - $spfeed = new \SimplePie_Core(); - $spfeed->set_feed_url( $url ); - $spfeed->enable_cache( false ); - $spfeed->set_stupidly_fast( true ); - - if (!$spfeed->init()) { - return null; - } - - //temporary try-catch to bypass SimplePie bugs - try { - $title = $spfeed->get_title(); - - $feed = new Feed($url, $title); - - return $feed; - } - catch (Exception $e) { - return null; - } - } - - public static function checkFavicon($favicon) { - if ($favicon === null || $favicon == false) - return false; - - $file = new \SimplePie_File($favicon); - // size in bytes - $filesize = strlen($file->body); - - if($file->success && $filesize > 0 && $filesize < 50000) { //bigger files are not considered favicons - $sniffer = new \SimplePie_Content_Type_Sniffer($file); - if(substr($sniffer->get_type(), 0, 6) === 'image/') { - $imgsize = getimagesize($favicon); - if ($imgsize['0'] <= 32 && $imgsize['1'] <= 32) { //bigger images are not considered favicons - return true; - } - } - } - return false; - } - - public static function discoverFavicon($url) { - //try webroot favicon - $favicon = \SimplePie_Misc::absolutize_url('/favicon.ico', $url); - - if(self::checkFavicon($favicon)) - return $favicon; - - //try to extract favicon from web page - $absoluteUrl = \SimplePie_Misc::absolutize_url('/', $url); - - $handle = curl_init ( ); - curl_setopt ( $handle, CURLOPT_URL, $absoluteUrl ); - curl_setopt ( $handle, CURLOPT_RETURNTRANSFER, 1 ); - curl_setopt ( $handle, CURLOPT_FOLLOWLOCATION, TRUE ); - curl_setopt ( $handle, CURLOPT_MAXREDIRS, 10 ); - - if ( FALSE!==($page=curl_exec($handle)) ) { - preg_match ( '/<[^>]*link[^>]*(rel=["\']icon["\']|rel=["\']shortcut icon["\']) .*href=["\']([^>]*)["\'].*>/iU', $page, $match ); - if (1