summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorBernhard Posselt <dev@bernhard-posselt.com>2016-07-23 21:24:54 +0200
committerBernhard Posselt <dev@bernhard-posselt.com>2016-07-23 21:24:54 +0200
commit004fcbbcc7609ca83807f2e38967ef54f469bf72 (patch)
tree49eb99b4ea92b2045793fc567f719b31ec7f9042 /lib
parent60abc0ed4438c9b6fda245b0dc33cb483bc2aeaf (diff)
Move to new directory structure
Diffstat (limited to 'lib')
-rw-r--r--lib/AppInfo/Application.php246
-rw-r--r--lib/Command/Updater/AfterUpdate.php40
-rw-r--r--lib/Command/Updater/AllFeeds.php53
-rw-r--r--lib/Command/Updater/BeforeUpdate.php41
-rw-r--r--lib/Command/Updater/UpdateFeed.php59
-rw-r--r--lib/Config/AppConfig.php137
-rw-r--r--lib/Config/Config.php181
-rw-r--r--lib/Config/DependencyException.php28
-rw-r--r--lib/Controller/AdminController.php88
-rw-r--r--lib/Controller/ApiController.php37
-rw-r--r--lib/Controller/EntityApiSerializer.php68
-rw-r--r--lib/Controller/ExportController.php91
-rw-r--r--lib/Controller/FeedApiController.php224
-rw-r--r--lib/Controller/FeedController.php301
-rw-r--r--lib/Controller/FolderApiController.php139
-rw-r--r--lib/Controller/FolderController.php176
-rw-r--r--lib/Controller/ItemApiController.php245
-rw-r--r--lib/Controller/ItemController.php218
-rw-r--r--lib/Controller/JSONHttpError.php31
-rw-r--r--lib/Controller/PageController.php224
-rw-r--r--lib/Controller/UserApiController.php72
-rw-r--r--lib/Controller/UtilityApiController.php83
-rw-r--r--lib/Cron/Updater.php39
-rw-r--r--lib/Db/EntityJSONSerializer.php28
-rw-r--r--lib/Db/Feed.php189
-rw-r--r--lib/Db/FeedMapper.php166
-rw-r--r--lib/Db/FeedType.php24
-rw-r--r--lib/Db/Folder.php73
-rw-r--r--lib/Db/FolderMapper.php110
-rw-r--r--lib/Db/IAPI.php18
-rw-r--r--lib/Db/Item.php256
-rw-r--r--lib/Db/ItemMapper.php403
-rw-r--r--lib/Db/MapperFactory.php47
-rw-r--r--lib/Db/Mysql/ItemMapper.php88
-rw-r--r--lib/Db/NewsMapper.php93
-rw-r--r--lib/Db/StatusFlag.php47
-rw-r--r--lib/DependencyInjection/IFactory.php24
-rw-r--r--lib/Explore/RecommendedSiteNotFoundException.php20
-rw-r--r--lib/Explore/RecommendedSites.php42
-rw-r--r--lib/Explore/feeds/feeds.de.json65
-rw-r--r--lib/Explore/feeds/feeds.en.json166
-rw-r--r--lib/Fetcher/FeedFetcher.php302
-rw-r--r--lib/Fetcher/Fetcher.php69
-rw-r--r--lib/Fetcher/FetcherException.php26
-rw-r--r--lib/Fetcher/IFeedFetcher.php48
-rw-r--r--lib/Fetcher/YoutubeFetcher.php82
-rw-r--r--lib/Hooks/User.php35
-rw-r--r--lib/Http/TextDownloadResponse.php49
-rw-r--r--lib/Http/TextResponse.php46
-rw-r--r--lib/Plugin/Client/Plugin.php44
-rw-r--r--lib/Service/FeedService.php454
-rw-r--r--lib/Service/FolderService.php178
-rw-r--r--lib/Service/ItemService.php259
-rw-r--r--lib/Service/Service.php62
-rw-r--r--lib/Service/ServiceConflictException.php27
-rw-r--r--lib/Service/ServiceException.php27
-rw-r--r--lib/Service/ServiceNotFoundException.php27
-rw-r--r--lib/Service/ServiceValidationException.php27
-rw-r--r--lib/Service/StatusService.php57
-rw-r--r--lib/Upgrade/Upgrade.php71
-rw-r--r--lib/Utility/OPMLExporter.php91
-rw-r--r--lib/Utility/PicoFeedClientFactory.php40
-rw-r--r--lib/Utility/PicoFeedFaviconFactory.php38
-rw-r--r--lib/Utility/ProxyConfigParser.php65
-rw-r--r--lib/Utility/Time.php30
-rw-r--r--lib/Utility/Updater.php54
66 files changed, 6888 insertions, 0 deletions
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php
new file mode 100644
index 000000000..5b403efac
--- /dev/null
+++ b/lib/AppInfo/Application.php
@@ -0,0 +1,246 @@
+<?php
+/**
+ * ownCloud - News
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Alessandro Cosentino <cosenal@gmail.com>
+ * @author Bernhard Posselt <dev@bernhard-posselt.com>
+ * @copyright Alessandro Cosentino 2012
+ * @copyright Bernhard Posselt 2012, 2014
+ */
+
+namespace OCA\News\AppInfo;
+
+use HTMLPurifier;
+use HTMLPurifier_Config;
+
+use PicoFeed\Config\Config as PicoFeedConfig;
+use PicoFeed\Reader\Reader as PicoFeedReader;
+
+use OCP\ILogger;
+use OCP\INavigationManager;
+use OCP\IURLGenerator;
+use OCP\IConfig;
+use OCP\IDBConnection;
+use OCP\AppFramework\App;
+use OCP\Files\IRootFolder;
+
+use OCA\News\Config\AppConfig;
+use OCA\News\Config\Config;
+use OCA\News\Service\FeedService;
+use OCA\News\Db\MapperFactory;
+use OCA\News\Db\ItemMapper;
+use OCA\News\Fetcher\Fetcher;
+use OCA\News\Fetcher\FeedFetcher;
+use OCA\News\Fetcher\YoutubeFetcher;
+use OCA\News\Explore\RecommendedSites;
+use OCA\News\Utility\ProxyConfigParser;
+
+
+class Application extends App {
+
+ public function __construct(array $urlParams=[]) {
+ parent::__construct('news', $urlParams);
+
+ // files
+ $this->registerFileContents('checksums', 'checksum.json');
+ $this->registerFileContents('info', '../../appinfo/info.xml');
+
+ // parameters
+ $this->registerParameter('exploreDir', '../Explore/feeds');
+ $this->registerParameter('configFile', 'config.ini');
+
+ // factories
+ $this->registerFactory(ItemMapper::class, MapperFactory::class);
+
+
+ /**
+ * App config parser
+ */
+ /** @noinspection PhpParamsInspection */
+ $this->registerService(AppConfig::class, function($c) {
+ $config = new AppConfig(
+ $c->query(INavigationManager::class),
+ $c->query(IURLGenerator::class)
+ );
+
+ $config->loadConfig($c->query('info'));
+
+ return $config;
+ });
+
+ /**
+ * Core
+ */
+ /** @noinspection PhpParamsInspection */
+ $this->registerService('LoggerParameters', function($c) {
+ return ['app' => $c->query('AppName')];
+ });
+
+ /** @noinspection PhpParamsInspection */
+ $this->registerService('databaseType', function($c) {
+ return $c->query(IConfig::class)->getSystemValue('dbtype');
+ });
+
+ /** @noinspection PhpParamsInspection */
+ $this->registerService('ConfigView', function($c) {
+ $fs = $c->query(IRootFolder::class);
+ $path = 'news/config';
+ if ($fs->nodeExists($path)) {
+ return $fs->get($path);
+ } else {
+ return $fs->newFolder($path);
+ }
+ });
+
+
+ /** @noinspection PhpParamsInspection */
+ $this->registerService(Config::class, function($c) {
+ $config = new Config(
+ $c->query('ConfigView'),
+ $c->query(ILogger::class),
+ $c->query('LoggerParameters')
+ );
+ $config->read($c->query('configFile'), true);
+ return $config;
+ });
+
+ /** @noinspection PhpParamsInspection */
+ $this->registerService(HTMLPurifier::class, function($c) {
+ $directory = $c->query(IConfig::class)
+ ->getSystemValue('datadirectory') . '/news/cache/purifier';
+
+ if(!is_dir($directory)) {
+ mkdir($directory, 0770, true);
+ }
+
+ $config = HTMLPurifier_Config::createDefault();
+ $config->set('HTML.ForbiddenAttributes', 'class');
+ $config->set('Cache.SerializerPath', $directory);
+ $config->set('HTML.SafeIframe', true);
+ $config->set('URI.SafeIframeRegexp',
+ '%^https://(?:www\.)?(' .
+ 'youtube(?:-nocookie)?.com/embed/|' .
+ 'player.vimeo.com/video/|' .
+ 'vk.com/video_ext.php)%'); //allow YouTube and Vimeo
+ $def = $config->getHTMLDefinition(true);
+ $def->addAttribute('iframe', 'allowfullscreen', 'Bool');
+ return new HTMLPurifier($config);
+ });
+
+ /**
+ * Fetchers
+ */
+ /** @noinspection PhpParamsInspection */
+ $this->registerService(PicoFeedConfig::class, function($c) {
+ // FIXME: move this into a separate class for testing?
+ $config = $c->query(Config::class);
+ $proxy = $c->query(ProxyConfigParser::class);
+
+ // use chrome's user agent string since mod_security rules
+ // assume that only browsers can send user agent strings. This
+ // can lead to blocked feed updates like joomla.org
+ // For more information see
+ // https://www.atomicorp.com/wiki/index.php/WAF_309925
+ $userAgent = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36' .
+ '(KHTML, like Gecko) Chrome/50.0.2661.75 Safari/537.36';
+
+ $pico = new PicoFeedConfig();
+ $pico->setClientUserAgent($userAgent)
+ ->setClientTimeout($config->getFeedFetcherTimeout())
+ ->setMaxRedirections($config->getMaxRedirects())
+ ->setMaxBodySize($config->getMaxSize())
+ ->setParserHashAlgo('md5');
+
+ // proxy settings
+ $proxySettings = $proxy->parse();
+ $host = $proxySettings['host'];
+ $port = $proxySettings['port'];
+ $user = $proxySettings['user'];
+ $password = $proxySettings['password'];
+
+ if ($host) {
+ $pico->setProxyHostname($host);
+
+ if ($port) {
+ $pico->setProxyPort($port);
+ }
+ }
+
+ if ($user) {
+ $pico->setProxyUsername($user)
+ ->setProxyPassword($password);
+ }
+
+ return $pico;
+ });
+
+ /** @noinspection PhpParamsInspection */
+ $this->registerService(Fetcher::class, function($c) {
+ $fetcher = new Fetcher();
+
+ // register fetchers in order, the most generic fetcher should be
+ // the last one
+ $fetcher->registerFetcher($c->query(YoutubeFetcher::class));
+ $fetcher->registerFetcher($c->query(FeedFetcher::class));
+
+ return $fetcher;
+ });
+
+
+ }
+
+ /**
+ * Registers the content of a file under a key
+ * @param string $key
+ * @param string $file path relative to this file, __DIR__ will be prepended
+ */
+ private function registerFileContents($key, $file) {
+ /** @noinspection PhpParamsInspection */
+ $this->registerService($key, function () use ($file) {
+ return file_get_contents(__DIR__ . '/' . $file);
+ });
+ }
+
+ /**
+ * Shortcut for registering a service
+ * @param string $key
+ * @param closure $factory
+ * @param boolean $shared
+ */
+ private function registerService($key, $factory, $shared=true) {
+ $this->getContainer()->registerService($key, $factory, $shared);
+ }
+
+ /**
+ * Shortcut for registering a parameter
+ * @param string $key
+ * @param mixed $value
+ */
+ private function registerParameter($key, $value) {
+ $this->getContainer()->registerParameter($key, $value);
+ }
+
+ /**
+ * Register a class containing the app construction logic instead of the
+ * inlining everything in this class to enhance testability
+ * @param string $key fully qualified class name
+ * @param string $factory fully qualified factory class name
+ */
+ private function registerFactory($key, $factory) {
+ /** @noinspection PhpParamsInspection */
+ $this->registerService($key, function ($c) use ($factory) {
+ return $c->query($factory)->build();
+ });
+ }
+
+ /**
+ * Register the additional config parameters found in the info.xml
+ */
+ public function registerConfig() {
+ $this->getContainer()->query(AppConfig::class)->registerAll();
+ }
+
+}
diff --git a/lib/Command/Updater/AfterUpdate.php b/lib/Command/Updater/AfterUpdate.php
new file mode 100644
index 000000000..36e23b477
--- /dev/null
+++ b/lib/Command/Updater/AfterUpdate.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * ownCloud - News
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Bernhard Posselt <dev@bernhard-posselt.com>
+ * @copyright Bernhard Posselt 2016
+ */
+
+namespace OCA\News\Command\Updater;
+
+use Exception;
+
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+use \OCA\News\Utility\Updater;
+
+class AfterUpdate extends Command {
+ private $updater;
+
+ public function __construct(Updater $updater) {
+ parent::__construct();
+ $this->updater = $updater;
+ }
+
+ protected function configure() {
+ $this->setName('news:updater:after-update')
+ ->setDescription('This is used to clean up the database. It ' .
+ 'removes old read articles which are not starred');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $this->updater->afterUpdate();
+ }
+
+}
diff --git a/lib/Command/Updater/AllFeeds.php b/lib/Command/Updater/AllFeeds.php
new file mode 100644
index 000000000..05330ac01
--- /dev/null
+++ b/lib/Command/Updater/AllFeeds.php
@@ -0,0 +1,53 @@
+<?php
+/**
+ * ownCloud - News
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Bernhard Posselt <dev@bernhard-posselt.com>
+ * @copyright Bernhard Posselt 2016
+ */
+
+namespace OCA\News\Command\Updater;
+
+use Exception;
+
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+use OCA\News\Service\FeedService;
+
+
+class AllFeeds extends Command {
+ private $feedService;
+
+ public function __construct(FeedService $feedService) {
+ parent::__construct();
+ $this->feedService = $feedService;
+ }
+
+ protected function configure() {
+ $json = '{"feeds": [{"id": 39, "userId": "john"}, // etc ]}';
+
+ $this->setName('news:updater:all-feeds')
+ ->setDescription('Prints a JSON string which contains all feed ' .
+ 'ids and user ids, e.g.: ' . $json);
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $feeds = $this->feedService->findAllFromAllUsers();
+ $result = ['feeds' => []];
+
+ foreach ($feeds as $feed) {
+ $result['feeds'][] = [
+ 'id' => $feed->getId(),
+ 'userId' => $feed->getUserId()
+ ];
+ }
+
+ print(json_encode($result));
+ }
+
+}
diff --git a/lib/Command/Updater/BeforeUpdate.php b/lib/Command/Updater/BeforeUpdate.php
new file mode 100644
index 000000000..6af0a5c3a
--- /dev/null
+++ b/lib/Command/Updater/BeforeUpdate.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * ownCloud - News
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Bernhard Posselt <dev@bernhard-posselt.com>
+ * @copyright Bernhard Posselt 2016
+ */
+
+namespace OCA\News\Command\Updater;
+
+use Exception;
+
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+use \OCA\News\Utility\Updater;
+
+class BeforeUpdate extends Command {
+ private $updater;
+
+ public function __construct(Updater $updater) {
+ parent::__construct();
+ $this->updater = $updater;
+ }
+
+ protected function configure() {
+ $this->setName('news:updater:before-update')
+ ->setDescription('This is used to clean up the database. It ' .
+ 'deletes folders and feeds that are marked for ' .
+ 'deletion');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $this->updater->beforeUpdate();
+ }
+
+}
diff --git a/lib/Command/Updater/UpdateFeed.php b/lib/Command/Updater/UpdateFeed.php
new file mode 100644
index 000000000..13fc2e625
--- /dev/null
+++ b/lib/Command/Updater/UpdateFeed.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * ownCloud - News
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Bernhard Posselt <dev@bernhard-posselt.com>
+ * @copyright Bernhard Posselt 2016
+ */
+
+namespace OCA\News\Command\Updater;
+
+use Exception;
+
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+use OCA\News\Service\FeedService;
+
+
+class UpdateFeed extends Command {
+ private $feedService;
+
+ public function __construct(FeedService $feedService) {
+ parent::__construct();
+ $this->feedService = $feedService;
+ }
+
+ protected function configure() {
+ $this->setName('news:updater:update-feed')
+ ->addArgument(
+ 'feed-id',
+ InputArgument::REQUIRED,
+ 'feed id, integer'
+ )
+ ->addArgument(
+ 'user-id',
+ InputArgument::REQUIRED,
+ 'user id of a user, string'
+ )
+ ->setDescription('Console API for updating a single user\'s feed');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ $feedId = $input->getArgument('feed-id');
+ $userId = $input->getArgument('user-id');
+ try {
+ $this->feedService->update($feedId, $userId);
+ } catch (Exception $e) {
+ $output->writeln('<error>Could not update feed with id ' . $feedId .
+ ' and user ' . $userId . ': ' . $e->getMessage() .
+ '</error> ');
+ }
+ }
+
+}
diff --git a/lib/Config/AppConfig.php b/lib/Config/AppConfig.php
new file mode 100644
index 000000000..55dcd6d1a
--- /dev/null
+++ b/lib/Config/AppConfig.php
@@ -0,0 +1,137 @@
+<?php
+/**
+ * ownCloud - News
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Alessandro Cosentino <cosenal@gmail.com>
+ * @author Bernhard Posselt <dev@bernhard-posselt.com>
+ * @copyright Alessandro Cosentino 2012
+ * @copyright Bernhard Posselt 2012, 2014
+ */
+
+namespace OCA\News\Config;
+
+use SimpleXMLElement;
+
+use OCP\INavigationManager;
+use OCP\IURLGenerator;
+use OCP\Util;
+use OCP\App;
+
+// Used to parse app.json file, should be in core at some point
+class AppConfig {
+
+ private $config;
+ private $navigationManager;
+ private $urlGenerator;
+
+ /**
+ * TODO: External deps that are needed:
+ * - add jobs
+ * - connect to hooks
+ */
+ public function __construct(INavigationManager $navigationManager,
+ IURLGenerator $urlGenerator) {
+ $this->navigationManager = $navigationManager;
+ $this->urlGenerator = $urlGenerator;