├── .gitattributes ├── .gitignore ├── .travis.yml ├── COPYING ├── README.md ├── pom.xml ├── reader-agent ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── sismics │ │ ├── reader │ │ └── agent │ │ │ ├── ReaderAgent.java │ │ │ ├── deployer │ │ │ ├── DeploymentStatus.java │ │ │ ├── DeploymentStatusListener.java │ │ │ └── ReaderDeployer.java │ │ │ ├── model │ │ │ └── Setting.java │ │ │ └── ui │ │ │ ├── AgentFrame.java │ │ │ ├── SettingPanel.java │ │ │ ├── StatusPanel.java │ │ │ └── TrayController.java │ │ └── util │ │ ├── EnvironmentUtil.java │ │ └── MessageUtil.java │ └── resources │ ├── images │ ├── reader-started-16.png │ └── reader-stopped-16.png │ ├── messages.properties │ └── messages_fr.properties ├── reader-android ├── .gitignore ├── app │ ├── .gitignore │ ├── build.gradle │ ├── libs │ │ ├── android-query.0.26.7.jar │ │ └── drag-sort-listview-0.6.1-SNAPSHOT-AAR.aar │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── com │ │ │ └── sismics │ │ │ ├── android │ │ │ ├── Log.java │ │ │ └── util │ │ │ │ └── DialogUtil.java │ │ │ ├── parallaxscroll │ │ │ ├── ParallaxScrollView.java │ │ │ └── ParallaxedView.java │ │ │ └── reader │ │ │ ├── MainApplication.java │ │ │ ├── activity │ │ │ ├── ArticleActivity.java │ │ │ ├── CategoriesActivity.java │ │ │ ├── LicenseActivity.java │ │ │ ├── LoginActivity.java │ │ │ ├── MainActivity.java │ │ │ └── SettingsActivity.java │ │ │ ├── constant │ │ │ └── Constants.java │ │ │ ├── fragment │ │ │ ├── AddSubscriptionDialogFragment.java │ │ │ ├── ArticleFragment.java │ │ │ ├── ArticlesDefaultFragment.java │ │ │ ├── ArticlesFragment.java │ │ │ ├── NavigationFragment.java │ │ │ └── SettingsFragment.java │ │ │ ├── listener │ │ │ ├── ArticlesHelperListener.java │ │ │ └── CallbackListener.java │ │ │ ├── model │ │ │ └── application │ │ │ │ └── ApplicationContext.java │ │ │ ├── provider │ │ │ └── RecentSuggestionsProvider.java │ │ │ ├── resource │ │ │ ├── ArticleResource.java │ │ │ ├── BaseResource.java │ │ │ ├── CategoryResource.java │ │ │ ├── StarredResource.java │ │ │ ├── SubscriptionResource.java │ │ │ └── UserResource.java │ │ │ ├── ui │ │ │ ├── adapter │ │ │ │ ├── ArticlesAdapter.java │ │ │ │ ├── ArticlesPagerAdapter.java │ │ │ │ ├── CategoryAdapter.java │ │ │ │ ├── SharedArticlesAdapterHelper.java │ │ │ │ ├── SubscriptionAdapter.java │ │ │ │ └── SubscriptionItem.java │ │ │ ├── form │ │ │ │ ├── Validable.java │ │ │ │ ├── Validator.java │ │ │ │ └── validator │ │ │ │ │ ├── Alphanumeric.java │ │ │ │ │ ├── Email.java │ │ │ │ │ ├── Length.java │ │ │ │ │ ├── Required.java │ │ │ │ │ └── ValidatorType.java │ │ │ └── widget │ │ │ │ ├── ArticleScrollView.java │ │ │ │ └── ArticlesSwipeRefreshLayout.java │ │ │ └── util │ │ │ ├── ApplicationUtil.java │ │ │ └── PreferenceUtil.java │ │ └── res │ │ ├── anim │ │ └── rssman.xml │ │ ├── drawable-hdpi │ │ ├── character.png │ │ ├── character_happy.png │ │ ├── character_sad.png │ │ ├── ic_action_about.png │ │ ├── ic_action_accept.png │ │ ├── ic_action_collection.png │ │ ├── ic_action_collection_inverse.png │ │ ├── ic_action_collection_new.png │ │ ├── ic_action_important.png │ │ ├── ic_action_important_inverse.png │ │ ├── ic_action_new_inverse.png │ │ ├── ic_action_not_important.png │ │ ├── ic_action_not_important_inverse.png │ │ ├── ic_action_read.png │ │ ├── ic_action_read_inverse.png │ │ ├── ic_action_settings.png │ │ ├── ic_action_share_inverse.png │ │ ├── ic_action_sort_by_size.png │ │ ├── ic_action_unread.png │ │ ├── ic_action_unread_inverse.png │ │ ├── ic_drag.9.png │ │ ├── ic_menu_moreoverflow_card_inverse_normal.png │ │ ├── ic_menu_moreoverflow_card_inverse_pressed.png │ │ ├── list_activated_holo.9.png │ │ └── list_background_holo.9.png │ │ ├── drawable-sw600dp-hdpi │ │ ├── list_activated_holo.9.png │ │ └── list_background_holo.9.png │ │ ├── drawable-sw600dp-xhdpi │ │ ├── list_activated_holo.9.png │ │ └── list_background_holo.9.png │ │ ├── drawable-xhdpi │ │ ├── character.png │ │ ├── character_happy.png │ │ ├── character_sad.png │ │ ├── ic_action_about.png │ │ ├── ic_action_accept.png │ │ ├── ic_action_collection.png │ │ ├── ic_action_collection_inverse.png │ │ ├── ic_action_collection_new.png │ │ ├── ic_action_important.png │ │ ├── ic_action_important_inverse.png │ │ ├── ic_action_new_inverse.png │ │ ├── ic_action_not_important.png │ │ ├── ic_action_not_important_inverse.png │ │ ├── ic_action_read.png │ │ ├── ic_action_read_inverse.png │ │ ├── ic_action_settings.png │ │ ├── ic_action_share_inverse.png │ │ ├── ic_action_sort_by_size.png │ │ ├── ic_action_unread.png │ │ ├── ic_action_unread_inverse.png │ │ ├── ic_drag.9.png │ │ ├── ic_launcher.png │ │ ├── ic_menu_moreoverflow_card_inverse_normal.png │ │ ├── ic_menu_moreoverflow_card_inverse_pressed.png │ │ ├── list_activated_holo.9.png │ │ └── list_background_holo.9.png │ │ ├── drawable-xxhdpi │ │ └── ic_launcher.png │ │ ├── drawable-xxxhdpi │ │ └── ic_launcher.png │ │ ├── drawable │ │ ├── article_title_background.xml │ │ ├── drawer_list_item_collection.xml │ │ ├── drawer_list_item_important.xml │ │ ├── drawer_list_item_read.xml │ │ ├── drawer_list_item_text_color.xml │ │ ├── drawer_list_item_unread.xml │ │ ├── list_item_activated_background.xml │ │ └── overflow_menu.xml │ │ ├── layout-sw600dp │ │ ├── article_activity.xml │ │ ├── article_item.xml │ │ └── main_activity.xml │ │ ├── layout │ │ ├── actionbar_indeterminate_progress.xml │ │ ├── add_subscription_dialog_fragment.xml │ │ ├── article_activity.xml │ │ ├── article_fragment.xml │ │ ├── article_item.xml │ │ ├── articles_fragment.xml │ │ ├── categories_activity.xml │ │ ├── drawer_list_item_category.xml │ │ ├── drawer_list_item_header.xml │ │ ├── drawer_list_item_subscription.xml │ │ ├── license_activity.xml │ │ ├── login_activity.xml │ │ ├── main_activity.xml │ │ └── manage_list_item_category.xml │ │ ├── menu │ │ ├── article_activity.xml │ │ ├── categories_activity.xml │ │ ├── category_overflow_menu.xml │ │ ├── context_articles.xml │ │ └── main.xml │ │ ├── values-de │ │ ├── arrays.xml │ │ └── strings.xml │ │ ├── values-sw600dp │ │ └── dimens.xml │ │ ├── values-w720dp │ │ └── dimens.xml │ │ ├── values │ │ ├── arrays.xml │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ │ └── xml │ │ ├── preferences.xml │ │ └── searchable.xml ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── lint.xml └── settings.gradle ├── reader-core ├── pom.xml └── src │ ├── demo │ └── resources │ │ └── db │ │ └── update │ │ └── dbupdate-000-2.sql │ ├── dev │ └── resources │ │ └── db │ │ └── update │ │ ├── dbupdate-000-1-web.sql │ │ └── dbupdate-000-2-test.sql │ ├── main │ ├── java │ │ └── com │ │ │ └── sismics │ │ │ ├── reader │ │ │ └── core │ │ │ │ ├── constant │ │ │ │ ├── ConfigType.java │ │ │ │ └── Constants.java │ │ │ │ ├── dao │ │ │ │ ├── file │ │ │ │ │ ├── html │ │ │ │ │ │ ├── FaviconDownloader.java │ │ │ │ │ │ ├── FaviconExtractor.java │ │ │ │ │ │ ├── FeedChooserStrategy.java │ │ │ │ │ │ └── RssExtractor.java │ │ │ │ │ ├── json │ │ │ │ │ │ ├── StarredArticleImportedEvent.java │ │ │ │ │ │ ├── StarredArticleImportedListener.java │ │ │ │ │ │ └── StarredReader.java │ │ │ │ │ ├── opml │ │ │ │ │ │ ├── OpmlFlattener.java │ │ │ │ │ │ ├── OpmlReader.java │ │ │ │ │ │ └── Outline.java │ │ │ │ │ └── rss │ │ │ │ │ │ ├── AtomArticleCommentUrlGuesserStrategy.java │ │ │ │ │ │ ├── AtomArticleUrlGuesserStrategy.java │ │ │ │ │ │ ├── AtomLink.java │ │ │ │ │ │ ├── AtomUrlGuesserStrategy.java │ │ │ │ │ │ ├── GuidFixer.java │ │ │ │ │ │ ├── RssReader.java │ │ │ │ │ │ └── XmlReader.java │ │ │ │ ├── jpa │ │ │ │ │ ├── ArticleDao.java │ │ │ │ │ ├── AuthenticationTokenDao.java │ │ │ │ │ ├── CategoryDao.java │ │ │ │ │ ├── ConfigDao.java │ │ │ │ │ ├── FeedDao.java │ │ │ │ │ ├── FeedSubscriptionDao.java │ │ │ │ │ ├── FeedSynchronizationDao.java │ │ │ │ │ ├── JobDao.java │ │ │ │ │ ├── JobEventDao.java │ │ │ │ │ ├── LocaleDao.java │ │ │ │ │ ├── RoleBaseFunctionDao.java │ │ │ │ │ ├── UserArticleDao.java │ │ │ │ │ ├── UserDao.java │ │ │ │ │ ├── criteria │ │ │ │ │ │ ├── ArticleCriteria.java │ │ │ │ │ │ ├── FeedCriteria.java │ │ │ │ │ │ ├── FeedSubscriptionCriteria.java │ │ │ │ │ │ ├── JobCriteria.java │ │ │ │ │ │ ├── JobEventCriteria.java │ │ │ │ │ │ ├── UserArticleCriteria.java │ │ │ │ │ │ └── UserCriteria.java │ │ │ │ │ ├── dto │ │ │ │ │ │ ├── ArticleDto.java │ │ │ │ │ │ ├── FeedDto.java │ │ │ │ │ │ ├── FeedSubscriptionDto.java │ │ │ │ │ │ ├── JobDto.java │ │ │ │ │ │ ├── JobEventDto.java │ │ │ │ │ │ ├── UserArticleDto.java │ │ │ │ │ │ └── UserDto.java │ │ │ │ │ └── mapper │ │ │ │ │ │ ├── ArticleMapper.java │ │ │ │ │ │ ├── FeedMapper.java │ │ │ │ │ │ ├── FeedSubscriptionMapper.java │ │ │ │ │ │ ├── JobEventMapper.java │ │ │ │ │ │ ├── JobMapper.java │ │ │ │ │ │ ├── UserArticleMapper.java │ │ │ │ │ │ └── UserMapper.java │ │ │ │ └── lucene │ │ │ │ │ ├── ArticleDao.java │ │ │ │ │ └── ReaderStandardAnalyzer.java │ │ │ │ ├── event │ │ │ │ ├── ArticleCreatedAsyncEvent.java │ │ │ │ ├── ArticleDeletedAsyncEvent.java │ │ │ │ ├── ArticleUpdatedAsyncEvent.java │ │ │ │ ├── FaviconUpdateRequestedEvent.java │ │ │ │ ├── PasswordChangedEvent.java │ │ │ │ ├── RebuildIndexAsyncEvent.java │ │ │ │ ├── SubscriptionImportedEvent.java │ │ │ │ └── UserCreatedEvent.java │ │ │ │ ├── listener │ │ │ │ ├── async │ │ │ │ │ ├── ArticleCreatedAsyncListener.java │ │ │ │ │ ├── ArticleDeletedAsyncListener.java │ │ │ │ │ ├── ArticleUpdatedAsyncListener.java │ │ │ │ │ ├── FaviconUpdateRequestedAsyncListener.java │ │ │ │ │ ├── RebuildIndexAsyncListener.java │ │ │ │ │ └── SubscriptionImportAsyncListener.java │ │ │ │ └── sync │ │ │ │ │ └── DeadEventListener.java │ │ │ │ ├── model │ │ │ │ ├── context │ │ │ │ │ └── AppContext.java │ │ │ │ └── jpa │ │ │ │ │ ├── Article.java │ │ │ │ │ ├── AuthenticationToken.java │ │ │ │ │ ├── BaseFunction.java │ │ │ │ │ ├── Category.java │ │ │ │ │ ├── Config.java │ │ │ │ │ ├── Feed.java │ │ │ │ │ ├── FeedSubscription.java │ │ │ │ │ ├── FeedSynchronization.java │ │ │ │ │ ├── Job.java │ │ │ │ │ ├── JobEvent.java │ │ │ │ │ ├── Locale.java │ │ │ │ │ ├── Role.java │ │ │ │ │ ├── RoleBaseFunction.java │ │ │ │ │ ├── User.java │ │ │ │ │ └── UserArticle.java │ │ │ │ ├── service │ │ │ │ ├── FeedService.java │ │ │ │ └── IndexingService.java │ │ │ │ └── util │ │ │ │ ├── ConfigUtil.java │ │ │ │ ├── DirectoryUtil.java │ │ │ │ ├── EntityManagerUtil.java │ │ │ │ ├── LuceneUtil.java │ │ │ │ ├── StreamUtil.java │ │ │ │ ├── TransactionUtil.java │ │ │ │ ├── UserUtil.java │ │ │ │ ├── http │ │ │ │ └── ReaderHttpClient.java │ │ │ │ ├── jpa │ │ │ │ ├── PaginatedList.java │ │ │ │ ├── PaginatedLists.java │ │ │ │ └── SortCriteria.java │ │ │ │ └── sanitizer │ │ │ │ ├── ArticleSanitizer.java │ │ │ │ └── TextSanitizer.java │ │ │ └── util │ │ │ ├── AdblockUtil.java │ │ │ ├── DateUtil.java │ │ │ ├── EnvironmentUtil.java │ │ │ ├── HttpUtil.java │ │ │ ├── JsonValidationUtil.java │ │ │ ├── LocaleUtil.java │ │ │ ├── MessageUtil.java │ │ │ ├── NetworkUtil.java │ │ │ ├── ResourceUtil.java │ │ │ ├── UrlUtil.java │ │ │ ├── adblock │ │ │ ├── Helper.java │ │ │ ├── JSEngine.java │ │ │ ├── Subscription.java │ │ │ └── SubscriptionParser.java │ │ │ ├── cert │ │ │ ├── CertUtil.java │ │ │ └── TrustAllManager.java │ │ │ ├── context │ │ │ └── ThreadLocalContext.java │ │ │ ├── jpa │ │ │ ├── BaseDao.java │ │ │ ├── DbOpenHelper.java │ │ │ ├── DialectUtil.java │ │ │ ├── EMF.java │ │ │ ├── ManagedProvidedConnectionHelper.java │ │ │ ├── QueryParam.java │ │ │ ├── ResultMapper.java │ │ │ ├── SessionUtil.java │ │ │ ├── SuppliedConnectionProviderConnectionHelper.java │ │ │ └── filter │ │ │ │ ├── FilterColumn.java │ │ │ │ └── FilterCriteria.java │ │ │ ├── log4j │ │ │ ├── LogCriteria.java │ │ │ ├── LogEntry.java │ │ │ └── MemoryAppender.java │ │ │ └── mime │ │ │ ├── MimeType.java │ │ │ └── MimeTypeUtil.java │ └── resources │ │ ├── META-INF │ │ └── persistence.xml │ │ ├── adblock │ │ ├── js │ │ │ ├── ElemHide.jsm │ │ │ ├── FilterClasses.jsm │ │ │ ├── FilterListener.jsm │ │ │ ├── FilterNotifier.jsm │ │ │ ├── FilterStorage.jsm │ │ │ ├── Matcher.jsm │ │ │ ├── SubscriptionClasses.jsm │ │ │ ├── Synchronizer.jsm │ │ │ ├── XMLHttpRequest.jsm │ │ │ ├── basedomain.js │ │ │ ├── publicSuffixList.js │ │ │ ├── punycode.js │ │ │ └── start.js │ │ └── subscriptions.xml │ │ ├── db │ │ └── update │ │ │ ├── dbupdate-000-0.sql │ │ │ ├── dbupdate-001-0.sql │ │ │ ├── dbupdate-002-0.sql │ │ │ ├── dbupdate-003-0.sql │ │ │ ├── dbupdate-004-0.sql │ │ │ ├── dbupdate-005-0.sql │ │ │ └── dbupdate-006-0.sql │ │ ├── messages.properties │ │ └── messages_fr.properties │ └── test │ ├── java │ └── com │ │ └── sismics │ │ ├── reader │ │ ├── BaseTransactionalTest.java │ │ └── core │ │ │ └── dao │ │ │ ├── file │ │ │ ├── html │ │ │ │ ├── TestFaviconDownloader.java │ │ │ │ ├── TestFaviconExtractor.java │ │ │ │ └── TestRssExtractor.java │ │ │ ├── json │ │ │ │ └── TestStarredReader.java │ │ │ ├── opml │ │ │ │ └── TestOpmlReader.java │ │ │ └── rss │ │ │ │ └── TestRssReader.java │ │ │ └── jpa │ │ │ └── TestJpa.java │ │ └── util │ │ ├── TestAdblockUtil.java │ │ ├── TestArticleSanitizer.java │ │ ├── TestCertUtil.java │ │ ├── TestDateUtil.java │ │ ├── TestNetworkUtil.java │ │ ├── TestResourceUtil.java │ │ ├── TestTextSanitizer.java │ │ └── TestUrlUtil.java │ └── resources │ ├── config.properties │ ├── feed │ ├── feed_atom_akewea.xml │ ├── feed_atom_github_user.xml │ ├── feed_atom_haverbeke.xml │ ├── feed_atom_makiko.xml │ ├── feed_atom_marijnhaverbeke.xml │ ├── feed_atom_ploum.xml │ ├── feed_atom_whatif.xml │ ├── feed_atom_whatif2.xml │ ├── feed_atom_xkcd.xml │ ├── feed_error_lemessager.html │ ├── feed_error_toomanyfatalerror.html │ ├── feed_rdf_autostrip.xml │ ├── feed_rdf_lxer.xml │ ├── feed_rdf_meisalam.xml │ ├── feed_rdf_oatmeal.xml │ ├── feed_rss2_apod.xml │ ├── feed_rss2_bysme.xml │ ├── feed_rss2_cultiz.xml │ ├── feed_rss2_developerworks.xml │ ├── feed_rss2_developpez.xml │ ├── feed_rss2_dilbert.xml │ ├── feed_rss2_distractionware.xml │ ├── feed_rss2_distractionware2.xml │ ├── feed_rss2_esa.xml │ ├── feed_rss2_fubiz.xml │ ├── feed_rss2_gizmodo.gzip │ ├── feed_rss2_ibox.xml │ ├── feed_rss2_korben.xml │ ├── feed_rss2_lemessager.xml │ ├── feed_rss2_maliki.xml │ ├── feed_rss2_nasa.xml │ ├── feed_rss2_nova.xml │ ├── feed_rss2_ploum.xml │ ├── feed_rss2_rottentomatoes.xml │ ├── feed_rss2_slackware.xml │ ├── feed_rss2_slashdot.xml │ ├── feed_rss2_space.xml │ ├── feed_rss2_spacedaily.xml │ └── feed_rss2_xkcd.xml │ ├── google_takeout │ └── starred.json │ ├── hibernate.properties │ ├── log4j.properties │ ├── lucene │ ├── korben_data.xml │ └── techcrunch_data.xml │ ├── opml │ ├── greader_subscriptions.xml │ ├── liferea_subscriptions.xml │ └── ttrss_subscriptions.xml │ └── page │ ├── korben.html │ ├── makiko-f.blogspot.fr.html │ ├── ploum.html │ ├── space.html │ └── xkcd.html ├── reader-distribution-debian ├── pom.xml └── src │ └── main │ ├── deb │ └── control │ │ ├── conffiles │ │ ├── control │ │ ├── postinst │ │ ├── postrm │ │ ├── preinst │ │ └── prerm │ └── package │ ├── etc │ ├── default │ │ └── reader │ └── init.d │ │ └── reader │ └── usr │ └── share │ └── doc │ └── reader │ ├── README │ └── copyright ├── reader-distribution-docker ├── Dockerfile └── docker-compose.yml ├── reader-distribution-mac ├── pom.xml └── src │ └── main │ └── osxappbundle │ ├── JavaApplicationStub │ └── reader-512.icns ├── reader-distribution-redhat ├── pom.xml └── src │ └── main │ ├── package │ └── etc │ │ ├── init.d │ │ └── reader │ │ └── sysconfig │ │ └── reader │ └── rpm │ └── script │ ├── postinstall │ ├── preinstall │ └── preremove ├── reader-distribution-standalone ├── pom.xml └── src │ └── main │ ├── assembly │ ├── dist.xml │ ├── reader.bat │ └── reader.sh │ └── java │ └── com │ └── sismics │ └── reader │ └── Standalone.java ├── reader-distribution-windows ├── pom.xml └── src │ └── main │ ├── launch4j │ ├── LICENSE.txt │ ├── reader-16.ico │ ├── reader-agent-elevated.manifest │ ├── reader-agent-elevated.xml │ ├── reader-agent.properties │ └── reader-agent.xml │ └── nsis │ ├── jre-7u21-windows-i586.exe │ └── reader.nsi ├── reader-web-common ├── pom.xml └── src │ ├── main │ └── java │ │ └── com │ │ └── sismics │ │ ├── rest │ │ ├── exception │ │ │ ├── ClientException.java │ │ │ ├── ForbiddenClientException.java │ │ │ └── ServerException.java │ │ ├── resource │ │ │ └── GenericExceptionMapper.java │ │ └── util │ │ │ ├── JsonUtil.java │ │ │ └── ValidationUtil.java │ │ ├── security │ │ ├── AnonymousPrincipal.java │ │ ├── IPrincipal.java │ │ └── UserPrincipal.java │ │ └── util │ │ └── filter │ │ ├── HeaderBasedSecurityFilter.java │ │ ├── RequestContextFilter.java │ │ ├── SecurityFilter.java │ │ └── TokenBasedSecurityFilter.java │ └── test │ └── java │ └── com │ └── sismics │ └── reader │ └── rest │ ├── BaseJerseyTest.java │ ├── descriptor │ └── JerseyTestWebAppDescriptorFactory.java │ ├── filter │ └── CookieAuthenticationFilter.java │ └── util │ └── TestValidationUtil.java ├── reader-web ├── pom.xml └── src │ ├── dev │ ├── main │ │ └── webapp │ │ │ └── web-override.xml │ └── resources │ │ ├── hibernate.properties │ │ └── log4j.properties │ ├── hosted │ └── resources │ │ ├── hibernate.properties │ │ └── log4j.properties │ ├── main │ ├── java │ │ └── com │ │ │ └── sismics │ │ │ └── reader │ │ │ └── rest │ │ │ ├── assembler │ │ │ └── ArticleAssembler.java │ │ │ ├── constant │ │ │ └── BaseFunction.java │ │ │ ├── dao │ │ │ └── ThemeDao.java │ │ │ ├── resource │ │ │ ├── AllResource.java │ │ │ ├── AppResource.java │ │ │ ├── ArticleResource.java │ │ │ ├── BaseResource.java │ │ │ ├── CategoryResource.java │ │ │ ├── JobResource.java │ │ │ ├── LocaleResource.java │ │ │ ├── SearchResource.java │ │ │ ├── StarredResource.java │ │ │ ├── SubscriptionResource.java │ │ │ ├── TextPlainMessageBodyWriter.java │ │ │ ├── ThemeResource.java │ │ │ └── UserResource.java │ │ │ └── util │ │ │ └── ValidationUtil.java │ ├── resources │ │ ├── config.properties │ │ └── image │ │ │ └── subscription.png │ └── webapp │ │ ├── .gitignore │ │ ├── Gruntfile.js │ │ ├── WEB-INF │ │ └── web.xml │ │ ├── package.json │ │ └── src │ │ ├── favicon.png │ │ ├── images │ │ ├── ajax-loader.gif │ │ ├── category.png │ │ ├── category_add.png │ │ ├── edit.png │ │ ├── error.png │ │ ├── external.png │ │ ├── full.png │ │ ├── jqueryui │ │ │ ├── animated-overlay.gif │ │ │ ├── ui-bg_flat_0_aaaaaa_40x100.png │ │ │ ├── ui-bg_flat_75_ffffff_40x100.png │ │ │ ├── ui-bg_glass_55_fbf9ee_1x400.png │ │ │ ├── ui-bg_glass_65_ffffff_1x400.png │ │ │ ├── ui-bg_glass_75_dadada_1x400.png │ │ │ ├── ui-bg_glass_75_e6e6e6_1x400.png │ │ │ ├── ui-bg_glass_95_fef1ec_1x400.png │ │ │ ├── ui-bg_highlight-soft_75_cccccc_1x100.png │ │ │ ├── ui-icons_222222_256x240.png │ │ │ ├── ui-icons_2e83ff_256x240.png │ │ │ ├── ui-icons_454545_256x240.png │ │ │ ├── ui-icons_888888_256x240.png │ │ │ └── ui-icons_cd0a0a_256x240.png │ │ ├── list.png │ │ ├── loader.gif │ │ ├── mime │ │ │ ├── application.png │ │ │ ├── audio.png │ │ │ ├── font.png │ │ │ ├── image.png │ │ │ ├── package.png │ │ │ ├── text.png │ │ │ └── video.png │ │ ├── narrow.png │ │ ├── nostar.png │ │ ├── notice.png │ │ ├── read.png │ │ ├── refresh.png │ │ ├── rss_icon.png │ │ ├── rssman.png │ │ ├── search.png │ │ ├── settings.png │ │ ├── share │ │ │ ├── email.png │ │ │ ├── facebook.png │ │ │ ├── googleplus.png │ │ │ └── twitter.png │ │ ├── star.png │ │ ├── subscription.png │ │ ├── success.png │ │ ├── tree_minus.gif │ │ ├── tree_plus.gif │ │ ├── unread.png │ │ ├── warning.png │ │ └── wide.png │ │ ├── index.html │ │ ├── javascripts │ │ ├── jquery.cookie.js │ │ ├── jquery.history.js │ │ ├── jquery.i18next.js │ │ ├── jquery.js │ │ ├── jquery.json.js │ │ ├── jquery.less.js │ │ ├── jquery.moment.js │ │ ├── jquery.numeral.js │ │ ├── jquery.qtip.js │ │ ├── jquery.throttle.js │ │ ├── jquery.toastmessage.js │ │ ├── jquery.ui.js │ │ ├── jquery.validate.js │ │ ├── jquery.visible.js │ │ ├── r.about.js │ │ ├── r.article.js │ │ ├── r.category.js │ │ ├── r.feed.js │ │ ├── r.main.js │ │ ├── r.search.js │ │ ├── r.settings.js │ │ ├── r.shortcuts.js │ │ ├── r.subscription.js │ │ ├── r.theme.js │ │ ├── r.user.js │ │ ├── r.util.js │ │ └── r.wizard.js │ │ ├── locales │ │ ├── messages.da.js │ │ ├── messages.de.js │ │ ├── messages.en.js │ │ ├── messages.fr.js │ │ ├── messages.it.js │ │ ├── messages.ja.js │ │ ├── messages.ko.js │ │ ├── messages.zh-CN.js │ │ ├── messages.zh-HK.js │ │ ├── messages.zh-TW.js │ │ └── messages.zh.js │ │ └── stylesheets │ │ ├── _desktop.less │ │ ├── _general.less │ │ ├── _jquery.toastmessage.less │ │ ├── _mixins.less │ │ ├── _smartphone-small.less │ │ ├── _smartphone.less │ │ ├── jquery.qtip.css │ │ ├── jquery.ui.css │ │ ├── loader.css │ │ ├── main.less │ │ └── theme │ │ ├── dark.less │ │ ├── default.less │ │ └── highcontrast.less │ ├── prod │ └── resources │ │ └── log4j.properties │ └── test │ ├── java │ └── com │ │ └── sismics │ │ └── reader │ │ └── rest │ │ ├── TestAllResource.java │ │ ├── TestAppResource.java │ │ ├── TestCategoryResource.java │ │ ├── TestJobResource.java │ │ ├── TestLocaleResource.java │ │ ├── TestSearchResource.java │ │ ├── TestSecurity.java │ │ ├── TestStarredResource.java │ │ ├── TestSubscriptionResource.java │ │ ├── TestThemeResource.java │ │ └── TestUserResource.java │ └── resources │ ├── hibernate.properties │ ├── http │ └── feeds │ │ ├── androiddev.xml │ │ ├── bigpicture.xml │ │ ├── deleted │ │ ├── deleted0.xml │ │ ├── deleted1.xml │ │ └── deleted2.xml │ │ ├── explosm.xml │ │ ├── future_date.xml │ │ ├── issue_119.xml │ │ ├── korben.xml │ │ ├── korben2.xml │ │ ├── qc.xml │ │ ├── saturdaymorning.xml │ │ ├── scientopia.xml │ │ ├── slashdot.xml │ │ └── xkcd.xml │ ├── import │ ├── greader_subscriptions.xml │ ├── issue_110@gmail.com-takeout.zip │ └── test@gmail.com-takeout.zip │ ├── log4j.properties │ └── stylesheets │ └── theme │ ├── default.less │ └── highcontrast.less ├── reader.xml └── rssman.ai /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set default behaviour, in case users don't have core.autocrlf set. 2 | * text=auto 3 | 4 | # Explicitly declare text files we want to always be normalized and converted 5 | # to native line endings on checkout. 6 | *.c text 7 | *.h text 8 | 9 | # Declare files that will always have CRLF line endings on checkout. 10 | *.sln text eol=crlf 11 | 12 | # Denote all files that are truly binary and should not be modified. 13 | *.png binary 14 | *.jpg binary 15 | 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /*/.classpath 2 | /*/.project 3 | /*/.settings 4 | /*/bin 5 | /*/gen 6 | /*/target 7 | *.iml 8 | .idea/ 9 | /reader-web/src/main/webapp/sismicsreader 10 | /reader-web/src/main/webapp/node 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | language: java 3 | services: 4 | - docker 5 | script: 6 | - if [ "$TRAVIS_BRANCH" == "release" ]; then 7 | mvn -B -Pprod,hosted -DskipTests clean install -pl reader-web,reader-core,reader-web-common; 8 | elif [ "$TRAVIS_BRANCH" == "demo" ]; then 9 | mvn -B -Pprod,demo -DskipTests clean install -pl reader-web,reader-core,reader-web-common; 10 | else 11 | mvn -B test; 12 | fi 13 | after_success: 14 | - if [ "$TRAVIS_BRANCH" == "release" ]; then 15 | docker build -f reader-distribution-docker/Dockerfile -t sismics/reader:latest .; 16 | docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD"; 17 | docker push sismics/reader:latest; 18 | elif [ "$TRAVIS_BRANCH" == "demo" ]; then 19 | docker build -f reader-distribution-docker/Dockerfile -t sismics/reader:demo-latest .; 20 | docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD"; 21 | docker push sismics/reader:demo-latest; 22 | fi 23 | -------------------------------------------------------------------------------- /reader-agent/src/main/java/com/sismics/reader/agent/deployer/DeploymentStatusListener.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.agent.deployer; 2 | 3 | /** 4 | * Callback interface implemented by classes that wants to be notified when the state 5 | * of the server deployment changes. 6 | * 7 | * @author jtremeaux 8 | */ 9 | public interface DeploymentStatusListener { 10 | 11 | /** 12 | * Method invoked when information about the server deployment is available 13 | * 14 | * @param deploymentStatus Deployment status 15 | */ 16 | void notifyDeploymentStatus(DeploymentStatus deploymentStatus); 17 | } 18 | -------------------------------------------------------------------------------- /reader-agent/src/main/java/com/sismics/util/MessageUtil.java: -------------------------------------------------------------------------------- 1 | package com.sismics.util; 2 | 3 | import java.text.MessageFormat; 4 | import java.util.Locale; 5 | import java.util.MissingResourceException; 6 | import java.util.ResourceBundle; 7 | 8 | /** 9 | * Message utilities. 10 | * 11 | * @author jtremeaux 12 | */ 13 | public class MessageUtil { 14 | private static final Locale locale = Locale.getDefault(); 15 | 16 | /** 17 | * Returns a message formated in the specified locale. 18 | * Returns **key** if no message is set for this key. 19 | * 20 | * @param key Message key 21 | * @param args Arguments of the message 22 | * @return Formated message 23 | */ 24 | public static String getMessage(String key, Object... args) { 25 | ResourceBundle resources = ResourceBundle.getBundle("messages", locale); 26 | String message = null; 27 | try { 28 | message = resources.getString(key); 29 | } catch (MissingResourceException e) { 30 | message = "**" + key + "**"; 31 | } 32 | return MessageFormat.format(message, args); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /reader-agent/src/main/resources/images/reader-started-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-agent/src/main/resources/images/reader-started-16.png -------------------------------------------------------------------------------- /reader-agent/src/main/resources/images/reader-stopped-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-agent/src/main/resources/images/reader-stopped-16.png -------------------------------------------------------------------------------- /reader-agent/src/main/resources/messages_fr.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-agent/src/main/resources/messages_fr.properties -------------------------------------------------------------------------------- /reader-android/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea 4 | build 5 | *.iml -------------------------------------------------------------------------------- /reader-android/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /reader-android/app/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | google() 5 | } 6 | dependencies { 7 | classpath 'com.android.tools.build:gradle:3.3.0' 8 | } 9 | } 10 | 11 | apply plugin: 'com.android.application' 12 | 13 | repositories { 14 | mavenCentral() 15 | google() 16 | flatDir { dirs 'libs' } 17 | } 18 | 19 | android { 20 | compileSdkVersion 28 21 | useLibrary 'org.apache.http.legacy' 22 | 23 | defaultConfig { 24 | minSdkVersion 14 25 | targetSdkVersion 28 26 | versionCode 12 27 | versionName "1.6.0" 28 | } 29 | 30 | signingConfigs { 31 | release { 32 | storeFile file(String.valueOf(System.getenv("READER_STORE_PATH"))) 33 | storePassword String.valueOf(System.getenv("READER_STORE_PASS")) 34 | keyAlias String.valueOf(System.getenv("READER_STORE_ALIAS")) 35 | keyPassword String.valueOf(System.getenv("READER_STORE_KEYPASS")) 36 | } 37 | } 38 | 39 | buildTypes { 40 | release { 41 | signingConfig signingConfigs.release 42 | } 43 | } 44 | } 45 | 46 | dependencies { 47 | implementation fileTree(dir: 'libs', include: '*.jar') 48 | implementation 'com.android.support:support-v4:28.0.0' 49 | implementation 'com.android.support:appcompat-v7:28.0.0' 50 | implementation 'com.mobeta.android.dslv:drag-sort-listview:0.6.1-SNAPSHOT-AAR@aar' 51 | implementation 'com.loopj.android:android-async-http:1.4.4' 52 | } -------------------------------------------------------------------------------- /reader-android/app/libs/android-query.0.26.7.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/libs/android-query.0.26.7.jar -------------------------------------------------------------------------------- /reader-android/app/libs/drag-sort-listview-0.6.1-SNAPSHOT-AAR.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/libs/drag-sort-listview-0.6.1-SNAPSHOT-AAR.aar -------------------------------------------------------------------------------- /reader-android/app/src/main/java/com/sismics/android/util/DialogUtil.java: -------------------------------------------------------------------------------- 1 | package com.sismics.android.util; 2 | 3 | import android.app.Activity; 4 | import android.app.AlertDialog; 5 | import android.content.DialogInterface; 6 | 7 | import com.sismics.reader.R; 8 | 9 | /** 10 | * Utility class for dialogs. 11 | * 12 | * @author bgamard 13 | */ 14 | public class DialogUtil { 15 | 16 | /** 17 | * Create a dialog with an OK button. 18 | * 19 | * @param activity Context activity 20 | * @param title Dialog title 21 | * @param message Dialog message 22 | */ 23 | public static void showOkDialog(Activity activity, int title, int message) { 24 | if (activity == null || activity.isFinishing()) { 25 | return; 26 | } 27 | 28 | AlertDialog.Builder builder = new AlertDialog.Builder(activity); 29 | 30 | builder.setTitle(title) 31 | .setMessage(message) 32 | .setCancelable(true) 33 | .setNeutralButton(R.string.ok, new DialogInterface.OnClickListener() { 34 | @Override 35 | public void onClick(DialogInterface dialog, int id) { 36 | dialog.dismiss(); 37 | } 38 | }).create().show(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /reader-android/app/src/main/java/com/sismics/reader/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader; 2 | 3 | import android.app.Application; 4 | 5 | import com.androidquery.callback.BitmapAjaxCallback; 6 | import com.sismics.reader.model.application.ApplicationContext; 7 | import com.sismics.reader.util.PreferenceUtil; 8 | 9 | import org.json.JSONObject; 10 | 11 | /** 12 | * Main application. 13 | * 14 | * @author bgamard 15 | */ 16 | public class MainApplication extends Application { 17 | @Override 18 | public void onCreate() { 19 | // Fetching /user/info from cache 20 | JSONObject json = PreferenceUtil.getCachedJson(getApplicationContext(), PreferenceUtil.PREF_CACHED_USER_INFO_JSON); 21 | ApplicationContext.getInstance().setUserInfo(getApplicationContext(), json); 22 | 23 | // TODO Changing the category of a subscription 24 | // TODO Renaming subscriptions 25 | // TODO Deleting subscriptions 26 | // TODO Admin interface if the user is admin 27 | 28 | // TODO Articles drawer: select article on opening 29 | 30 | super.onCreate(); 31 | } 32 | 33 | @Override 34 | public void onLowMemory() { 35 | super.onLowMemory(); 36 | BitmapAjaxCallback.clearCache(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /reader-android/app/src/main/java/com/sismics/reader/activity/LicenseActivity.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.activity; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.text.Html; 6 | import android.text.method.LinkMovementMethod; 7 | import android.view.MenuItem; 8 | 9 | import com.androidquery.AQuery; 10 | import com.sismics.reader.R; 11 | 12 | /** 13 | * Open source licenses activity. 14 | * 15 | * @author bgamard 16 | */ 17 | public class LicenseActivity extends AppCompatActivity { 18 | 19 | /** 20 | * AQuery. 21 | */ 22 | final AQuery aq = new AQuery(this); 23 | 24 | @Override 25 | protected void onCreate(Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | 28 | setContentView(R.layout.license_activity); 29 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 30 | getSupportActionBar().setHomeButtonEnabled(true); 31 | 32 | aq.id(R.id.txtLicenses) 33 | .text(Html.fromHtml(getString(R.string.licenses_content))) 34 | .getTextView() 35 | .setMovementMethod(LinkMovementMethod.getInstance()); 36 | } 37 | 38 | @Override 39 | public boolean onOptionsItemSelected(MenuItem item) { 40 | switch (item.getItemId()) { 41 | case android.R.id.home: 42 | finish(); 43 | return true; 44 | } 45 | 46 | return super.onOptionsItemSelected(item); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /reader-android/app/src/main/java/com/sismics/reader/activity/SettingsActivity.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.activity; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.view.MenuItem; 6 | 7 | import com.sismics.reader.fragment.SettingsFragment; 8 | 9 | /** 10 | * Settings activity. 11 | * 12 | * @author bgamard. 13 | */ 14 | public class SettingsActivity extends AppCompatActivity { 15 | 16 | @Override 17 | protected void onCreate(Bundle savedInstanceState) { 18 | super.onCreate(savedInstanceState); 19 | 20 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 21 | getSupportActionBar().setHomeButtonEnabled(true); 22 | 23 | // Display the fragment as the main content. 24 | getFragmentManager().beginTransaction() 25 | .replace(android.R.id.content, new SettingsFragment()) 26 | .commit(); 27 | } 28 | 29 | @Override 30 | public boolean onOptionsItemSelected(MenuItem item) { 31 | switch (item.getItemId()) { 32 | case android.R.id.home: 33 | finish(); 34 | return true; 35 | } 36 | 37 | return super.onOptionsItemSelected(item); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /reader-android/app/src/main/java/com/sismics/reader/constant/Constants.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.constant; 2 | 3 | 4 | /** 5 | * Application constants. 6 | * 7 | * @author bgamard 8 | */ 9 | public class Constants { 10 | /** 11 | * Request code from articles list. 12 | */ 13 | public static final int REQUEST_CODE_ARTICLES = 1; 14 | 15 | /** 16 | * Request code for managing activities. 17 | */ 18 | public static final int REQUEST_CODE_MANAGE_CATEGORIES = 2; 19 | } 20 | -------------------------------------------------------------------------------- /reader-android/app/src/main/java/com/sismics/reader/fragment/ArticlesDefaultFragment.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | import com.androidquery.AQuery; 9 | import com.sismics.reader.R; 10 | 11 | /** 12 | * Articles default fragment. 13 | * 14 | * @author bgamard 15 | */ 16 | public class ArticlesDefaultFragment extends NavigationFragment { 17 | 18 | /** 19 | * AQuery. 20 | */ 21 | private AQuery aq; 22 | 23 | @Override 24 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 25 | View view = inflater.inflate(R.layout.articles_fragment, container, false); 26 | aq = new AQuery(view); 27 | aq.id(R.id.articleList).getListView().setEmptyView(aq.id(R.id.progressBar).getView()); 28 | aq.id(R.id.loadingText).text(R.string.loading_subscriptions); 29 | 30 | return view; 31 | } 32 | 33 | /** 34 | * Listen to subscription loading error. 35 | */ 36 | public void onSubscriptionError() { 37 | aq.id(R.id.emptyList).text(R.string.error_loading_subscriptions) 38 | .getTextView() 39 | .setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, R.drawable.character_sad); 40 | aq.id(R.id.articleList).getListView().setEmptyView(aq.id(R.id.emptyList).getView()); 41 | aq.id(R.id.progressBar).gone(); 42 | } 43 | } -------------------------------------------------------------------------------- /reader-android/app/src/main/java/com/sismics/reader/fragment/NavigationFragment.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.fragment; 2 | 3 | import android.support.v4.app.Fragment; 4 | 5 | 6 | /** 7 | * Base navigation fragment. 8 | * 9 | * @author bgamard 10 | */ 11 | public class NavigationFragment extends Fragment { 12 | } -------------------------------------------------------------------------------- /reader-android/app/src/main/java/com/sismics/reader/listener/ArticlesHelperListener.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.listener; 2 | 3 | /** 4 | * Listener on articles loading. 5 | 6 | * @author bgamard 7 | */ 8 | public interface ArticlesHelperListener { 9 | 10 | /** 11 | * Start loading articles. 12 | */ 13 | public void onStart(); 14 | 15 | /** 16 | * Articles successfully loaded. 17 | */ 18 | public void onSuccess(); 19 | 20 | /** 21 | * Error occurred while loading the articles. 22 | */ 23 | public void onError(); 24 | 25 | /** 26 | * End loading new articles. 27 | */ 28 | public void onEnd(); 29 | } 30 | -------------------------------------------------------------------------------- /reader-android/app/src/main/java/com/sismics/reader/listener/CallbackListener.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.listener; 2 | 3 | /** 4 | * Simple listener. 5 | * 6 | * @author bgamard 7 | */ 8 | public interface CallbackListener { 9 | public void onComplete(); 10 | } 11 | -------------------------------------------------------------------------------- /reader-android/app/src/main/java/com/sismics/reader/provider/RecentSuggestionsProvider.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.provider; 2 | 3 | import android.content.SearchRecentSuggestionsProvider; 4 | 5 | /** 6 | * Search recent suggestions provider. 7 | * 8 | * @author bgamard. 9 | */ 10 | public class RecentSuggestionsProvider extends SearchRecentSuggestionsProvider { 11 | public final static String AUTHORITY = "com.sismics.reader.provider.RecentSuggestionsProvider"; 12 | public final static int MODE = DATABASE_MODE_QUERIES; 13 | 14 | public RecentSuggestionsProvider() { 15 | setupSuggestions(AUTHORITY, MODE); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /reader-android/app/src/main/java/com/sismics/reader/ui/adapter/ArticlesPagerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.ui.adapter; 2 | 3 | import android.support.v4.app.Fragment; 4 | import android.support.v4.app.FragmentManager; 5 | import android.support.v4.app.FragmentStatePagerAdapter; 6 | 7 | import com.sismics.reader.fragment.ArticleFragment; 8 | 9 | import org.json.JSONObject; 10 | 11 | import java.util.List; 12 | 13 | 14 | /** 15 | * Adapter for articles ViewPager. 16 | * 17 | * @author bgamard 18 | */ 19 | public class ArticlesPagerAdapter extends FragmentStatePagerAdapter { 20 | /** 21 | * Constructor. 22 | * @param fm FragmentManager 23 | */ 24 | public ArticlesPagerAdapter(FragmentManager fm) { 25 | super(fm); 26 | } 27 | 28 | @Override 29 | public Fragment getItem(int position) { 30 | JSONObject article = SharedArticlesAdapterHelper.getInstance().getArticleItems().get(position); 31 | return ArticleFragment.newInstance(article); 32 | } 33 | 34 | @Override 35 | public int getCount() { 36 | return SharedArticlesAdapterHelper.getInstance().getArticleItems().size(); 37 | } 38 | 39 | @Override 40 | public int getItemPosition(Object object) { 41 | return POSITION_UNCHANGED; 42 | // Do not return POSITION_NONE all the time or the whole fragment will be invalidated 43 | // return POSITION_NONE; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /reader-android/app/src/main/java/com/sismics/reader/ui/form/Validable.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.ui.form; 2 | 3 | import android.view.View; 4 | 5 | public class Validable { 6 | 7 | private View view; 8 | 9 | private boolean isValidated = false; 10 | 11 | /** 12 | * Getter of view. 13 | * @return view 14 | */ 15 | public View getView() { 16 | return view; 17 | } 18 | 19 | /** 20 | * Setter of view. 21 | * @param view view 22 | */ 23 | public void setView(View view) { 24 | this.view = view; 25 | } 26 | 27 | /** 28 | * Getter of isValidated. 29 | * @return isValidated 30 | */ 31 | public boolean isValidated() { 32 | return isValidated; 33 | } 34 | 35 | /** 36 | * Setter of isValidated. 37 | * @param isValidated isValidated 38 | */ 39 | public void setValidated(boolean isValidated) { 40 | this.isValidated = isValidated; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /reader-android/app/src/main/java/com/sismics/reader/ui/form/validator/Alphanumeric.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.ui.form.validator; 2 | 3 | import java.util.regex.Pattern; 4 | 5 | import android.content.Context; 6 | 7 | import com.sismics.reader.R; 8 | 9 | /** 10 | * Alphanumeric validator. 11 | * 12 | * @author bgamard 13 | */ 14 | public class Alphanumeric implements ValidatorType { 15 | 16 | private static Pattern ALPHANUMERIC_PATTERN = Pattern.compile("[a-zA-Z0-9_]+"); 17 | 18 | @Override 19 | public boolean validate(String text) { 20 | return ALPHANUMERIC_PATTERN.matcher(text).matches(); 21 | } 22 | 23 | @Override 24 | public String getErrorMessage(Context context) { 25 | return context.getString(R.string.validate_error_alphanumeric); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /reader-android/app/src/main/java/com/sismics/reader/ui/form/validator/Email.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.ui.form.validator; 2 | 3 | import java.util.regex.Pattern; 4 | 5 | import android.content.Context; 6 | 7 | import com.sismics.reader.R; 8 | 9 | /** 10 | * Email validator. 11 | * 12 | * @author bgamard 13 | */ 14 | public class Email implements ValidatorType { 15 | 16 | /** 17 | * Pattern de validation. 18 | */ 19 | private static Pattern EMAIL_PATTERN = Pattern.compile(".+@.+\\..+"); 20 | 21 | @Override 22 | public boolean validate(String text) { 23 | return EMAIL_PATTERN.matcher(text).matches(); 24 | } 25 | 26 | @Override 27 | public String getErrorMessage(Context context) { 28 | return context.getResources().getString(R.string.validate_error_email); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /reader-android/app/src/main/java/com/sismics/reader/ui/form/validator/Length.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.ui.form.validator; 2 | 3 | import android.content.Context; 4 | 5 | import com.sismics.reader.R; 6 | 7 | /** 8 | * Text length validator. 9 | * 10 | * @author bgamard 11 | */ 12 | public class Length implements ValidatorType { 13 | 14 | /** 15 | * Minimum length. 16 | */ 17 | private int minLength = 0; 18 | 19 | /** 20 | * Maximum length. 21 | */ 22 | private int maxLength = 0; 23 | 24 | /** 25 | * True if the last validation error was about a string too short. 26 | */ 27 | private boolean tooShort; 28 | 29 | /** 30 | * Constructor. 31 | * @param minLength 32 | * @param maxLength 33 | */ 34 | public Length(int minLength, int maxLength) { 35 | this.minLength = minLength; 36 | this.maxLength = maxLength; 37 | } 38 | 39 | @Override 40 | public boolean validate(String text) { 41 | tooShort = text.trim().length() < minLength; 42 | return text.trim().length() >= minLength && text.trim().length() <= maxLength; 43 | } 44 | 45 | @Override 46 | public String getErrorMessage(Context context) { 47 | if (tooShort) { 48 | return context.getResources().getString(R.string.validate_error_length_min, minLength); 49 | } 50 | return context.getResources().getString(R.string.validate_error_length_max, maxLength); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /reader-android/app/src/main/java/com/sismics/reader/ui/form/validator/Required.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.ui.form.validator; 2 | 3 | import android.content.Context; 4 | 5 | import com.sismics.reader.R; 6 | 7 | /** 8 | * Text presence validator. 9 | * 10 | * @author bgamard 11 | */ 12 | public class Required implements ValidatorType { 13 | 14 | @Override 15 | public boolean validate(String text) { 16 | return text.trim().length() != 0; 17 | } 18 | 19 | @Override 20 | public String getErrorMessage(Context context) { 21 | return context.getString(R.string.validate_error_required); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /reader-android/app/src/main/java/com/sismics/reader/ui/form/validator/ValidatorType.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.ui.form.validator; 2 | 3 | import android.content.Context; 4 | 5 | /** 6 | * Interface for validation types. 7 | * 8 | * @author bgamard 9 | */ 10 | public interface ValidatorType { 11 | 12 | /** 13 | * Returns true if the validator is validated. 14 | * @param text 15 | * @return 16 | */ 17 | public boolean validate(String text); 18 | 19 | /** 20 | * Returns an error message. 21 | * @param context 22 | * @return 23 | */ 24 | public String getErrorMessage(Context context); 25 | } 26 | -------------------------------------------------------------------------------- /reader-android/app/src/main/java/com/sismics/reader/ui/widget/ArticlesSwipeRefreshLayout.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.ui.widget; 2 | 3 | import android.content.Context; 4 | import android.support.v4.widget.SwipeRefreshLayout; 5 | import android.util.AttributeSet; 6 | import android.widget.ListView; 7 | 8 | import com.sismics.reader.R; 9 | 10 | /** 11 | * Subclassing of SwipeRefreshLayout to handle our custom case. 12 | * 13 | * @author bgamard. 14 | */ 15 | public class ArticlesSwipeRefreshLayout extends SwipeRefreshLayout { 16 | public ArticlesSwipeRefreshLayout(Context context) { 17 | super(context); 18 | } 19 | 20 | public ArticlesSwipeRefreshLayout(Context context, AttributeSet attrs) { 21 | super(context, attrs); 22 | } 23 | 24 | @Override 25 | public boolean canChildScrollUp() { 26 | ListView listView = (ListView) findViewById(R.id.articleList); 27 | return listView != null && listView.getChildCount() > 0 28 | && (listView.getFirstVisiblePosition() > 0 || listView.getChildAt(0) 29 | .getTop() < listView.getPaddingTop()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /reader-android/app/src/main/java/com/sismics/reader/util/ApplicationUtil.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.util; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageInfo; 5 | import android.content.pm.PackageManager.NameNotFoundException; 6 | 7 | /** 8 | * Utility class on general application data. 9 | * 10 | * @author bgamard 11 | */ 12 | public class ApplicationUtil { 13 | 14 | /** 15 | * Returns version name. 16 | * 17 | * @param context 18 | * @return Nom de la version 19 | */ 20 | public static String getVersionName(Context context) { 21 | try { 22 | PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); 23 | return packageInfo.versionName; 24 | } catch (NameNotFoundException e) { 25 | return ""; 26 | } 27 | } 28 | 29 | /** 30 | * Returns version number. 31 | * 32 | * @param context 33 | * @return Numéro de version 34 | */ 35 | public static int getVersionCode(Context context) { 36 | try { 37 | PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); 38 | return packageInfo.versionCode; 39 | } catch (NameNotFoundException e) { 40 | return 0; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /reader-android/app/src/main/res/anim/rssman.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 13 | 14 | 21 | 22 | 29 | 30 | 37 | 38 | -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-hdpi/character.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-hdpi/character.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-hdpi/character_happy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-hdpi/character_happy.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-hdpi/character_sad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-hdpi/character_sad.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-hdpi/ic_action_about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-hdpi/ic_action_about.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-hdpi/ic_action_accept.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-hdpi/ic_action_accept.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-hdpi/ic_action_collection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-hdpi/ic_action_collection.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-hdpi/ic_action_collection_inverse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-hdpi/ic_action_collection_inverse.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-hdpi/ic_action_collection_new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-hdpi/ic_action_collection_new.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-hdpi/ic_action_important.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-hdpi/ic_action_important.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-hdpi/ic_action_important_inverse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-hdpi/ic_action_important_inverse.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-hdpi/ic_action_new_inverse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-hdpi/ic_action_new_inverse.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-hdpi/ic_action_not_important.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-hdpi/ic_action_not_important.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-hdpi/ic_action_not_important_inverse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-hdpi/ic_action_not_important_inverse.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-hdpi/ic_action_read.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-hdpi/ic_action_read.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-hdpi/ic_action_read_inverse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-hdpi/ic_action_read_inverse.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-hdpi/ic_action_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-hdpi/ic_action_settings.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-hdpi/ic_action_share_inverse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-hdpi/ic_action_share_inverse.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-hdpi/ic_action_sort_by_size.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-hdpi/ic_action_sort_by_size.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-hdpi/ic_action_unread.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-hdpi/ic_action_unread.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-hdpi/ic_action_unread_inverse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-hdpi/ic_action_unread_inverse.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-hdpi/ic_drag.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-hdpi/ic_drag.9.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-hdpi/ic_menu_moreoverflow_card_inverse_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-hdpi/ic_menu_moreoverflow_card_inverse_normal.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-hdpi/ic_menu_moreoverflow_card_inverse_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-hdpi/ic_menu_moreoverflow_card_inverse_pressed.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-hdpi/list_activated_holo.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-hdpi/list_activated_holo.9.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-hdpi/list_background_holo.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-hdpi/list_background_holo.9.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-sw600dp-hdpi/list_activated_holo.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-sw600dp-hdpi/list_activated_holo.9.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-sw600dp-hdpi/list_background_holo.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-sw600dp-hdpi/list_background_holo.9.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-sw600dp-xhdpi/list_activated_holo.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-sw600dp-xhdpi/list_activated_holo.9.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-sw600dp-xhdpi/list_background_holo.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-sw600dp-xhdpi/list_background_holo.9.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-xhdpi/character.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-xhdpi/character.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-xhdpi/character_happy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-xhdpi/character_happy.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-xhdpi/character_sad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-xhdpi/character_sad.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-xhdpi/ic_action_about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-xhdpi/ic_action_about.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-xhdpi/ic_action_accept.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-xhdpi/ic_action_accept.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-xhdpi/ic_action_collection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-xhdpi/ic_action_collection.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-xhdpi/ic_action_collection_inverse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-xhdpi/ic_action_collection_inverse.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-xhdpi/ic_action_collection_new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-xhdpi/ic_action_collection_new.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-xhdpi/ic_action_important.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-xhdpi/ic_action_important.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-xhdpi/ic_action_important_inverse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-xhdpi/ic_action_important_inverse.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-xhdpi/ic_action_new_inverse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-xhdpi/ic_action_new_inverse.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-xhdpi/ic_action_not_important.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-xhdpi/ic_action_not_important.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-xhdpi/ic_action_not_important_inverse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-xhdpi/ic_action_not_important_inverse.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-xhdpi/ic_action_read.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-xhdpi/ic_action_read.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-xhdpi/ic_action_read_inverse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-xhdpi/ic_action_read_inverse.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-xhdpi/ic_action_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-xhdpi/ic_action_settings.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-xhdpi/ic_action_share_inverse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-xhdpi/ic_action_share_inverse.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-xhdpi/ic_action_sort_by_size.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-xhdpi/ic_action_sort_by_size.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-xhdpi/ic_action_unread.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-xhdpi/ic_action_unread.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-xhdpi/ic_action_unread_inverse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-xhdpi/ic_action_unread_inverse.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-xhdpi/ic_drag.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-xhdpi/ic_drag.9.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-xhdpi/ic_menu_moreoverflow_card_inverse_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-xhdpi/ic_menu_moreoverflow_card_inverse_normal.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-xhdpi/ic_menu_moreoverflow_card_inverse_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-xhdpi/ic_menu_moreoverflow_card_inverse_pressed.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-xhdpi/list_activated_holo.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-xhdpi/list_activated_holo.9.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-xhdpi/list_background_holo.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-xhdpi/list_background_holo.9.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/app/src/main/res/drawable-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable/article_title_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable/drawer_list_item_collection.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable/drawer_list_item_important.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable/drawer_list_item_read.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable/drawer_list_item_text_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable/drawer_list_item_unread.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable/list_item_activated_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /reader-android/app/src/main/res/drawable/overflow_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /reader-android/app/src/main/res/layout/actionbar_indeterminate_progress.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /reader-android/app/src/main/res/layout/add_subscription_dialog_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 14 | 15 | 21 | 22 | 27 | 28 | -------------------------------------------------------------------------------- /reader-android/app/src/main/res/layout/articles_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 15 | 26 | 27 | 34 | 35 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /reader-android/app/src/main/res/layout/drawer_list_item_header.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 21 | 22 | 27 | 28 | -------------------------------------------------------------------------------- /reader-android/app/src/main/res/layout/license_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /reader-android/app/src/main/res/menu/article_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | 19 | 20 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /reader-android/app/src/main/res/menu/categories_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 9 | 10 | 15 | 16 | -------------------------------------------------------------------------------- /reader-android/app/src/main/res/menu/category_overflow_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /reader-android/app/src/main/res/menu/context_articles.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | 16 | 17 | 22 | 23 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /reader-android/app/src/main/res/menu/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | 16 | 17 | 21 | 22 | 26 | 30 | 31 | 35 | 36 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /reader-android/app/src/main/res/values-de/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Ungelesen 6 | Alle 7 | Favoriten 8 | 9 | 10 | 11 | Klein 12 | Normal 13 | Groß 14 | 15 | 16 | -------------------------------------------------------------------------------- /reader-android/app/src/main/res/values-sw600dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | -------------------------------------------------------------------------------- /reader-android/app/src/main/res/values-w720dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 40dp 4 | -------------------------------------------------------------------------------- /reader-android/app/src/main/res/values/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 6 | 15 7 | 20 8 | 30 9 | 10 | 11 | 12 | Unread 13 | All 14 | Starred 15 | 16 | 17 | 18 | 1 19 | 2 20 | 3 21 | 22 | 23 | 24 | Small 25 | Normal 26 | Large 27 | 28 | 29 | 10 30 | 12 31 | 14 32 | 33 | 34 | -------------------------------------------------------------------------------- /reader-android/app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /reader-android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #2ab0e0 4 | #0099cc 5 | #aa66cc 6 | #9933cc 7 | #50ffffff 8 | -------------------------------------------------------------------------------- /reader-android/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8dp 4 | 0dp 5 | -------------------------------------------------------------------------------- /reader-android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 16 | 17 | 21 | 22 | -------------------------------------------------------------------------------- /reader-android/app/src/main/res/xml/searchable.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | -------------------------------------------------------------------------------- /reader-android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. -------------------------------------------------------------------------------- /reader-android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /reader-android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Feb 06 13:36:50 CET 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip 7 | -------------------------------------------------------------------------------- /reader-android/lint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /reader-android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /reader-core/src/dev/resources/db/update/dbupdate-000-2-test.sql: -------------------------------------------------------------------------------- 1 | update T_CONFIG set CFG_VALUE_C = 'RAM' where CFG_ID_C = 'LUCENE_DIRECTORY_STORAGE'; -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/constant/ConfigType.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.constant; 2 | 3 | /** 4 | * Configuration parameters. 5 | * 6 | * @author jtremeaux 7 | */ 8 | public enum ConfigType { 9 | /** 10 | * Lucene directory storage type. 11 | */ 12 | LUCENE_DIRECTORY_STORAGE, 13 | } 14 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/dao/file/html/FeedChooserStrategy.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.dao.file.html; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Strategy used to guess the URL of a RSS / Atom feed when several are present. 7 | * 8 | * @author jtremeaux 9 | */ 10 | public class FeedChooserStrategy { 11 | 12 | /** 13 | * Guess the correct feed URL from a set of links. 14 | * 15 | * @param feedList List of links 16 | * @return Feed URL 17 | */ 18 | public String guess(List feedList) { 19 | return feedList.get(0); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/dao/file/json/StarredArticleImportedEvent.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.dao.file.json; 2 | 3 | import com.google.common.base.Objects; 4 | import com.sismics.reader.core.model.jpa.Article; 5 | import com.sismics.reader.core.model.jpa.Feed; 6 | 7 | /** 8 | * Event raised on starred articles imported. 9 | * 10 | * @author jtremeaux 11 | */ 12 | public class StarredArticleImportedEvent { 13 | private Feed feed; 14 | 15 | private Article article; 16 | 17 | /** 18 | * Getter of feed. 19 | * 20 | * @return feed 21 | */ 22 | public Feed getFeed() { 23 | return feed; 24 | } 25 | 26 | /** 27 | * Setter of feed. 28 | * 29 | * @param feed feed 30 | */ 31 | public void setFeed(Feed feed) { 32 | this.feed = feed; 33 | } 34 | 35 | /** 36 | * Getter of article. 37 | * 38 | * @return article 39 | */ 40 | public Article getArticle() { 41 | return article; 42 | } 43 | 44 | /** 45 | * Setter of article. 46 | * 47 | * @param article article 48 | */ 49 | public void setArticle(Article article) { 50 | this.article = article; 51 | } 52 | 53 | @Override 54 | public String toString() { 55 | return Objects.toStringHelper(this) 56 | .add("feed", feed) 57 | .add("article", article) 58 | .toString(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/dao/file/json/StarredArticleImportedListener.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.dao.file.json; 2 | 3 | /** 4 | * Listener for starred item import events. 5 | * 6 | * @author jtremeaux 7 | */ 8 | public interface StarredArticleImportedListener { 9 | /** 10 | * Invoked when a new starred item is imported. 11 | * 12 | * @param event Event 13 | */ 14 | void onStarredArticleImported(StarredArticleImportedEvent event); 15 | } 16 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/dao/file/rss/AtomArticleCommentUrlGuesserStrategy.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.dao.file.rss; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Guess the article comment URL from a set of links. 7 | * 8 | * @author jtremeaux 9 | */ 10 | public class AtomArticleCommentUrlGuesserStrategy { 11 | 12 | /** 13 | * Guess the correct Site URL from a set of links. 14 | * 15 | * @param atomLinkList List of links 16 | * @return Site URL 17 | */ 18 | public String guess(List atomLinkList) { 19 | if (atomLinkList == null || atomLinkList.isEmpty()) { 20 | return null; 21 | } 22 | 23 | // 1st try: link with "replies" rel and html content type 24 | for (AtomLink atomLink : atomLinkList) { 25 | if ("replies".equals(atomLink.getRel()) && "text/html".equals(atomLink.getType())) { 26 | return atomLink.getHref(); 27 | } 28 | } 29 | 30 | // 2nd try: any link with "replies" rel 31 | for (AtomLink atomLink : atomLinkList) { 32 | if ("replies".equals(atomLink.getRel())) { 33 | return atomLink.getHref(); 34 | } 35 | } 36 | 37 | // Default: no comment link present 38 | return null; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/dao/file/rss/AtomArticleUrlGuesserStrategy.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.dao.file.rss; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Guess the article URL from a set of links. 7 | * 8 | * @author jtremeaux 9 | */ 10 | public class AtomArticleUrlGuesserStrategy { 11 | 12 | /** 13 | * Guess the correct article URL from a set of links. 14 | * 15 | * @param atomLinkList List of links 16 | * @return Site URL 17 | */ 18 | public String guess(List atomLinkList) { 19 | if (atomLinkList == null || atomLinkList.isEmpty()) { 20 | return null; 21 | } 22 | 23 | // 1st try: link from the element 24 | for (AtomLink atomLink : atomLinkList) { 25 | if (atomLink.getRel() == null && atomLink.getType() == null) { 26 | return atomLink.getHref(); 27 | } 28 | } 29 | 30 | // 2nd try: link from the element 31 | for (AtomLink atomLink : atomLinkList) { 32 | if ("alternate".equals(atomLink.getRel()) && "text/html".equals(atomLink.getType())) { 33 | return atomLink.getHref(); 34 | } 35 | } 36 | 37 | // Default: return the first link 38 | return atomLinkList.get(0).getHref(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/dao/file/rss/GuidFixer.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.dao.file.rss; 2 | 3 | import org.apache.commons.lang.StringUtils; 4 | 5 | import com.google.common.hash.Hasher; 6 | import com.google.common.hash.Hashing; 7 | import com.sismics.reader.core.model.jpa.Article; 8 | 9 | /** 10 | * Complete the GUID of articles. 11 | * 12 | * @author jtremeaux 13 | */ 14 | public class GuidFixer { 15 | 16 | /** 17 | * Complete the GUID of an article. 18 | * 19 | * @param article Article to complete (modified by side effect) 20 | */ 21 | public static void fixGuid(Article article) { 22 | if (StringUtils.isBlank(article.getGuid())) { 23 | Hasher hasher = Hashing.sha1().newHasher(); 24 | if (StringUtils.isNotBlank(article.getUrl())) { 25 | hasher.putString(article.getUrl()); 26 | } else { 27 | if (StringUtils.isNotBlank(article.getTitle())) { 28 | hasher.putString(article.getTitle()); 29 | } else if (StringUtils.isNotBlank(article.getDescription())) { 30 | hasher.putString(article.getDescription()); 31 | } 32 | } 33 | article.setGuid(hasher.hash().toString()); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/dao/jpa/ConfigDao.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.dao.jpa; 2 | 3 | import javax.persistence.EntityManager; 4 | import javax.persistence.NoResultException; 5 | 6 | import com.sismics.reader.core.constant.ConfigType; 7 | import com.sismics.reader.core.model.jpa.Config; 8 | import com.sismics.util.context.ThreadLocalContext; 9 | 10 | /** 11 | * Configuration parameter DAO. 12 | * 13 | * @author jtremeaux 14 | */ 15 | public class ConfigDao { 16 | /** 17 | * Gets a configuration parameter by its ID. 18 | * 19 | * @param id Configuration parameter ID 20 | * @return Configuration parameter 21 | */ 22 | public Config getById(ConfigType id) { 23 | EntityManager em = ThreadLocalContext.get().getEntityManager(); 24 | 25 | // Prevents from getting parameters outside of a transactional context (e.g. jUnit) 26 | if (em == null) { 27 | return null; 28 | } 29 | 30 | try { 31 | return em.find(Config.class, id); 32 | } catch (NoResultException e) { 33 | return null; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/dao/jpa/LocaleDao.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.dao.jpa; 2 | 3 | import java.util.List; 4 | 5 | import javax.persistence.EntityManager; 6 | import javax.persistence.NoResultException; 7 | import javax.persistence.Query; 8 | 9 | import com.sismics.reader.core.model.jpa.Locale; 10 | import com.sismics.util.context.ThreadLocalContext; 11 | 12 | /** 13 | * Locale DAO. 14 | * 15 | * @author jtremeaux 16 | */ 17 | public class LocaleDao { 18 | /** 19 | * Gets a locale by its ID. 20 | * 21 | * @param id Locale ID 22 | * @return Locale 23 | */ 24 | public Locale getById(String id) { 25 | EntityManager em = ThreadLocalContext.get().getEntityManager(); 26 | try { 27 | return em.find(Locale.class, id); 28 | } catch (NoResultException e) { 29 | return null; 30 | } 31 | } 32 | 33 | /** 34 | * Returns the list of all locales. 35 | * 36 | * @return List of locales 37 | */ 38 | @SuppressWarnings("unchecked") 39 | public List findAll() { 40 | EntityManager em = ThreadLocalContext.get().getEntityManager(); 41 | Query q = em.createQuery("select l from Locale l order by l.id"); 42 | return q.getResultList(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/dao/jpa/RoleBaseFunctionDao.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.dao.jpa; 2 | 3 | import com.google.common.collect.Sets; 4 | import com.sismics.util.context.ThreadLocalContext; 5 | 6 | import javax.persistence.EntityManager; 7 | import javax.persistence.Query; 8 | import java.util.Set; 9 | 10 | /** 11 | * Role base functions DAO. 12 | * 13 | * @author jtremeaux 14 | */ 15 | public class RoleBaseFunctionDao { 16 | /** 17 | * Find the set of base functions of a role. 18 | * 19 | * @param roleId Role ID 20 | * @return Set of base functions 21 | */ 22 | @SuppressWarnings("unchecked") 23 | public Set findByRoleId(String roleId) { 24 | EntityManager em = ThreadLocalContext.get().getEntityManager(); 25 | StringBuilder sb = new StringBuilder("select rbf.RBF_IDBASEFUNCTION_C from T_ROLE_BASE_FUNCTION rbf, T_ROLE r") 26 | .append(" where rbf.RBF_IDROLE_C = :roleId and rbf.RBF_DELETEDATE_D is null") 27 | .append(" and r.ROL_ID_C = rbf.RBF_IDROLE_C and r.ROL_DELETEDATE_D is null"); 28 | Query q = em.createNativeQuery(sb.toString()) 29 | .setParameter("roleId", roleId); 30 | return Sets.newHashSet(q.getResultList()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/dao/jpa/criteria/FeedCriteria.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.dao.jpa.criteria; 2 | 3 | /** 4 | * Feed criteria. 5 | * 6 | * @author jtremeaux 7 | */ 8 | public class FeedCriteria { 9 | /** 10 | * Feed URL. 11 | */ 12 | private String feedUrl; 13 | 14 | /** 15 | * Returns only feed having user subscriptions. 16 | */ 17 | private boolean withUserSubscription; 18 | 19 | /** 20 | * Getter of feedUrl. 21 | * 22 | * @return feedUrl 23 | */ 24 | public String getFeedUrl() { 25 | return feedUrl; 26 | } 27 | 28 | /** 29 | * Setter of feedUrl. 30 | * 31 | * @param feedUrl feedUrl 32 | */ 33 | public FeedCriteria setFeedUrl(String feedUrl) { 34 | this.feedUrl = feedUrl; 35 | return this; 36 | } 37 | 38 | /** 39 | * Getter of withUserSubscription. 40 | * 41 | * @return withUserSubscription 42 | */ 43 | public boolean isWithUserSubscription() { 44 | return withUserSubscription; 45 | } 46 | 47 | /** 48 | * Setter of withUserSubscription. 49 | * 50 | * @param withUserSubscription withUserSubscription 51 | */ 52 | public FeedCriteria setWithUserSubscription(boolean withUserSubscription) { 53 | this.withUserSubscription = withUserSubscription; 54 | return this; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/dao/jpa/criteria/JobCriteria.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.dao.jpa.criteria; 2 | 3 | /** 4 | * Job criteria. 5 | * 6 | * @author jtremeaux 7 | */ 8 | public class JobCriteria { 9 | /** 10 | * User ID. 11 | */ 12 | private String userId; 13 | 14 | /** 15 | * Getter of userId. 16 | * 17 | * @return userId 18 | */ 19 | public String getUserId() { 20 | return userId; 21 | } 22 | 23 | /** 24 | * Setter of userId. 25 | * 26 | * @param userId userId 27 | */ 28 | public JobCriteria setUserId(String userId) { 29 | this.userId = userId; 30 | return this; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/dao/jpa/criteria/JobEventCriteria.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.dao.jpa.criteria; 2 | 3 | /** 4 | * Job event criteria. 5 | * 6 | * @author jtremeaux 7 | */ 8 | public class JobEventCriteria { 9 | /** 10 | * Job ID. 11 | */ 12 | private String jobId; 13 | 14 | /** 15 | * Getter of jobId. 16 | * 17 | * @return jobId 18 | */ 19 | public String getJobId() { 20 | return jobId; 21 | } 22 | 23 | /** 24 | * Setter of jobId. 25 | * 26 | * @param jobId jobId 27 | */ 28 | public JobEventCriteria setJobId(String jobId) { 29 | this.jobId = jobId; 30 | return this; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/dao/jpa/criteria/UserCriteria.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.dao.jpa.criteria; 2 | 3 | /** 4 | * User criteria. 5 | * 6 | * @author jtremeaux 7 | */ 8 | public class UserCriteria { 9 | } 10 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/dao/jpa/dto/FeedDto.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.dao.jpa.dto; 2 | 3 | /** 4 | * Feed DTO. 5 | * 6 | * @author jtremeaux 7 | */ 8 | public class FeedDto { 9 | /** 10 | * Feed ID. 11 | */ 12 | private String id; 13 | 14 | /** 15 | * Feed RSS URL. 16 | */ 17 | private String rssUrl; 18 | 19 | /** 20 | * Getter of id. 21 | * 22 | * @return id 23 | */ 24 | public String getId() { 25 | return id; 26 | } 27 | 28 | /** 29 | * Setter of id. 30 | * 31 | * @param id id 32 | */ 33 | public void setId(String id) { 34 | this.id = id; 35 | } 36 | 37 | /** 38 | * Getter of rssUrl. 39 | * 40 | * @return rssUrl 41 | */ 42 | public String getRssUrl() { 43 | return rssUrl; 44 | } 45 | 46 | /** 47 | * Setter of rssUrl. 48 | * 49 | * @param rssUrl rssUrl 50 | */ 51 | public void setRssUrl(String rssUrl) { 52 | this.rssUrl = rssUrl; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/dao/jpa/dto/JobEventDto.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.dao.jpa.dto; 2 | 3 | /** 4 | * Job DTO. 5 | * 6 | * @author jtremeaux 7 | */ 8 | public class JobEventDto { 9 | /** 10 | * Job ID. 11 | */ 12 | private String id; 13 | 14 | /** 15 | * Job event name. 16 | */ 17 | private String name; 18 | 19 | /** 20 | * Job event value. 21 | */ 22 | private String value; 23 | 24 | /** 25 | * Getter of id. 26 | * 27 | * @return id 28 | */ 29 | public String getId() { 30 | return id; 31 | } 32 | 33 | /** 34 | * Setter of id. 35 | * 36 | * @param id id 37 | */ 38 | public void setId(String id) { 39 | this.id = id; 40 | } 41 | 42 | /** 43 | * Getter of name. 44 | * 45 | * @return name 46 | */ 47 | public String getName() { 48 | return name; 49 | } 50 | 51 | /** 52 | * Setter of name. 53 | * 54 | * @param name name 55 | */ 56 | public void setName(String name) { 57 | this.name = name; 58 | } 59 | 60 | /** 61 | * Getter of value. 62 | * 63 | * @return value 64 | */ 65 | public String getValue() { 66 | return value; 67 | } 68 | 69 | /** 70 | * Setter of value. 71 | * 72 | * @param value value 73 | */ 74 | public void setValue(String value) { 75 | this.value = value; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/dao/jpa/mapper/ArticleMapper.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.dao.jpa.mapper; 2 | 3 | import com.sismics.reader.core.dao.jpa.dto.ArticleDto; 4 | import com.sismics.util.jpa.ResultMapper; 5 | 6 | /** 7 | * @author jtremeaux 8 | */ 9 | public class ArticleMapper extends ResultMapper { 10 | @Override 11 | public ArticleDto map(Object[] o) { 12 | int i = 0; 13 | ArticleDto dto = new ArticleDto(); 14 | dto.setId(stringValue(o[i++])); 15 | dto.setUrl(stringValue(o[i++])); 16 | dto.setGuid(stringValue(o[i++])); 17 | dto.setTitle(stringValue(o[i++])); 18 | dto.setCreator(stringValue(o[i++])); 19 | dto.setDescription(stringValue(o[i++])); 20 | dto.setCommentUrl(stringValue(o[i++])); 21 | dto.setCommentCount(intValue(o[i++])); 22 | dto.setEnclosureUrl(stringValue(o[i++])); 23 | dto.setEnclosureCount(intValue(o[i++])); 24 | dto.setEnclosureType(stringValue(o[i++])); 25 | dto.setPublicationDate(dateValue(o[i++])); 26 | dto.setCreateDate(dateValue(o[i++])); 27 | dto.setFeedId(stringValue(o[i])); 28 | 29 | return dto; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/dao/jpa/mapper/FeedMapper.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.dao.jpa.mapper; 2 | 3 | import com.sismics.reader.core.dao.jpa.dto.FeedDto; 4 | import com.sismics.util.jpa.ResultMapper; 5 | 6 | /** 7 | * @author jtremeaux 8 | */ 9 | public class FeedMapper extends ResultMapper { 10 | @Override 11 | public FeedDto map(Object[] o) { 12 | int i = 0; 13 | FeedDto dto = new FeedDto(); 14 | dto.setId(stringValue(o[i++])); 15 | dto.setRssUrl(stringValue(o[i])); 16 | 17 | return dto; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/dao/jpa/mapper/FeedSubscriptionMapper.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.dao.jpa.mapper; 2 | 3 | import com.sismics.reader.core.dao.jpa.dto.FeedSubscriptionDto; 4 | import com.sismics.util.jpa.ResultMapper; 5 | 6 | /** 7 | * @author jtremeaux 8 | */ 9 | public class FeedSubscriptionMapper extends ResultMapper { 10 | @Override 11 | public FeedSubscriptionDto map(Object[] o) { 12 | int i = 0; 13 | FeedSubscriptionDto dto = new FeedSubscriptionDto(); 14 | dto.setId(stringValue(o[i++])); 15 | String feedSubscriptionTitle = stringValue(o[i++]); 16 | dto.setUnreadUserArticleCount(intValue(o[i++])); 17 | dto.setCreateDate(dateValue(o[i++])); 18 | dto.setUserId(stringValue(o[i++])); 19 | dto.setFeedId(stringValue(o[i++])); 20 | String feedTitle = stringValue(o[i++]); 21 | dto.setFeedSubscriptionTitle(feedSubscriptionTitle != null ? feedSubscriptionTitle : feedTitle); 22 | dto.setFeedTitle(feedTitle); 23 | dto.setFeedRssUrl(stringValue(o[i++])); 24 | dto.setFeedUrl(stringValue(o[i++])); 25 | dto.setFeedDescription(stringValue(o[i++])); 26 | dto.setCategoryId(stringValue(o[i++])); 27 | dto.setCategoryParentId(stringValue(o[i++])); 28 | dto.setCategoryName(stringValue(o[i++])); 29 | Boolean folded = booleanValue(o[i++]); 30 | dto.setCategoryFolded(folded != null ? folded : false); 31 | dto.setSynchronizationFailCount(((Number) o[i]).intValue()); 32 | 33 | return dto; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/dao/jpa/mapper/JobEventMapper.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.dao.jpa.mapper; 2 | 3 | import com.sismics.reader.core.dao.jpa.dto.JobEventDto; 4 | import com.sismics.util.jpa.ResultMapper; 5 | 6 | /** 7 | * @author jtremeaux 8 | */ 9 | public class JobEventMapper extends ResultMapper { 10 | @Override 11 | public JobEventDto map(Object[] o) { 12 | int i = 0; 13 | JobEventDto dto = new JobEventDto(); 14 | dto.setId(stringValue(o[i++])); 15 | dto.setName(stringValue(o[i++])); 16 | dto.setValue(stringValue(o[i])); 17 | 18 | return dto; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/dao/jpa/mapper/JobMapper.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.dao.jpa.mapper; 2 | 3 | import com.sismics.reader.core.dao.jpa.dto.JobDto; 4 | import com.sismics.util.jpa.ResultMapper; 5 | 6 | import java.sql.Timestamp; 7 | 8 | /** 9 | * @author jtremeaux 10 | */ 11 | public class JobMapper extends ResultMapper { 12 | @Override 13 | public JobDto map(Object[] o) { 14 | int i = 0; 15 | JobDto dto = new JobDto(); 16 | dto.setId(stringValue(o[i++])); 17 | dto.setName(stringValue(o[i++])); 18 | dto.setUserId(stringValue(o[i++])); 19 | Timestamp createTimestamp = (Timestamp) o[i++]; 20 | if (createTimestamp != null) { 21 | dto.setCreateTimestamp(createTimestamp.getTime()); 22 | } 23 | Timestamp startTimestamp = (Timestamp) o[i++]; 24 | if (startTimestamp != null) { 25 | dto.setStartTimestamp(startTimestamp.getTime()); 26 | } 27 | Timestamp endTimestamp = (Timestamp) o[i]; 28 | if (endTimestamp != null) { 29 | dto.setEndTimestamp(endTimestamp.getTime()); 30 | } 31 | 32 | return dto; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/dao/jpa/mapper/UserMapper.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.dao.jpa.mapper; 2 | 3 | import com.sismics.reader.core.dao.jpa.dto.UserDto; 4 | import com.sismics.util.jpa.ResultMapper; 5 | 6 | import java.sql.Timestamp; 7 | 8 | /** 9 | * @author jtremeaux 10 | */ 11 | public class UserMapper extends ResultMapper { 12 | @Override 13 | public UserDto map(Object[] o) { 14 | int i = 0; 15 | UserDto dto = new UserDto(); 16 | dto.setId(stringValue(o[i++])); 17 | dto.setUsername(stringValue(o[i++])); 18 | dto.setEmail(stringValue(o[i++])); 19 | dto.setCreateTimestamp(((Timestamp) o[i++]).getTime()); 20 | dto.setLocaleId(stringValue(o[i])); 21 | 22 | return dto; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/event/ArticleCreatedAsyncEvent.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.event; 2 | 3 | import java.util.List; 4 | 5 | import com.google.common.base.Objects; 6 | import com.sismics.reader.core.model.jpa.Article; 7 | 8 | /** 9 | * New articles created event. 10 | * 11 | * @author bgamard 12 | */ 13 | public class ArticleCreatedAsyncEvent { 14 | /** 15 | * List of newly created articles. 16 | */ 17 | private List
articleList; 18 | 19 | /** 20 | * Getter of articleList. 21 | * 22 | * @return articleList 23 | */ 24 | public List
getArticleList() { 25 | return articleList; 26 | } 27 | 28 | /** 29 | * Setter of articleList. 30 | * 31 | * @param articleList articleList 32 | */ 33 | public void setArticleList(List
articleList) { 34 | this.articleList = articleList; 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return Objects.toStringHelper(this) 40 | .add("articles", (articleList != null ? articleList.size() : "0") + " articles") 41 | .toString(); 42 | } 43 | } -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/event/ArticleDeletedAsyncEvent.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.event; 2 | 3 | import com.google.common.base.Objects; 4 | import com.sismics.reader.core.model.jpa.Article; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * Articles deleted event. 10 | * 11 | * @author bgamard 12 | */ 13 | public class ArticleDeletedAsyncEvent { 14 | /** 15 | * List of deleted articles. 16 | */ 17 | private List
articleList; 18 | 19 | /** 20 | * Getter of articleList. 21 | * 22 | * @return articleList 23 | */ 24 | public List
getArticleList() { 25 | return articleList; 26 | } 27 | 28 | /** 29 | * Setter of articleList. 30 | * 31 | * @param articleList articleList 32 | */ 33 | public void setArticleList(List
articleList) { 34 | this.articleList = articleList; 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return Objects.toStringHelper(this) 40 | .add("articles", (articleList != null ? articleList.size() : "0") + " articles") 41 | .toString(); 42 | } 43 | } -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/event/ArticleUpdatedAsyncEvent.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.event; 2 | 3 | import java.util.List; 4 | 5 | import com.google.common.base.Objects; 6 | import com.sismics.reader.core.model.jpa.Article; 7 | 8 | /** 9 | * Articles updated event. 10 | * 11 | * @author bgamard 12 | */ 13 | public class ArticleUpdatedAsyncEvent { 14 | /** 15 | * List of updated articles. 16 | */ 17 | private List
articleList; 18 | 19 | /** 20 | * Getter of articleList. 21 | * 22 | * @return articleList 23 | */ 24 | public List
getArticleList() { 25 | return articleList; 26 | } 27 | 28 | /** 29 | * Setter of articleList. 30 | * 31 | * @param articleList articleList 32 | */ 33 | public void setArticleList(List
articleList) { 34 | this.articleList = articleList; 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return Objects.toStringHelper(this) 40 | .add("articles", (articleList != null ? articleList.size() : "0") + " articles") 41 | .toString(); 42 | } 43 | } -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/event/FaviconUpdateRequestedEvent.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.event; 2 | 3 | import com.google.common.base.Objects; 4 | import com.sismics.reader.core.model.jpa.Feed; 5 | 6 | /** 7 | * Event raised on request to update a feed favicon. 8 | * 9 | * @author jtremeaux 10 | */ 11 | public class FaviconUpdateRequestedEvent { 12 | /** 13 | * Feed to update. 14 | */ 15 | private Feed feed; 16 | 17 | @Override 18 | public String toString() { 19 | return Objects.toStringHelper(this) 20 | .add("feedId", feed.getId()) 21 | .toString(); 22 | } 23 | 24 | /** 25 | * Getter of feed. 26 | * 27 | * @return feed 28 | */ 29 | public Feed getFeed() { 30 | return feed; 31 | } 32 | 33 | /** 34 | * Setter of feed. 35 | * 36 | * @param feed feed 37 | */ 38 | public void setFeed(Feed feed) { 39 | this.feed = feed; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/event/PasswordChangedEvent.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.event; 2 | 3 | import com.sismics.reader.core.model.jpa.User; 4 | 5 | /** 6 | * Event raised after the user changes his password. 7 | * 8 | * @author jtremeaux 9 | */ 10 | public class PasswordChangedEvent { 11 | /** 12 | * Created user. 13 | */ 14 | private User user; 15 | 16 | /** 17 | * Getter of user. 18 | * 19 | * @return user 20 | */ 21 | public User getUser() { 22 | return user; 23 | } 24 | 25 | /** 26 | * Setter of user. 27 | * 28 | * @param user user 29 | */ 30 | public void setUser(User user) { 31 | this.user = user; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/event/RebuildIndexAsyncEvent.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.event; 2 | 3 | import com.google.common.base.Objects; 4 | 5 | /** 6 | * Rebuild index event. 7 | * 8 | * @author bgamard 9 | */ 10 | public class RebuildIndexAsyncEvent { 11 | @Override 12 | public String toString() { 13 | return Objects.toStringHelper(this) 14 | .toString(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/event/SubscriptionImportedEvent.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.event; 2 | 3 | import java.io.File; 4 | 5 | import com.google.common.base.Objects; 6 | import com.sismics.reader.core.model.jpa.User; 7 | 8 | /** 9 | * Event raised on request to import an subscriptions (OPML, Google Takeout) file. 10 | * 11 | * @author jtremeaux 12 | */ 13 | public class SubscriptionImportedEvent { 14 | /** 15 | * User requesting the import. 16 | */ 17 | private User user; 18 | 19 | /** 20 | * Temporary file to import. 21 | */ 22 | private File importFile; 23 | 24 | /** 25 | * Getter of user. 26 | * 27 | * @return user 28 | */ 29 | public User getUser() { 30 | return user; 31 | } 32 | 33 | /** 34 | * Setter of user. 35 | * 36 | * @param user user 37 | */ 38 | public void setUser(User user) { 39 | this.user = user; 40 | } 41 | 42 | /** 43 | * Getter of importFile. 44 | * 45 | * @return importFile 46 | */ 47 | public File getImportFile() { 48 | return importFile; 49 | } 50 | 51 | /** 52 | * Setter of importFile. 53 | * 54 | * @param importFile importFile 55 | */ 56 | public void setImportFile(File importFile) { 57 | this.importFile = importFile; 58 | } 59 | 60 | @Override 61 | public String toString() { 62 | return Objects.toStringHelper(this) 63 | .add("user", user) 64 | .add("importFile", importFile) 65 | .toString(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/event/UserCreatedEvent.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.event; 2 | 3 | import com.google.common.base.Objects; 4 | import com.sismics.reader.core.model.jpa.User; 5 | 6 | /** 7 | * Event raised after the creation of a user. 8 | * 9 | * @author jtremeaux 10 | */ 11 | public class UserCreatedEvent { 12 | /** 13 | * Created user. 14 | */ 15 | private User user; 16 | 17 | /** 18 | * Getter of user. 19 | * 20 | * @return user 21 | */ 22 | public User getUser() { 23 | return user; 24 | } 25 | 26 | /** 27 | * Setter of user. 28 | * 29 | * @param user user 30 | */ 31 | public void setUser(User user) { 32 | this.user = user; 33 | } 34 | 35 | @Override 36 | public String toString() { 37 | return Objects.toStringHelper(this) 38 | .add("user", user) 39 | .toString(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/listener/async/ArticleDeletedAsyncListener.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.listener.async; 2 | 3 | import com.google.common.eventbus.Subscribe; 4 | import com.sismics.reader.core.dao.lucene.ArticleDao; 5 | import com.sismics.reader.core.event.ArticleDeletedAsyncEvent; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import java.text.MessageFormat; 10 | 11 | /** 12 | * Listener on deleted articles. 13 | * 14 | * @author bgamard 15 | */ 16 | public class ArticleDeletedAsyncListener { 17 | /** 18 | * Logger. 19 | */ 20 | private static final Logger log = LoggerFactory.getLogger(ArticleDeletedAsyncListener.class); 21 | 22 | /** 23 | * Process deleted articles. 24 | * 25 | * @param articlesDeletedAsyncEvent Deleted articles event 26 | */ 27 | @Subscribe 28 | public void onArticleDeleted(final ArticleDeletedAsyncEvent articlesDeletedAsyncEvent) throws Exception { 29 | if (log.isInfoEnabled()) { 30 | log.info("Deleted article event: " + articlesDeletedAsyncEvent.toString()); 31 | } 32 | long startTime = System.currentTimeMillis(); 33 | 34 | // Delete index 35 | ArticleDao articleDao = new ArticleDao(); 36 | articleDao.delete(articlesDeletedAsyncEvent.getArticleList()); 37 | 38 | long endTime = System.currentTimeMillis(); 39 | if (log.isInfoEnabled()) { 40 | log.info(MessageFormat.format("Index deleted in {0}ms", endTime - startTime)); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/listener/async/ArticleUpdatedAsyncListener.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.listener.async; 2 | 3 | import com.google.common.eventbus.Subscribe; 4 | import com.sismics.reader.core.dao.lucene.ArticleDao; 5 | import com.sismics.reader.core.event.ArticleUpdatedAsyncEvent; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import java.text.MessageFormat; 10 | 11 | /** 12 | * Listener on updated articles. 13 | * 14 | * @author bgamard 15 | */ 16 | public class ArticleUpdatedAsyncListener { 17 | /** 18 | * Logger. 19 | */ 20 | private static final Logger log = LoggerFactory.getLogger(ArticleUpdatedAsyncListener.class); 21 | 22 | /** 23 | * Process updated articles. 24 | * 25 | * @param articlesUpdatedAsyncEvent Updated articles event 26 | */ 27 | @Subscribe 28 | public void onArticleUpdated(final ArticleUpdatedAsyncEvent articlesUpdatedAsyncEvent) throws Exception { 29 | if (log.isInfoEnabled()) { 30 | log.info("Updated article event: " + articlesUpdatedAsyncEvent.toString()); 31 | } 32 | long startTime = System.currentTimeMillis(); 33 | 34 | // Update index 35 | ArticleDao articleDao = new ArticleDao(); 36 | articleDao.update(articlesUpdatedAsyncEvent.getArticleList()); 37 | 38 | long endTime = System.currentTimeMillis(); 39 | if (log.isInfoEnabled()) { 40 | log.info(MessageFormat.format("Index updated in {0}ms", endTime - startTime)); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/listener/async/RebuildIndexAsyncListener.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.listener.async; 2 | 3 | import com.google.common.eventbus.Subscribe; 4 | import com.sismics.reader.core.dao.lucene.ArticleDao; 5 | import com.sismics.reader.core.event.RebuildIndexAsyncEvent; 6 | import com.sismics.reader.core.model.jpa.Article; 7 | import com.sismics.reader.core.util.TransactionUtil; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * Listener on rebuild index. 15 | * 16 | * @author bgamard 17 | */ 18 | public class RebuildIndexAsyncListener { 19 | /** 20 | * Logger. 21 | */ 22 | private static final Logger log = LoggerFactory.getLogger(RebuildIndexAsyncListener.class); 23 | 24 | /** 25 | * Rebuild articles index. 26 | * 27 | * @param rebuildIndexAsyncEvent Index rebuild event 28 | */ 29 | @Subscribe 30 | public void onArticleCreated(final RebuildIndexAsyncEvent rebuildIndexAsyncEvent) throws Exception { 31 | if (log.isInfoEnabled()) { 32 | log.info("Rebuild index event: " + rebuildIndexAsyncEvent.toString()); 33 | } 34 | 35 | // Fetch all articles 36 | TransactionUtil.handle(() -> { 37 | com.sismics.reader.core.dao.jpa.ArticleDao jpaArticleDao = new com.sismics.reader.core.dao.jpa.ArticleDao(); 38 | List
articleList = jpaArticleDao.findAll(); 39 | 40 | // Rebuild index 41 | ArticleDao articleDao = new ArticleDao(); 42 | articleDao.rebuildIndex(articleList); 43 | }); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/listener/sync/DeadEventListener.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.listener.sync; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import com.google.common.eventbus.DeadEvent; 7 | import com.google.common.eventbus.Subscribe; 8 | 9 | /** 10 | * Listener for all unprocessed events. 11 | * 12 | * @author jtremeaux 13 | */ 14 | public class DeadEventListener { 15 | /** 16 | * Logger. 17 | */ 18 | private static final Logger log = LoggerFactory.getLogger(DeadEventListener.class); 19 | 20 | /** 21 | * Process every dead event. 22 | * 23 | * @param deadEvent Catchall event 24 | */ 25 | @Subscribe 26 | public void onDeadEvent(DeadEvent deadEvent) { 27 | log.error("Dead event catched: " + deadEvent.toString()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/model/jpa/BaseFunction.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.model.jpa; 2 | 3 | import javax.persistence.Column; 4 | import javax.persistence.Entity; 5 | import javax.persistence.Id; 6 | import javax.persistence.Table; 7 | 8 | import com.google.common.base.Objects; 9 | 10 | /** 11 | * Base function entity. 12 | * 13 | * @author jtremeaux 14 | */ 15 | @Entity 16 | @Table(name = "T_BASE_FUNCTION") 17 | public class BaseFunction { 18 | /** 19 | * Base function ID (ex: "ADMIN"). 20 | */ 21 | @Id 22 | @Column(name = "BAF_ID_C", length = 10) 23 | private String id; 24 | 25 | /** 26 | * Getter of id. 27 | * 28 | * @return id 29 | */ 30 | public String getId() { 31 | return id; 32 | } 33 | 34 | /** 35 | * Setter of id. 36 | * 37 | * @param id id 38 | */ 39 | public void setId(String id) { 40 | this.id = id; 41 | } 42 | 43 | @Override 44 | public String toString() { 45 | return Objects.toStringHelper(this) 46 | .add("id", id) 47 | .toString(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/model/jpa/Locale.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.model.jpa; 2 | 3 | import javax.persistence.Column; 4 | import javax.persistence.Entity; 5 | import javax.persistence.Id; 6 | import javax.persistence.Table; 7 | 8 | import com.google.common.base.Objects; 9 | 10 | /** 11 | * Locale entity. 12 | * 13 | * @author jtremeaux 14 | */ 15 | @Entity 16 | @Table(name = "T_LOCALE") 17 | public class Locale { 18 | /** 19 | * Locale ID (ex: fr_FR). 20 | */ 21 | @Id 22 | @Column(name = "LOC_ID_C", length = 10) 23 | private String id; 24 | 25 | /** 26 | * Getter of id. 27 | * 28 | * @return id 29 | */ 30 | public String getId() { 31 | return id; 32 | } 33 | 34 | /** 35 | * Setter of id. 36 | * 37 | * @param id id 38 | */ 39 | public void setId(String id) { 40 | this.id = id; 41 | } 42 | 43 | @Override 44 | public String toString() { 45 | return Objects.toStringHelper(this) 46 | .add("id", id) 47 | .toString(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/util/EntityManagerUtil.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.util; 2 | 3 | import com.sismics.util.context.ThreadLocalContext; 4 | 5 | /** 6 | * Entity manager utils. 7 | * 8 | * @author jtremeaux 9 | */ 10 | public class EntityManagerUtil { 11 | /** 12 | * Flush the entity manager session. 13 | */ 14 | public static void flush() { 15 | ThreadLocalContext.get().getEntityManager().flush(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/util/StreamUtil.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.util; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.PushbackInputStream; 6 | import java.util.zip.GZIPInputStream; 7 | 8 | /** 9 | * Stream utilities. 10 | * 11 | * @author bgamard 12 | */ 13 | public class StreamUtil { 14 | 15 | /** 16 | * Detects if the stream is gzipped, and returns a uncompressed stream according to this. 17 | * 18 | * @param is InputStream 19 | * @return InputStream 20 | */ 21 | public static InputStream detectGzip(InputStream is) throws IOException { 22 | PushbackInputStream pb = new PushbackInputStream(is, 2); 23 | byte [] signature = new byte[2]; 24 | pb.read(signature); 25 | pb.unread(signature); 26 | if(signature[0] == (byte) GZIPInputStream.GZIP_MAGIC && signature[1] == (byte) (GZIPInputStream.GZIP_MAGIC >> 8)) { 27 | return new GZIPInputStream(pb); 28 | } else { 29 | return pb; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/util/UserUtil.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.util; 2 | 3 | import com.sismics.reader.core.model.jpa.User; 4 | 5 | /** 6 | * Utilitaires sur les utilisateurs. 7 | * 8 | * @author jtremeaux 9 | */ 10 | public class UserUtil { 11 | /** 12 | * Retourne the user's username. 13 | * 14 | * @param user User 15 | * @return User name 16 | */ 17 | public static String getUserName(User user) { 18 | return user.getUsername(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/util/jpa/SortCriteria.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.util.jpa; 2 | 3 | /** 4 | * Sort criteria of a query. 5 | * 6 | * @author jtremeaux 7 | */ 8 | public class SortCriteria { 9 | /** 10 | * Index of the column to sort (first is 0). 11 | */ 12 | private int column; 13 | 14 | /** 15 | * Sort in increasing order (or else decreasing). 16 | */ 17 | private boolean asc = true; 18 | 19 | private String sortQuery; 20 | 21 | /** 22 | * Constructor of sortCriteria. 23 | */ 24 | public SortCriteria(String sortQuery) { 25 | this.sortQuery = sortQuery; 26 | } 27 | 28 | /** 29 | * Constructor of sortCriteria. 30 | */ 31 | public SortCriteria(Integer column, Boolean asc) { 32 | if (column != null) { 33 | this.column = column; 34 | } 35 | if (asc != null) { 36 | this.asc = asc; 37 | } 38 | } 39 | 40 | public String getSortQuery() { 41 | return sortQuery; 42 | } 43 | 44 | public int getColumn() { 45 | return column; 46 | } 47 | 48 | public boolean isAsc() { 49 | return asc; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/reader/core/util/sanitizer/TextSanitizer.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.util.sanitizer; 2 | 3 | import java.util.regex.Pattern; 4 | 5 | import org.owasp.html.HtmlPolicyBuilder; 6 | import org.owasp.html.PolicyFactory; 7 | 8 | /** 9 | * Sanitize some HTML text contents. Removes all elements, converts HTML entities to unicode. 10 | * 11 | * @author jtremeaux 12 | */ 13 | public class TextSanitizer { 14 | private final static PolicyFactory policy = new HtmlPolicyBuilder().toFactory(); 15 | private final static Pattern TAG_PATTERN = Pattern.compile("<.+>"); 16 | 17 | /** 18 | * Sanitize title contents. 19 | * 20 | * @param html HTML to sanitize 21 | * @return Sanitized HTML 22 | */ 23 | public static String sanitize(String html) { 24 | final String safeHtml = policy.sanitize(html); 25 | return TAG_PATTERN.matcher(safeHtml).replaceAll(""); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/util/MessageUtil.java: -------------------------------------------------------------------------------- 1 | package com.sismics.util; 2 | 3 | import java.text.MessageFormat; 4 | import java.util.Locale; 5 | import java.util.MissingResourceException; 6 | import java.util.ResourceBundle; 7 | 8 | /** 9 | * Message utilities. 10 | * 11 | * @author jtremeaux 12 | */ 13 | public class MessageUtil { 14 | /** 15 | * Returns a message formated in the specified locale. 16 | * Returns **key** if no message is set for this key. 17 | * 18 | * @param locale Locale 19 | * @param key Message key 20 | * @param args Arguments of the message 21 | * @return Formated message 22 | */ 23 | public static String getMessage(Locale locale, String key, Object... args) { 24 | ResourceBundle resources = ResourceBundle.getBundle("messages", locale); 25 | String message = null; 26 | try { 27 | message = resources.getString(key); 28 | } catch (MissingResourceException e) { 29 | message = "**" + key + "**"; 30 | } 31 | return MessageFormat.format(message, args); 32 | } 33 | 34 | /** 35 | * Returns the resource bundle containing messages for the locale. 36 | * 37 | * @param locale Locale to use 38 | * @return Resource bundle 39 | */ 40 | public static ResourceBundle getMessage(Locale locale) { 41 | return ResourceBundle.getBundle("messages", locale); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/util/adblock/Helper.java: -------------------------------------------------------------------------------- 1 | package com.sismics.util.adblock; 2 | 3 | import java.io.File; 4 | import java.net.URL; 5 | import java.nio.file.Files; 6 | import java.nio.file.Path; 7 | import java.nio.file.Paths; 8 | import java.util.TimerTask; 9 | 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import com.google.common.base.Charsets; 14 | import com.google.common.io.Resources; 15 | 16 | public class Helper { 17 | 18 | private static final Logger log = LoggerFactory.getLogger(Helper.class); 19 | 20 | private JSEngine js; 21 | 22 | public Helper(JSEngine js) { 23 | this.js = js; 24 | } 25 | 26 | public void log(Object msg) { 27 | log.debug(msg.toString()); 28 | } 29 | 30 | public void load(String path) throws Exception { 31 | URL url = Resources.getResource("adblock" + File.separator + "js" + File.separator + path); 32 | js.evaluate(Resources.toString(url, Charsets.UTF_8)); 33 | } 34 | 35 | public boolean fileExists(String stringPath) { 36 | Path path = Paths.get(stringPath); 37 | return Files.exists(path); 38 | } 39 | 40 | public boolean canAutoupdate() { 41 | return true; 42 | } 43 | 44 | public TimerTask timerTask(final Runnable runnable) { 45 | return new TimerTask() { 46 | @Override 47 | public void run() { 48 | runnable.run(); 49 | } 50 | }; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/util/adblock/JSEngine.java: -------------------------------------------------------------------------------- 1 | package com.sismics.util.adblock; 2 | 3 | import javax.script.ScriptEngine; 4 | import javax.script.ScriptEngineManager; 5 | import javax.script.ScriptException; 6 | 7 | public class JSEngine { 8 | 9 | private ScriptEngine engine; 10 | 11 | public JSEngine() { 12 | ScriptEngineManager manager = new ScriptEngineManager(); 13 | engine = manager.getEngineByName("JavaScript"); 14 | } 15 | 16 | public Object evaluate(String script) throws ScriptException { 17 | return engine.eval(script); 18 | } 19 | 20 | public void put(String key, Object value) { 21 | engine.put(key, value); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/util/adblock/Subscription.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Adblock Plus , 3 | * Copyright (C) 2006-2013 Eyeo GmbH 4 | * 5 | * Adblock Plus is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License version 3 as 7 | * published by the Free Software Foundation. 8 | * 9 | * Adblock Plus is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with Adblock Plus. If not, see . 16 | */ 17 | 18 | package com.sismics.util.adblock; 19 | 20 | public class Subscription { 21 | public String title; 22 | public String specialization; 23 | public String url; 24 | public String homepage; 25 | public String[] prefixes; 26 | public String author; 27 | } 28 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/util/cert/TrustAllManager.java: -------------------------------------------------------------------------------- 1 | package com.sismics.util.cert; 2 | 3 | import javax.net.ssl.X509TrustManager; 4 | import java.security.cert.CertificateException; 5 | import java.security.cert.X509Certificate; 6 | 7 | /** 8 | * A trust manager that trusts all certificates (unsecure). 9 | * 10 | * @author jtremeaux 11 | */ 12 | public class TrustAllManager implements X509TrustManager { 13 | @Override 14 | public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { 15 | // NOP 16 | } 17 | 18 | @Override 19 | public void checkServerTrusted(X509Certificate[] certs, String authType) { 20 | // NOP 21 | } 22 | 23 | @Override 24 | public X509Certificate[] getAcceptedIssuers() { 25 | return null; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/util/jpa/SessionUtil.java: -------------------------------------------------------------------------------- 1 | package com.sismics.util.jpa; 2 | 3 | import org.hibernate.Session; 4 | import org.hibernate.SessionFactory; 5 | import org.hibernate.ejb.HibernateEntityManagerFactory; 6 | 7 | /** 8 | * Hibernate session utilities. 9 | * 10 | * @author jtremeaux 11 | */ 12 | public final class SessionUtil { 13 | /** 14 | * Private constructor. 15 | */ 16 | private SessionUtil() { 17 | } 18 | 19 | /** 20 | * Returns an instance of the current session. 21 | * 22 | * @return Instance of the current session 23 | */ 24 | public static Session getCurrentSession() { 25 | SessionFactory sessionFactory = ((HibernateEntityManagerFactory) EMF.get()).getSessionFactory(); 26 | return sessionFactory.getCurrentSession(); 27 | } 28 | } -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/util/jpa/filter/FilterColumn.java: -------------------------------------------------------------------------------- 1 | package com.sismics.util.jpa.filter; 2 | 3 | /** 4 | * Filter to apply on a column. 5 | * 6 | * @author jtremeaux 7 | */ 8 | public abstract class FilterColumn { 9 | /** 10 | * Column to filter. 11 | */ 12 | protected String column; 13 | 14 | /** 15 | * Filter expression to apply. 16 | */ 17 | protected String filter; 18 | 19 | public FilterColumn(String column, String filter) { 20 | this.column = column; 21 | this.filter = filter; 22 | } 23 | 24 | public String getColumn() { 25 | return column; 26 | } 27 | 28 | public String getFilter() { 29 | return filter; 30 | } 31 | 32 | public abstract String getPredicate(); 33 | 34 | public abstract Object getParamValue(); 35 | 36 | public String getParamName() { 37 | return "filtercolumn_" + column; 38 | } 39 | 40 | public boolean hasParam() { 41 | return column != null; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/util/jpa/filter/FilterCriteria.java: -------------------------------------------------------------------------------- 1 | package com.sismics.util.jpa.filter; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * Filtering criteria of a query. 8 | * 9 | * @author jtremeaux 10 | */ 11 | public class FilterCriteria { 12 | /** 13 | * Columns to sort. 14 | */ 15 | private List filterColumnList = new ArrayList(); 16 | 17 | /** 18 | * Constructor of SortCriteria. 19 | * 20 | * @param filterColumnList List of sort columns 21 | */ 22 | public FilterCriteria(List filterColumnList) { 23 | this.filterColumnList = filterColumnList; 24 | } 25 | 26 | public List getFilterColumnList() { 27 | return filterColumnList; 28 | } 29 | } -------------------------------------------------------------------------------- /reader-core/src/main/java/com/sismics/util/mime/MimeType.java: -------------------------------------------------------------------------------- 1 | package com.sismics.util.mime; 2 | 3 | /** 4 | * A collection of MIME types. 5 | * 6 | * @author jtremeaux 7 | */ 8 | public class MimeType { 9 | 10 | public static final String IMAGE_X_ICON = "image/x-icon"; 11 | 12 | public static final String IMAGE_PNG = "image/png"; 13 | 14 | public static final String IMAGE_JPEG = "image/jpeg"; 15 | 16 | public static final String IMAGE_GIF = "image/gif"; 17 | 18 | public static final String APPLICATION_ZIP = "application/zip"; 19 | } 20 | -------------------------------------------------------------------------------- /reader-core/src/main/resources/META-INF/persistence.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | org.hibernate.ejb.HibernatePersistence 8 | 9 | com.sismics.reader.core.model.jpa.Article 10 | com.sismics.reader.core.model.jpa.AuthenticationToken 11 | com.sismics.reader.core.model.jpa.BaseFunction 12 | com.sismics.reader.core.model.jpa.Category 13 | com.sismics.reader.core.model.jpa.Config 14 | com.sismics.reader.core.model.jpa.Feed 15 | com.sismics.reader.core.model.jpa.FeedSubscription 16 | com.sismics.reader.core.model.jpa.FeedSynchronization 17 | com.sismics.reader.core.model.jpa.Job 18 | com.sismics.reader.core.model.jpa.JobEvent 19 | com.sismics.reader.core.model.jpa.Locale 20 | com.sismics.reader.core.model.jpa.User 21 | com.sismics.reader.core.model.jpa.UserArticle 22 | com.sismics.reader.core.model.jpa.RoleBaseFunction 23 | 24 | -------------------------------------------------------------------------------- /reader-core/src/main/resources/db/update/dbupdate-001-0.sql: -------------------------------------------------------------------------------- 1 | alter table T_FEED add column FED_RSSBASEURI_C varchar(2000); 2 | alter table T_ARTICLE add column ART_BASEURI_C varchar(2000); 3 | create cached table T_JOB (JOB_ID_C varchar(36) not null, JOB_IDUSER_C varchar(36), JOB_NAME_C varchar(50) not null, JOB_CREATEDATE_D datetime not null, JOB_STARTDATE_D datetime, JOB_ENDDATE_D datetime, JOB_DELETEDATE_D datetime, primary key (JOB_ID_C)); 4 | create cached table T_JOB_EVENT ( JOE_ID_C varchar(36) not null, JOE_IDJOB_C varchar(36), JOE_NAME_C varchar(50) not null, JOE_VALUE_C varchar(250), JOE_CREATEDATE_D datetime not null, JOE_DELETEDATE_D datetime, primary key (JOE_ID_C)); 5 | alter table T_JOB add constraint FK_JOB_IDUSER_C foreign key (JOB_IDUSER_C) references T_USER (USE_ID_C) on delete restrict on update restrict; 6 | alter table T_JOB_EVENT add constraint FK_JOE_IDJOB_C foreign key (JOE_IDJOB_C) references T_JOB (JOB_ID_C) on delete restrict on update restrict; 7 | create index IDX_ART_PUBLICATIONDATE_D on T_ARTICLE (ART_PUBLICATIONDATE_D, ART_ID_C); 8 | create index IDX_USA_STARREDDATE_D on T_USER_ARTICLE (USA_STARREDDATE_D, USA_ID_C); 9 | update T_CONFIG set CFG_VALUE_C='1' where CFG_ID_C='DB_VERSION'; 10 | -------------------------------------------------------------------------------- /reader-core/src/main/resources/db/update/dbupdate-002-0.sql: -------------------------------------------------------------------------------- 1 | alter table T_USER add column USE_NARROWARTICLE_B bit default 0 not null; 2 | update T_CONFIG set CFG_VALUE_C='2' where CFG_ID_C='DB_VERSION'; 3 | -------------------------------------------------------------------------------- /reader-core/src/main/resources/db/update/dbupdate-003-0.sql: -------------------------------------------------------------------------------- 1 | alter table T_FEED_SUBSCRIPTION add column FES_UNREADCOUNT_N int default 0 not null; 2 | update T_FEED_SUBSCRIPTION set FES_UNREADCOUNT_N=(select count(a.ART_ID_C) from T_USER_ARTICLE ua join T_ARTICLE a on ua.USA_IDARTICLE_C = a.ART_ID_C where a.ART_IDFEED_C = FES_IDFEED_C and a.ART_DELETEDATE_D is null and ua.USA_READDATE_D is null and ua.USA_DELETEDATE_D is null and ua.USA_IDUSER_C = FES_IDUSER_C); 3 | update T_CONFIG set CFG_VALUE_C='3' where CFG_ID_C='DB_VERSION'; 4 | -------------------------------------------------------------------------------- /reader-core/src/main/resources/db/update/dbupdate-004-0.sql: -------------------------------------------------------------------------------- 1 | update T_USER set USE_THEME_C = 'default' where USE_THEME_C = 'default.less'; 2 | update T_USER set USE_THEME_C = 'highcontrast' where USE_THEME_C = 'highcontrast.less'; 3 | update T_CONFIG set CFG_VALUE_C='4' where CFG_ID_C='DB_VERSION'; 4 | -------------------------------------------------------------------------------- /reader-core/src/main/resources/db/update/dbupdate-005-0.sql: -------------------------------------------------------------------------------- 1 | create index IDX_USA_READDATE_D on T_USER_ARTICLE (USA_READDATE_D, USA_ID_C); 2 | create cached table T_FEED_SYNCHRONIZATION ( FSY_ID_C varchar(36) not null, FSY_IDFEED_C varchar(36) not null, FSY_SUCCESS_B bit not null, FSY_MESSAGE_C longvarchar, FSY_DURATION_N int not null, FSY_CREATEDATE_D datetime not null, primary key (FSY_ID_C) ); 3 | alter table T_FEED_SYNCHRONIZATION add constraint FK_FSY_IDFEED_C foreign key (FSY_IDFEED_C) references T_FEED (FED_ID_C) on delete restrict on update restrict; 4 | create index IDX_FSY_CREATEDATE_D on T_FEED_SYNCHRONIZATION (FSY_IDFEED_C, FSY_CREATEDATE_D); 5 | update T_CONFIG set CFG_VALUE_C='5' where CFG_ID_C='DB_VERSION'; 6 | -------------------------------------------------------------------------------- /reader-core/src/main/resources/db/update/dbupdate-006-0.sql: -------------------------------------------------------------------------------- 1 | create index FK_ART_IDFEED_C on T_ARTICLE (ART_IDFEED_C); 2 | create index FK_AUT_IDUSER_C on T_AUTHENTICATION_TOKEN (AUT_IDUSER_C); 3 | create index FK_USA_IDARTICLE_C on T_USER_ARTICLE (USA_IDARTICLE_C); 4 | create index FK_USA_IDUSER_C on T_USER_ARTICLE (USA_IDUSER_C); 5 | create index FK_USE_IDROLE_C on T_USER (USE_IDROLE_C); 6 | create index FK_USE_IDLOCALE_C on T_USER (USE_IDLOCALE_C); 7 | create index FK_RBF_IDBASEFUNCTION_C on T_ROLE_BASE_FUNCTION (RBF_IDBASEFUNCTION_C); 8 | create index FK_RBF_IDROLE_C on T_ROLE_BASE_FUNCTION (RBF_IDROLE_C); 9 | create index FK_JOE_IDJOB_C on T_JOB_EVENT (JOE_IDJOB_C); 10 | create index FK_JOB_IDUSER_C on T_JOB (JOB_IDUSER_C); 11 | create index FK_FES_IDCATEGORY_C on T_FEED_SUBSCRIPTION (FES_IDCATEGORY_C); 12 | create index FK_FES_IDFEED_C on T_FEED_SUBSCRIPTION (FES_IDFEED_C); 13 | create index FK_FES_IDUSER_C on T_FEED_SUBSCRIPTION (FES_IDUSER_C); 14 | create index FK_CAT_IDPARENT_C on T_CATEGORY (CAT_IDPARENT_C); 15 | create index FK_CAT_IDUSER_C on T_CATEGORY (CAT_IDUSER_C); 16 | update T_CONFIG set CFG_VALUE_C='6' where CFG_ID_C='DB_VERSION'; -------------------------------------------------------------------------------- /reader-core/src/main/resources/messages.properties: -------------------------------------------------------------------------------- 1 | reader.export.title={0}''s subscriptions in Sismics Reader 2 | -------------------------------------------------------------------------------- /reader-core/src/main/resources/messages_fr.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /reader-core/src/test/java/com/sismics/reader/BaseTransactionalTest.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader; 2 | 3 | import javax.persistence.EntityManager; 4 | import javax.persistence.EntityTransaction; 5 | 6 | import org.junit.After; 7 | import org.junit.Before; 8 | 9 | import com.sismics.util.context.ThreadLocalContext; 10 | import com.sismics.util.jpa.EMF; 11 | 12 | /** 13 | * Base class of tests with a transactional context. 14 | * 15 | * @author jtremeaux 16 | */ 17 | public abstract class BaseTransactionalTest { 18 | @Before 19 | public void setUp() throws Exception { 20 | // Initialize the entity manager 21 | EntityManager em = EMF.get().createEntityManager(); 22 | ThreadLocalContext context = ThreadLocalContext.get(); 23 | context.setEntityManager(em); 24 | EntityTransaction tx = em.getTransaction(); 25 | tx.begin(); 26 | } 27 | 28 | @After 29 | public void tearDown() throws Exception { 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /reader-core/src/test/java/com/sismics/reader/core/dao/file/html/TestFaviconExtractor.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.dao.file.html; 2 | 3 | import com.sismics.reader.core.util.http.ReaderHttpClient; 4 | import org.junit.Test; 5 | 6 | import java.io.InputStream; 7 | import java.net.URL; 8 | 9 | import static junit.framework.Assert.assertTrue; 10 | 11 | /** 12 | * Test of the favicon extractor. 13 | * 14 | * @author jtremeaux 15 | */ 16 | public class TestFaviconExtractor { 17 | @Test 18 | public void faviconExtractorSismicsTest() throws Exception { 19 | final FaviconExtractor extractor = new FaviconExtractor("https://www.sismics.com/"); 20 | new ReaderHttpClient() { 21 | 22 | @Override 23 | public Void process(InputStream is) throws Exception { 24 | extractor.readPage(is); 25 | return null; 26 | } 27 | }.open(new URL("https://www.sismics.com")); 28 | assertTrue(extractor.getFavicon().contains("/public/img/favicon.png")); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /reader-core/src/test/java/com/sismics/reader/core/dao/jpa/TestJpa.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.core.dao.jpa; 2 | 3 | import com.sismics.reader.BaseTransactionalTest; 4 | import com.sismics.reader.core.model.jpa.User; 5 | import com.sismics.reader.core.util.TransactionUtil; 6 | import org.junit.Test; 7 | 8 | import static junit.framework.Assert.assertEquals; 9 | import static junit.framework.Assert.assertNotNull; 10 | 11 | /** 12 | * Tests the persistance layer. 13 | * 14 | * @author jtremeaux 15 | */ 16 | public class TestJpa extends BaseTransactionalTest { 17 | @Test 18 | public void testJpa() throws Exception { 19 | // Create a user 20 | UserDao userDao = new UserDao(); 21 | User user = new User(); 22 | user.setUsername("username"); 23 | user.setEmail("toto@reader.com"); 24 | user.setLocaleId("fr_FR"); 25 | user.setRoleId("user"); 26 | String id = userDao.create(user); 27 | 28 | TransactionUtil.commit(); 29 | 30 | // Search a user by his ID 31 | user = userDao.getById(id); 32 | assertNotNull(user); 33 | assertEquals("toto@reader.com", user.getEmail()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /reader-core/src/test/java/com/sismics/util/TestAdblockUtil.java: -------------------------------------------------------------------------------- 1 | package com.sismics.util; 2 | 3 | import com.sismics.util.adblock.Subscription; 4 | import org.junit.Ignore; 5 | import org.junit.Test; 6 | 7 | @Ignore 8 | public class TestAdblockUtil { 9 | 10 | @Test 11 | public void test() throws Exception { 12 | AdblockUtil adblock = new AdblockUtil(); 13 | adblock.start(); 14 | Subscription subscription = adblock.offerSubscription(); 15 | adblock.setSubscription(subscription); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /reader-core/src/test/java/com/sismics/util/TestCertUtil.java: -------------------------------------------------------------------------------- 1 | package com.sismics.util; 2 | 3 | import com.sismics.reader.core.util.http.ReaderHttpClient; 4 | import com.sismics.util.cert.CertUtil; 5 | import org.junit.Ignore; 6 | import org.junit.Test; 7 | 8 | import java.io.InputStream; 9 | import java.net.URL; 10 | 11 | import static junit.framework.Assert.fail; 12 | 13 | /** 14 | * Test of the certificate utilities. 15 | * 16 | * @author jtremeaux 17 | */ 18 | @Ignore 19 | public class TestCertUtil { 20 | 21 | @Test 22 | public void sslFailTest() throws Exception { 23 | // This fails at the time of test, due to Startcom certificate not included in the JDK 24 | // javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: 25 | // sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 26 | try { 27 | CertUtil.testSsl("lescastcodeurs.com", 443); 28 | fail(); 29 | } catch (Exception e) { 30 | // NOP 31 | } 32 | } 33 | 34 | @Test 35 | public void sslTrustAllCertificateTest() throws Exception { 36 | new ReaderHttpClient() { 37 | @Override 38 | public Void process(InputStream is) throws Exception { 39 | return null; 40 | } 41 | }.open(new URL("https://lescastcodeurs.com")); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /reader-core/src/test/java/com/sismics/util/TestDateUtil.java: -------------------------------------------------------------------------------- 1 | package com.sismics.util; 2 | 3 | import com.sismics.reader.core.dao.file.rss.RssReader; 4 | import org.junit.Test; 5 | 6 | import static junit.framework.Assert.assertEquals; 7 | import static junit.framework.Assert.assertNotNull; 8 | 9 | /** 10 | * Test of the date utilities. 11 | * 12 | * @author jtremeaux 13 | */ 14 | public class TestDateUtil { 15 | 16 | @Test 17 | public void guessTimezoneCodeTest() throws Exception { 18 | assertEquals("Thu, 04 APR 2013 20:37:27 +10", DateUtil.guessTimezoneOffset("Thu, 04 APR 2013 20:37:27 AEST")); 19 | } 20 | 21 | @Test 22 | public void parseDateTest() throws Exception { 23 | assertNotNull(DateUtil.parseDate("Fri Jan 06 2017 16:13:28 GMT+0900 (JST)", RssReader.DF_RSS)); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /reader-core/src/test/java/com/sismics/util/TestNetworkUtil.java: -------------------------------------------------------------------------------- 1 | package com.sismics.util; 2 | 3 | import org.junit.Ignore; 4 | import org.junit.Test; 5 | 6 | import static junit.framework.Assert.assertTrue; 7 | 8 | /** 9 | * Test of the network utilities. 10 | * 11 | * @author bgamard 12 | */ 13 | public class TestNetworkUtil { 14 | 15 | @Test 16 | @Ignore 17 | public void testUpnp() throws Exception { 18 | assertTrue(NetworkUtil.mapTcpPort(4040)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /reader-core/src/test/java/com/sismics/util/TestResourceUtil.java: -------------------------------------------------------------------------------- 1 | package com.sismics.util; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import static junit.framework.Assert.assertNotNull; 9 | import static junit.framework.Assert.assertTrue; 10 | 11 | /** 12 | * Test of the resource utils. 13 | * 14 | * @author jtremeaux 15 | */ 16 | public class TestResourceUtil { 17 | 18 | @Test 19 | public void listFilesTest() throws Exception { 20 | List fileList = ResourceUtil.list(Test.class, "/junit/framework"); 21 | assertTrue(fileList.contains("Test.class")); 22 | 23 | fileList = ResourceUtil.list(Test.class, "/junit/framework/"); 24 | assertTrue(fileList.contains("Test.class")); 25 | 26 | fileList = ResourceUtil.list(Test.class, "junit/framework/"); 27 | assertTrue(fileList.contains("Test.class")); 28 | 29 | fileList = ResourceUtil.list(Test.class, "junit/framework/"); 30 | assertTrue(fileList.contains("Test.class")); 31 | } 32 | 33 | @Test 34 | public void loadResourceFileTest() { 35 | Map properties = ResourceUtil.loadPropertiesFromUrl(TestResourceUtil.class.getResource("/config.properties")); 36 | assertNotNull(properties); 37 | assertTrue(properties.size() > 0); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /reader-core/src/test/java/com/sismics/util/TestTextSanitizer.java: -------------------------------------------------------------------------------- 1 | package com.sismics.util; 2 | 3 | import com.sismics.reader.core.util.sanitizer.TextSanitizer; 4 | import org.junit.Test; 5 | 6 | import static junit.framework.Assert.assertEquals; 7 | 8 | /** 9 | * Test of the text sanitizer. 10 | * 11 | * @author jtremeaux 12 | */ 13 | public class TestTextSanitizer { 14 | /** 15 | * Tests the text sanitizer. 16 | * 17 | */ 18 | @Test 19 | public void textSanitizerTest() throws Exception { 20 | assertEquals("", TextSanitizer.sanitize(null)); 21 | assertEquals("Test title", TextSanitizer.sanitize("Test title")); 22 | assertEquals("Test title", TextSanitizer.sanitize("Test
title
")); 23 | assertEquals("Test title — a title", TextSanitizer.sanitize("Test title — a title")); 24 | assertEquals("Weirdest DLC Sponsorship Ever: SimCity, Brought To You By Crest", TextSanitizer.sanitize("Weirdest DLC Sponsorship Ever: SimCity</em>, Brought To You By Crest")); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /reader-core/src/test/resources/config.properties: -------------------------------------------------------------------------------- 1 | api.current_version=${project.version} 2 | api.min_version=1.0 3 | db.version=6 -------------------------------------------------------------------------------- /reader-core/src/test/resources/feed/feed_error_toomanyfatalerror.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Le Messager 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /reader-core/src/test/resources/feed/feed_rdf_autostrip.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-core/src/test/resources/feed/feed_rdf_autostrip.xml -------------------------------------------------------------------------------- /reader-core/src/test/resources/feed/feed_rss2_gizmodo.gzip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-core/src/test/resources/feed/feed_rss2_gizmodo.gzip -------------------------------------------------------------------------------- /reader-core/src/test/resources/feed/feed_rss2_ibox.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-core/src/test/resources/feed/feed_rss2_ibox.xml -------------------------------------------------------------------------------- /reader-core/src/test/resources/feed/feed_rss2_lemessager.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-core/src/test/resources/feed/feed_rss2_lemessager.xml -------------------------------------------------------------------------------- /reader-core/src/test/resources/feed/feed_rss2_maliki.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-core/src/test/resources/feed/feed_rss2_maliki.xml -------------------------------------------------------------------------------- /reader-core/src/test/resources/hibernate.properties: -------------------------------------------------------------------------------- 1 | hibernate.connection.driver_class=org.hsqldb.jdbcDriver 2 | hibernate.connection.url=jdbc:hsqldb:mem:reader 3 | hibernate.connection.username=sa 4 | hibernate.connection.password= 5 | hibernate.dialect=org.hibernate.dialect.HSQLDialect 6 | hibernate.show_sql=true 7 | hibernate.format_sql=false 8 | hibernate.max_fetch_depth=5 9 | hibernate.cache.use_second_level_cache=false 10 | -------------------------------------------------------------------------------- /reader-core/src/test/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootCategory=DEBUG, CONSOLE, MEMORY 2 | log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender 3 | log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout 4 | log4j.appender.CONSOLE.layout.ConversionPattern=%d{DATE} %p %l %m %n 5 | log4j.appender.MEMORY=com.sismics.util.log4j.MemoryAppender 6 | log4j.appender.MEMORY.size=1000 7 | 8 | log4j.logger.com.sismics=DEBUG 9 | -------------------------------------------------------------------------------- /reader-core/src/test/resources/opml/greader_subscriptions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Abonnements de Naku dans Google Reader 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /reader-core/src/test/resources/opml/liferea_subscriptions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Liferea Feed List Export 5 | 6 | 7 | 9 | 13 | 16 | 20 | 24 | 27 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /reader-core/src/test/resources/opml/ttrss_subscriptions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Sat, 22 Feb 2014 23:02:45 +0000 5 | Tiny Tiny RSS Feed Export 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /reader-distribution-debian/src/main/deb/control/conffiles: -------------------------------------------------------------------------------- 1 | /etc/default/reader 2 | 3 | -------------------------------------------------------------------------------- /reader-distribution-debian/src/main/deb/control/control: -------------------------------------------------------------------------------- 1 | Package: reader 2 | Version: ${project.version} 3 | Section: net 4 | Priority: optional 5 | Architecture: all 6 | Description: Reader is a Web-based aggregator of content served by Web Feeds. 7 | . 8 | Java 8 or higher is required to run Reader. 9 | . 10 | More information can be found at http://www.sismics.com/reader/ 11 | Maintainer: Jean-Marc Tremeaux 12 | -------------------------------------------------------------------------------- /reader-distribution-debian/src/main/deb/control/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | ln -sf /usr/share/reader/reader.sh /usr/bin/reader 6 | 7 | mkdir -p /var/reader 8 | chmod 750 /var/reader 9 | 10 | # Clear jetty cache. 11 | rm -rf /var/reader/jetty 12 | 13 | # Configure Reader service. 14 | update-rc.d reader defaults 99 15 | 16 | # Start Reader service. 17 | invoke-rc.d reader start 18 | -------------------------------------------------------------------------------- /reader-distribution-debian/src/main/deb/control/postrm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | # Remove symlink. 6 | rm -f /usr/bin/reader 7 | 8 | # Remove startup scripts. 9 | update-rc.d -f reader remove 10 | -------------------------------------------------------------------------------- /reader-distribution-debian/src/main/deb/control/preinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | # Stop Reader service. 6 | if [ -e /etc/init.d/reader ]; then 7 | invoke-rc.d reader stop 8 | fi 9 | 10 | # Backup database. 11 | if [ -e /var/reader/db ]; then 12 | rm -rf /var/reader/db.backup 13 | cp -R /var/reader/db /var/reader/db.backup 14 | fi 15 | -------------------------------------------------------------------------------- /reader-distribution-debian/src/main/deb/control/prerm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | # Stop Reader service. 6 | if [ -e /etc/init.d/reader ]; then 7 | invoke-rc.d reader stop 8 | fi 9 | -------------------------------------------------------------------------------- /reader-distribution-debian/src/main/package/etc/default/reader: -------------------------------------------------------------------------------- 1 | # 2 | # This is the configuration file for the Sismics Reader service 3 | # (/etc/init.d/reader) 4 | # 5 | # To change the startup parameters of Reader, modify 6 | # the READER_ARGS variable below. 7 | # 8 | # Type "reader --help" on the command line to read an 9 | # explanation of the different options. 10 | # 11 | # For example, to specify that Reader should use port 80 (for http) 12 | # and use a Java memory heap size of 200 MB, use the following: 13 | # 14 | # READER_ARGS="--port=80 --max-memory=200" 15 | 16 | READER_ARGS="--max-memory=150" 17 | 18 | 19 | # The user which should run the Reader process. Default "root". 20 | # Note that non-root users are by default not allowed to use ports 21 | # below 1024. Also make sure to grant the user write permissions in 22 | # the /var/reader directory, otherwise starting Reader will fail. 23 | 24 | READER_USER=root -------------------------------------------------------------------------------- /reader-distribution-debian/src/main/package/usr/share/doc/reader/README: -------------------------------------------------------------------------------- 1 | What is Reader? 2 | --------------- 3 | 4 | Reader is an open source, Web-based aggregator of content served by Web Feeds (RSS, Atom). 5 | 6 | Reader is written in Java, and may be run on any operating system with Java support. 7 | 8 | See for a list of features and benefits. 9 | 10 | Requirements: 11 | ------------- 12 | 13 | * Java Runtime Environment (JRE) 8 or greater 14 | 15 | Reporting issues: 16 | --------------- 17 | 18 | Issues should be reported to the GitHub project page . 19 | 20 | -------------------------------------------------------------------------------- /reader-distribution-debian/src/main/package/usr/share/doc/reader/copyright: -------------------------------------------------------------------------------- 1 | == Reader == 2 | 3 | This package of Reader was debianized on ${timestamp} 4 | by Jean-Marc Tremeaux . 5 | 6 | It can be downloaded from . 7 | 8 | Copyright holders and authors: 9 | (C) 2013-2018 Jean-Marc Tremeaux 10 | (C) 2013-2018 Benjamin Gamard 11 | 12 | This package is free software; you can redistribute it and/or modify 13 | it under the terms of the GNU General Public License as published by 14 | the Free Software Foundation; either version 2 of the License, or 15 | (at your option) any later version. 16 | 17 | This package is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU General Public License for more details. 21 | 22 | You should have received a copy of the GNU General Public License 23 | along with this package; if not, write to the Free Software 24 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 25 | 26 | On Debian systems, the complete text of the GNU General 27 | Public License can be found in `/usr/share/common-licenses/GPL'. 28 | -------------------------------------------------------------------------------- /reader-distribution-docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM sismics/jetty:9.3.11 2 | MAINTAINER benjamin.gam@gmail.com 3 | 4 | ADD reader-web/target/reader-web-*.war /opt/jetty/webapps/reader.war 5 | ADD reader.xml /opt/jetty/webapps/reader.xml 6 | -------------------------------------------------------------------------------- /reader-distribution-docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | web: 4 | image: sismics/reader:latest 5 | restart: always 6 | ports: 7 | - 8123:8080 8 | links: 9 | - db 10 | volumes: 11 | - data:/data 12 | network_mode: bridge 13 | db: 14 | image: sismics/hsqldb:2.3.0 15 | restart: always 16 | hostname: sismics_reader_hsqldb 17 | environment: 18 | - DB_NAME=reader 19 | volumes: 20 | - hsqldb_data:/data 21 | network_mode: bridge 22 | 23 | volumes: 24 | data: 25 | hsqldb_data: 26 | -------------------------------------------------------------------------------- /reader-distribution-mac/src/main/osxappbundle/JavaApplicationStub: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-distribution-mac/src/main/osxappbundle/JavaApplicationStub -------------------------------------------------------------------------------- /reader-distribution-mac/src/main/osxappbundle/reader-512.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-distribution-mac/src/main/osxappbundle/reader-512.icns -------------------------------------------------------------------------------- /reader-distribution-redhat/src/main/package/etc/sysconfig/reader: -------------------------------------------------------------------------------- 1 | # 2 | # This is the configuration file for the Sismics Reader service 3 | # (/etc/init.d/reader) 4 | # 5 | # To change the startup parameters of Reader, modify 6 | # the READER_ARGS variable below. 7 | # 8 | # Type "reader --help" on the command line to read an 9 | # explanation of the different options. 10 | # 11 | # For example, to specify that Reader should use port 80 (for http) 12 | # and use a Java memory heap size of 200 MB, use the following: 13 | # 14 | # READER_ARGS="--port=80 --max-memory=200" 15 | 16 | READER_ARGS="--max-memory=150" 17 | 18 | 19 | # The user which should run the Reader process. Default "root". 20 | # Note that non-root users are by default not allowed to use ports 21 | # below 1024. Also make sure to grant the user write permissions in 22 | # the music directories, otherwise changing album art and tags will fail. 23 | 24 | READER_USER=root -------------------------------------------------------------------------------- /reader-distribution-redhat/src/main/rpm/script/postinstall: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | mkdir -p /var/reader 4 | ln -sf /usr/share/reader/reader.sh /usr/bin/reader 5 | chmod 750 /var/reader 6 | 7 | # Clear jetty cache. 8 | rm -rf /var/reader/jetty 9 | 10 | # For SELinux: Set security context 11 | chcon -t java_exec_t /etc/init.d/reader 2>/dev/null 12 | 13 | # Configure and start Reader service. 14 | chkconfig --add reader 15 | service reader start 16 | 17 | exit 0 18 | -------------------------------------------------------------------------------- /reader-distribution-redhat/src/main/rpm/script/preinstall: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Stop Reader service. 4 | if [ -e /etc/init.d/reader ]; then 5 | service reader stop 6 | fi 7 | 8 | # Backup database. 9 | if [ -e /var/reader/db ]; then 10 | rm -rf /var/reader/db.backup 11 | cp -R /var/reader/db /var/reader/db.backup 12 | fi 13 | 14 | exit 0 15 | -------------------------------------------------------------------------------- /reader-distribution-redhat/src/main/rpm/script/preremove: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Only do it if uninstalling, not upgrading. 4 | if [ $1 = 0 ] ; then 5 | # Stop the service. 6 | [ -e /etc/init.d/reader ] && service reader stop 7 | 8 | # Remove symlink. 9 | rm -f /usr/bin/reader 10 | 11 | # Remove startup scripts. 12 | chkconfig --del reader 13 | fi 14 | 15 | exit 0 16 | -------------------------------------------------------------------------------- /reader-distribution-standalone/src/main/assembly/dist.xml: -------------------------------------------------------------------------------- 1 | 2 | dist 3 | 4 | tar.gz 5 | 6 | 7 | 8 | target/${project.artifactId}-${project.version}-jar-with-dependencies.jar 9 | / 10 | reader-standalone.jar 11 | 12 | 13 | target/sismicsreader.war 14 | / 15 | 16 | 17 | src/main/assembly/reader.bat 18 | / 19 | 20 | 21 | src/main/assembly/reader.sh 22 | / 23 | unix 24 | 0755 25 | 26 | 27 | 28 | 29 | ${project.basedir}/src/main/resources 30 | 31 | * 32 | 33 | / 34 | 35 | 36 | -------------------------------------------------------------------------------- /reader-distribution-windows/src/main/launch4j/reader-16.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-distribution-windows/src/main/launch4j/reader-16.ico -------------------------------------------------------------------------------- /reader-distribution-windows/src/main/launch4j/reader-agent-elevated.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /reader-distribution-windows/src/main/launch4j/reader-agent-elevated.xml: -------------------------------------------------------------------------------- 1 | 2 | true 3 | gui 4 | reader-agent.jar 5 | ${project.build.directory}/reader-agent-elevated.exe 6 | Reader 7 | -elevated 8 | . 9 | normal 10 | http://www.java.com/download/ 11 | url 12 | false 13 | false 14 | ${basedir}/src/main/launch4j/reader-agent-elevated.manifest 15 | ${basedir}/src/main/launch4j/reader-16.ico 16 | 17 | com.sismics.reader.agent.ReaderAgent 18 | ./reader-agent-${project.version}-jar-with-dependencies.jar 19 | 20 | 21 | 22 | 1.6.0 23 | 24 | preferJre 25 | 512 26 | -XX:MaxPermSize=128M 27 | 28 | 29 | Startup error 30 | Bundled JRE error 31 | JRE version error 32 | Launcher error 33 | An application instance is already running. 34 | 35 | -------------------------------------------------------------------------------- /reader-distribution-windows/src/main/launch4j/reader-agent.properties: -------------------------------------------------------------------------------- 1 | reader.host=0.0.0.0 2 | reader.port=4001 3 | reader.context_path=/ 4 | -------------------------------------------------------------------------------- /reader-distribution-windows/src/main/launch4j/reader-agent.xml: -------------------------------------------------------------------------------- 1 | 2 | true 3 | gui 4 | reader-agent.jar 5 | ${project.build.directory}/reader-agent.exe 6 | Reader 7 | 8 | . 9 | normal 10 | http://www.java.com/download/ 11 | url 12 | false 13 | false 14 | ${basedir}/src/main/launch4j/reader-agent-elevated.manifest 15 | ${basedir}/src/main/launch4j/reader-16.ico 16 | 17 | com.sismics.reader.agent.ReaderAgent 18 | ./reader-agent-${project.version}-jar-with-dependencies.jar 19 | 20 | 21 | 22 | 1.6.0 23 | 24 | preferJre 25 | 512 26 | -XX:MaxPermSize=128M 27 | 28 | 29 | Startup error 30 | Bundled JRE error 31 | JRE version error 32 | Launcher error 33 | An application instance is already running. 34 | 35 | -------------------------------------------------------------------------------- /reader-distribution-windows/src/main/nsis/jre-7u21-windows-i586.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-distribution-windows/src/main/nsis/jre-7u21-windows-i586.exe -------------------------------------------------------------------------------- /reader-web-common/src/main/java/com/sismics/rest/exception/ForbiddenClientException.java: -------------------------------------------------------------------------------- 1 | package com.sismics.rest.exception; 2 | 3 | import org.codehaus.jettison.json.JSONException; 4 | import org.codehaus.jettison.json.JSONObject; 5 | 6 | import javax.ws.rs.WebApplicationException; 7 | import javax.ws.rs.core.Response; 8 | import javax.ws.rs.core.Response.Status; 9 | 10 | /** 11 | * Unauthorized access to the resource exception. 12 | * 13 | * @author jtremeaux 14 | */ 15 | public class ForbiddenClientException extends WebApplicationException { 16 | /** 17 | * Serial UID. 18 | */ 19 | private static final long serialVersionUID = 1L; 20 | 21 | /** 22 | * Constructor of ForbiddenClientException. 23 | * 24 | */ 25 | public ForbiddenClientException() throws JSONException { 26 | super(Response.status(Status.FORBIDDEN).entity(new JSONObject() 27 | .put("type", "ForbiddenError") 28 | .put("message", "You don't have access to this resource")).build()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /reader-web-common/src/main/java/com/sismics/rest/resource/GenericExceptionMapper.java: -------------------------------------------------------------------------------- 1 | package com.sismics.rest.resource; 2 | 3 | import javax.ws.rs.WebApplicationException; 4 | import javax.ws.rs.core.Response; 5 | import javax.ws.rs.ext.ExceptionMapper; 6 | import javax.ws.rs.ext.Provider; 7 | 8 | import org.codehaus.jettison.json.JSONException; 9 | import org.codehaus.jettison.json.JSONObject; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | /** 14 | * Generic exception mapper that transforms all unknown exception into ServerError. 15 | * 16 | * @author jtremeaux 17 | */ 18 | @Provider 19 | public class GenericExceptionMapper implements ExceptionMapper { 20 | /** 21 | * Logger. 22 | */ 23 | private static final Logger log = LoggerFactory.getLogger(GenericExceptionMapper.class); 24 | 25 | @Override 26 | public Response toResponse(Exception e) { 27 | if (e instanceof WebApplicationException) { 28 | return ((WebApplicationException) e).getResponse(); 29 | } 30 | 31 | log.error("Unknown error", e); 32 | 33 | JSONObject entity = new JSONObject(); 34 | try { 35 | entity.put("type", "UnknownError"); 36 | entity.put("message", "Unknown server error"); 37 | } catch (JSONException e2) { 38 | log.error("Error building response", e2); 39 | } 40 | 41 | return Response.status(Response.Status.INTERNAL_SERVER_ERROR) 42 | .entity(entity) 43 | .build(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /reader-web-common/src/main/java/com/sismics/rest/util/JsonUtil.java: -------------------------------------------------------------------------------- 1 | package com.sismics.rest.util; 2 | 3 | import org.codehaus.jettison.json.JSONArray; 4 | import org.codehaus.jettison.json.JSONException; 5 | import org.codehaus.jettison.json.JSONObject; 6 | 7 | /** 8 | * JSON utilities. 9 | * 10 | * @author jtremeaux 11 | */ 12 | public class JsonUtil { 13 | 14 | /** 15 | * Fix of {@see JsonObject.append()}, which seems to create nested arrays. 16 | * 17 | * @param o JSON Object 18 | * @param key Key containing the array of null 19 | * @param value Value to append 20 | * @return Updated object 21 | */ 22 | public static JSONObject append(JSONObject o, String key, JSONObject value) throws JSONException { 23 | Object prevValue = o.opt(key); 24 | if (prevValue == null) { 25 | o.put(key, new JSONArray().put(value)); 26 | } else if (!(prevValue instanceof JSONArray)){ 27 | throw new JSONException("JSONObject[" + key + "] is not a JSONArray."); 28 | } else { 29 | JSONArray newArray = new JSONArray(); 30 | JSONArray oldArray = ((JSONArray) prevValue); 31 | for (int i = 0; i < oldArray.length(); i++) { 32 | newArray.put(oldArray.get(i)); 33 | } 34 | newArray.put(value); 35 | o.put(key, newArray); 36 | } 37 | return o; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /reader-web-common/src/main/java/com/sismics/security/IPrincipal.java: -------------------------------------------------------------------------------- 1 | package com.sismics.security; 2 | 3 | import java.security.Principal; 4 | import java.util.Locale; 5 | 6 | import org.joda.time.DateTimeZone; 7 | 8 | /** 9 | * Interface of principals. 10 | * 11 | * @author jtremeaux 12 | */ 13 | public interface IPrincipal extends Principal { 14 | /** 15 | * Checks if the principal is anonymous. 16 | * 17 | * @return True if the principal is anonymous. 18 | */ 19 | boolean isAnonymous(); 20 | 21 | /** 22 | * Returns the ID of the connected user, or null if the user is anonymous 23 | * 24 | * @return ID of the connected user 25 | */ 26 | public String getId(); 27 | 28 | /** 29 | * Returns the locale of the principal. 30 | * 31 | * @return Locale of the principal 32 | */ 33 | public Locale getLocale(); 34 | 35 | /** 36 | * Returns the timezone of the principal. 37 | * 38 | * @return Timezone of the principal 39 | */ 40 | public DateTimeZone getDateTimeZone(); 41 | 42 | /** 43 | * Returns the email of the principal. 44 | * 45 | * @return Email of the principal 46 | */ 47 | public String getEmail(); 48 | } 49 | -------------------------------------------------------------------------------- /reader-web-common/src/main/java/com/sismics/util/filter/HeaderBasedSecurityFilter.java: -------------------------------------------------------------------------------- 1 | package com.sismics.util.filter; 2 | 3 | import com.sismics.reader.core.dao.jpa.UserDao; 4 | import com.sismics.reader.core.model.jpa.User; 5 | 6 | import javax.servlet.FilterConfig; 7 | import javax.servlet.ServletException; 8 | import javax.servlet.http.HttpServletRequest; 9 | 10 | /** 11 | * A header-based security filter that authenticates an user using the "X-Authenticated-User" request header as the user ID. 12 | * This filter is intended to be used in conjunction with an external authenticating proxy. 13 | * 14 | * @author pacien 15 | */ 16 | public class HeaderBasedSecurityFilter extends SecurityFilter { 17 | 18 | public static final String AUTHENTICATED_USER_HEADER = "X-Authenticated-User"; 19 | 20 | private boolean enabled; 21 | 22 | @Override 23 | public void init(FilterConfig filterConfig) throws ServletException { 24 | this.enabled = Boolean.parseBoolean(filterConfig.getInitParameter("enabled")) 25 | || Boolean.parseBoolean(System.getProperty("reader.header_authentication")); 26 | } 27 | 28 | @Override 29 | protected User authenticate(HttpServletRequest request) { 30 | if (!this.enabled) return null; 31 | 32 | String username = request.getHeader(AUTHENTICATED_USER_HEADER); 33 | return (new UserDao()).getActiveByUsername(username); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /reader-web-common/src/test/java/com/sismics/reader/rest/filter/CookieAuthenticationFilter.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.rest.filter; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import javax.ws.rs.core.Cookie; 7 | 8 | import com.sismics.util.filter.TokenBasedSecurityFilter; 9 | import com.sun.jersey.api.client.ClientHandlerException; 10 | import com.sun.jersey.api.client.ClientRequest; 11 | import com.sun.jersey.api.client.ClientResponse; 12 | import com.sun.jersey.api.client.filter.ClientFilter; 13 | 14 | /** 15 | * Filter to add the authentication token into a cookie. 16 | * 17 | * @author jtremeaux 18 | */ 19 | public class CookieAuthenticationFilter extends ClientFilter { 20 | private String authToken; 21 | 22 | public CookieAuthenticationFilter(String authToken) { 23 | this.authToken = authToken; 24 | } 25 | 26 | @Override 27 | public ClientResponse handle(ClientRequest request) throws ClientHandlerException { 28 | Cookie cookie = new Cookie(TokenBasedSecurityFilter.COOKIE_NAME, authToken); 29 | List cookieList = new ArrayList(); 30 | cookieList.add(cookie); 31 | if (authToken != null) { 32 | request.getHeaders().put("Cookie", cookieList); 33 | } 34 | ClientResponse response = getNext().handle(request); 35 | if (response.getCookies() != null) { 36 | cookieList.addAll(response.getCookies()); 37 | } 38 | return response; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /reader-web-common/src/test/java/com/sismics/reader/rest/util/TestValidationUtil.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.rest.util; 2 | 3 | import junit.framework.Assert; 4 | 5 | import org.junit.Test; 6 | 7 | import com.sismics.rest.exception.ClientException; 8 | import com.sismics.rest.util.ValidationUtil; 9 | 10 | /** 11 | * Test the validations. 12 | * 13 | * @author jtremeaux 14 | */ 15 | public class TestValidationUtil { 16 | @Test 17 | public void testValidateHttpUrlFail() throws Exception { 18 | ValidationUtil.validateHttpUrl("http://www.google.com", "url"); 19 | ValidationUtil.validateHttpUrl("https://www.google.com", "url"); 20 | ValidationUtil.validateHttpUrl(" https://www.google.com ", "url"); 21 | try { 22 | ValidationUtil.validateHttpUrl("ftp://www.google.com", "url"); 23 | Assert.fail(); 24 | } catch (ClientException e) { 25 | // NOP 26 | } 27 | try { 28 | ValidationUtil.validateHttpUrl("http://", "url"); 29 | Assert.fail(); 30 | } catch (ClientException e) { 31 | // NOP 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /reader-web/src/dev/main/webapp/web-override.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | default 11 | 12 | useFileMappedBuffer 13 | false 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /reader-web/src/dev/resources/hibernate.properties: -------------------------------------------------------------------------------- 1 | hibernate.connection.driver_class=org.hsqldb.jdbcDriver 2 | hibernate.connection.url=jdbc:hsqldb:mem:reader 3 | hibernate.connection.username=sa 4 | hibernate.connection.password= 5 | hibernate.dialect=org.hibernate.dialect.HSQLDialect 6 | hibernate.show_sql=false 7 | hibernate.format_sql=false 8 | hibernate.max_fetch_depth=5 9 | hibernate.cache.use_second_level_cache=false 10 | 11 | hibernate.c3p0.min_size=1 12 | hibernate.c3p0.max_size=30 13 | hibernate.c3p0.timeout=5000 14 | hibernate.c3p0.max_statements=0 15 | hibernate.c3p0.acquire_increment=3 16 | hibernate.c3p0.idle_test_period=10 17 | -------------------------------------------------------------------------------- /reader-web/src/dev/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootCategory=WARN, CONSOLE, MEMORY 2 | log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender 3 | log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout 4 | log4j.appender.CONSOLE.layout.ConversionPattern=%d{DATE} %p %l %m %n 5 | log4j.appender.MEMORY=com.sismics.util.log4j.MemoryAppender 6 | log4j.appender.MEMORY.size=1000 7 | 8 | log4j.logger.com.sismics=DEBUG 9 | -------------------------------------------------------------------------------- /reader-web/src/hosted/resources/hibernate.properties: -------------------------------------------------------------------------------- 1 | hibernate.connection.driver_class=org.hsqldb.jdbcDriver 2 | hibernate.connection.url=jdbc:hsqldb:hsql://sismics_reader_hsqldb/reader 3 | hibernate.connection.username=sa 4 | hibernate.connection.password= 5 | hibernate.dialect=org.hibernate.dialect.HSQLDialect 6 | hibernate.show_sql=false 7 | hibernate.format_sql=false 8 | hibernate.max_fetch_depth=5 9 | hibernate.cache.use_second_level_cache=false 10 | 11 | hibernate.c3p0.min_size=1 12 | hibernate.c3p0.max_size=30 13 | hibernate.c3p0.timeout=5000 14 | hibernate.c3p0.max_statements=0 15 | hibernate.c3p0.acquire_increment=3 16 | hibernate.c3p0.idle_test_period=10 17 | -------------------------------------------------------------------------------- /reader-web/src/hosted/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootCategory=WARN, CONSOLE, MEMORY 2 | log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender 3 | log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout 4 | log4j.appender.CONSOLE.layout.ConversionPattern=%d{DATE} %p %l %m %n 5 | log4j.appender.MEMORY=com.sismics.util.log4j.MemoryAppender 6 | log4j.appender.MEMORY.size=1000 7 | 8 | log4j.logger.com.sismics=INFO 9 | -------------------------------------------------------------------------------- /reader-web/src/main/java/com/sismics/reader/rest/constant/BaseFunction.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.rest.constant; 2 | 3 | /** 4 | * Base functions. 5 | * 6 | * @author jtremeaux 7 | */ 8 | public enum BaseFunction { 9 | 10 | /** 11 | * Allows the user to use the admin fonctions. 12 | */ 13 | ADMIN, 14 | 15 | /** 16 | * Allows the user to change his password. 17 | */ 18 | PASSWORD, 19 | 20 | /** 21 | * Allows the user to import OPML / Takeout data. 22 | */ 23 | IMPORT, 24 | } 25 | -------------------------------------------------------------------------------- /reader-web/src/main/java/com/sismics/reader/rest/resource/LocaleResource.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.rest.resource; 2 | 3 | import com.sismics.reader.core.dao.jpa.LocaleDao; 4 | import com.sismics.reader.core.model.jpa.Locale; 5 | import org.codehaus.jettison.json.JSONException; 6 | import org.codehaus.jettison.json.JSONObject; 7 | 8 | import javax.ws.rs.GET; 9 | import javax.ws.rs.Path; 10 | import javax.ws.rs.Produces; 11 | import javax.ws.rs.core.MediaType; 12 | import javax.ws.rs.core.Response; 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | /** 17 | * Locale REST resources. 18 | * 19 | * @author jtremeaux 20 | */ 21 | @Path("/locale") 22 | public class LocaleResource extends BaseResource { 23 | /** 24 | * Returns the list of all locales. 25 | * 26 | * @return Response 27 | */ 28 | @GET 29 | @Produces(MediaType.APPLICATION_JSON) 30 | public Response list() throws JSONException { 31 | LocaleDao localeDao = new LocaleDao(); 32 | List localeList = localeDao.findAll(); 33 | JSONObject response = new JSONObject(); 34 | List items = new ArrayList(); 35 | for (Locale locale : localeList) { 36 | JSONObject item = new JSONObject(); 37 | item.put("id", locale.getId()); 38 | items.add(item); 39 | } 40 | response.put("locales", items); 41 | return Response.ok().entity(response).build(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /reader-web/src/main/resources/config.properties: -------------------------------------------------------------------------------- 1 | api.current_version=${project.version} 2 | api.min_version=1.0 3 | db.version=6 -------------------------------------------------------------------------------- /reader-web/src/main/resources/image/subscription.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/resources/image/subscription.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules -------------------------------------------------------------------------------- /reader-web/src/main/webapp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sismics-reader", 3 | "description": "Free and open source feeds reader", 4 | "readme": "See http://github.com/simics/reader for more informations.", 5 | "version": "1.3.0", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/sismics/reader.git" 9 | }, 10 | "devDependencies": { 11 | "grunt": "~0.4.2", 12 | "grunt-cli": "~0.1.13", 13 | "grunt-contrib-uglify": "~0.3.2", 14 | "grunt-contrib-concat": "~0.3.0", 15 | "grunt-contrib-copy": "~0.5.0", 16 | "grunt-contrib-clean": "~0.5.0", 17 | "grunt-cleanempty": "~0.2.0", 18 | "grunt-htmlrefs": "~0.5.0", 19 | "grunt-css": "~0.5.4", 20 | "grunt-contrib-less": "~0.9.0", 21 | "grunt-remove": "~0.1.0", 22 | "grunt-text-replace": "~0.3.11" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/favicon.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/ajax-loader.gif -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/category.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/category.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/category_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/category_add.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/edit.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/error.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/external.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/external.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/full.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/jqueryui/animated-overlay.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/jqueryui/animated-overlay.gif -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/jqueryui/ui-bg_flat_0_aaaaaa_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/jqueryui/ui-bg_flat_0_aaaaaa_40x100.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/jqueryui/ui-bg_flat_75_ffffff_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/jqueryui/ui-bg_flat_75_ffffff_40x100.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/jqueryui/ui-bg_glass_55_fbf9ee_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/jqueryui/ui-bg_glass_55_fbf9ee_1x400.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/jqueryui/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/jqueryui/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/jqueryui/ui-bg_glass_75_dadada_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/jqueryui/ui-bg_glass_75_dadada_1x400.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/jqueryui/ui-bg_glass_75_e6e6e6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/jqueryui/ui-bg_glass_75_e6e6e6_1x400.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/jqueryui/ui-bg_glass_95_fef1ec_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/jqueryui/ui-bg_glass_95_fef1ec_1x400.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/jqueryui/ui-bg_highlight-soft_75_cccccc_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/jqueryui/ui-bg_highlight-soft_75_cccccc_1x100.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/jqueryui/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/jqueryui/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/jqueryui/ui-icons_2e83ff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/jqueryui/ui-icons_2e83ff_256x240.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/jqueryui/ui-icons_454545_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/jqueryui/ui-icons_454545_256x240.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/jqueryui/ui-icons_888888_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/jqueryui/ui-icons_888888_256x240.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/jqueryui/ui-icons_cd0a0a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/jqueryui/ui-icons_cd0a0a_256x240.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/list.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/loader.gif -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/mime/application.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/mime/application.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/mime/audio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/mime/audio.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/mime/font.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/mime/font.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/mime/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/mime/image.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/mime/package.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/mime/package.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/mime/text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/mime/text.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/mime/video.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/mime/video.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/narrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/narrow.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/nostar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/nostar.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/notice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/notice.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/read.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/read.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/refresh.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/rss_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/rss_icon.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/rssman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/rssman.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/search.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/settings.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/share/email.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/share/email.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/share/facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/share/facebook.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/share/googleplus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/share/googleplus.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/share/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/share/twitter.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/star.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/subscription.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/subscription.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/success.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/tree_minus.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/tree_minus.gif -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/tree_plus.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/tree_plus.gif -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/unread.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/unread.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/warning.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/images/wide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/images/wide.png -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/javascripts/jquery.throttle.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery throttle / debounce - v1.1 - 3/7/2010 3 | * http://benalman.com/projects/jquery-throttle-debounce-plugin/ 4 | * 5 | * Copyright (c) 2010 "Cowboy" Ben Alman 6 | * Dual licensed under the MIT and GPL licenses. 7 | * http://benalman.com/about/license/ 8 | */ 9 | (function(b,c){var $=b.jQuery||b.Cowboy||(b.Cowboy={}),a;$.throttle=a=function(e,f,j,i){var h,d=0;if(typeof f!=="boolean"){i=j;j=f;f=c}function g(){var o=this,m=+new Date()-d,n=arguments;function l(){d=+new Date();j.apply(o,n)}function k(){h=c}if(i&&!h){l()}h&&clearTimeout(h);if(i===c&&m>e){l()}else{if(f!==true){h=setTimeout(i?k:l,i===c?e-m:e)}}}if($.guid){g.guid=j.guid=j.guid||$.guid++}return g};$.debounce=function(d,e,f){return f===c?a(d,e,false):a(d,f,e!==false)}})(this); -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/javascripts/jquery.visible.js: -------------------------------------------------------------------------------- 1 | (function($){ 2 | 3 | /** 4 | * Copyright 2012, Digital Fusion 5 | * Licensed under the MIT license. 6 | * http://teamdf.com/jquery-plugins/license/ 7 | * 8 | * @author Sam Sehnert 9 | * @desc A small plugin that checks whether elements are within 10 | * the user visible viewport of a web browser. 11 | * only accounts for vertical position, not horizontal. 12 | */ 13 | $.fn.visible = function(partial){ 14 | if ($(this).size() == 0) { 15 | return false; 16 | } 17 | 18 | var $t = $(this), 19 | $w = $(window), 20 | viewTop = $w.scrollTop(), 21 | viewBottom = viewTop + $w.height(), 22 | _top = $t.offset().top, 23 | _bottom = _top + $t.height(), 24 | compareTop = partial === true ? _bottom : _top, 25 | compareBottom = partial === true ? _top : _bottom; 26 | 27 | return ((compareBottom <= viewBottom) && (compareTop >= viewTop)); 28 | }; 29 | 30 | /** 31 | * JQuery selector returning elements largely outside the window. 32 | */ 33 | $.extend($.expr[':'], { 34 | largelyoutside: function(el) { 35 | var wheight = $(window).height(); 36 | var offset = $(el).offset(); 37 | var wscrolltop = $(window).scrollTop(); 38 | return offset.top > wscrolltop + wheight * 4 || offset.top + $(el).height() < wscrolltop - wheight * 4; 39 | } 40 | }); 41 | 42 | })(jQuery); -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/javascripts/r.category.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Initializing category module. 3 | */ 4 | r.category.init = function() { 5 | // Tip for adding category 6 | $('#category-add-button').qtip({ 7 | content: { text: $('#qtip-category-add') }, 8 | position: { 9 | my: 'top right', 10 | at: 'bottom center', 11 | effect: false, 12 | viewport: $(window) 13 | }, 14 | show: { event: 'click' }, 15 | hide: { event: 'click unfocus' }, 16 | style: { classes: 'qtip-light qtip-shadow' } 17 | }); 18 | 19 | // Adding a category 20 | $('#category-submit-button').click(function() { 21 | var _this = $(this); 22 | var name = $('#category-name-input').val(); 23 | 24 | // Validating form 25 | if (name != '') { 26 | // Disable button during the request to avoid double entries 27 | _this.attr('disabled', 'disabled'); 28 | 29 | // Calling API 30 | r.util.ajax({ 31 | url: r.util.url.category_add, 32 | type: 'PUT', 33 | data: { name: name }, 34 | done: function(data) { 35 | // Closing tip 36 | $('#category-add-button').qtip('hide'); 37 | 38 | // Reseting form 39 | $('#qtip-category-add form')[0].reset(); 40 | 41 | // Updating subscriptions tree 42 | r.subscription.update(); 43 | }, 44 | always: function() { 45 | // Enabing button 46 | _this.removeAttr('disabled'); 47 | } 48 | }); 49 | } 50 | 51 | // Prevent form submission 52 | return false; 53 | }); 54 | }; -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/javascripts/r.main.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Application modules. 3 | */ 4 | var r = { 5 | main: { 6 | mobile: false // True if mobile context 7 | }, 8 | user: {}, 9 | subscription: {}, 10 | category: {}, 11 | feed: {}, 12 | article: {}, 13 | search: {}, 14 | settings: {}, 15 | about: {}, 16 | wizard: {}, 17 | theme: {}, 18 | shortcuts: {}, 19 | util: {} 20 | }; 21 | 22 | /** 23 | * Application entry point. 24 | */ 25 | $(document).ready(function() { 26 | r.main.mobile = $('#subscriptions-show-button').is(':visible'); 27 | 28 | // Displaying login if necessary 29 | r.util.init(); 30 | r.user.init(); 31 | r.user.boot(); 32 | }); 33 | 34 | /** 35 | * Modules initialization. 36 | */ 37 | r.main.initModules = function() { 38 | // Load modules together 39 | r.subscription.init(); 40 | r.feed.init(); 41 | r.category.init(); 42 | r.article.init(); 43 | r.search.init(); 44 | r.settings.init(); 45 | r.about.init(); 46 | r.wizard.init(); 47 | r.theme.init(); 48 | r.shortcuts.init(); 49 | 50 | // First page 51 | if (r.user.hasBaseFunction('ADMIN') && r.user.userInfo.first_connection) { 52 | window.location.hash = '#/wizard/'; 53 | } else if (window.location.hash.length == 0) { 54 | window.location.hash = '#/feed/unread'; 55 | } 56 | }; 57 | 58 | /** 59 | * Reset current page context to show a new view. 60 | */ 61 | r.main.reset = function() { 62 | $('#toolbar > *').addClass('hidden'); 63 | 64 | r.feed.reset(); 65 | r.settings.reset(); 66 | r.about.reset(); 67 | r.wizard.reset(); 68 | }; -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/javascripts/r.search.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Initializing search module. 3 | */ 4 | r.search.init = function() { 5 | // Search on press enter 6 | $('#search-input').keydown(function(e) { 7 | if (e.which != 13) { 8 | return; 9 | } 10 | 11 | var query = $('#search-input').val(); 12 | if (query != '') { 13 | window.location.hash = '#/feed/search/' + encodeURI(query); 14 | } 15 | }); 16 | }; -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/javascripts/r.theme.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Initialize theme module. 3 | */ 4 | r.theme.init = function() { 5 | r.theme.update(r.user.userInfo.theme); 6 | }; 7 | 8 | /** 9 | * Update current theme. 10 | */ 11 | r.theme.update = function(theme) { 12 | if (theme) { 13 | // Add custom stylesheet 14 | var isLess = typeof less != 'undefined'; 15 | if (isLess) { 16 | // Remove previous custom theme 17 | less.sheets = $.grep(less.sheets, function(sheet) { 18 | return !$(sheet).hasClass('custom'); 19 | }); 20 | $('html > style').remove(); 21 | 22 | // Add custom stylesheet 23 | less.sheets.push($('')[0]); 24 | less.refresh(); 25 | } else { 26 | // Remove previous custom theme 27 | $('head > link.theme').remove(); 28 | 29 | // Just add the stylesheet, the browser handle it 30 | $('head').append($('')[0]); 31 | } 32 | } 33 | }; -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/stylesheets/_desktop.less: -------------------------------------------------------------------------------- 1 | body, html { 2 | background: #fff; 3 | height: 100%; 4 | } 5 | 6 | #actionbar { 7 | display: none; 8 | } 9 | 10 | #subscriptions { 11 | position: absolute; 12 | z-index: 2; 13 | width: 249px; 14 | top: 0; 15 | left: 0; 16 | bottom: 0; 17 | background: #f0f0f0; 18 | border-right: 1px solid #ccc; 19 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); 20 | overflow-y: auto; 21 | } 22 | 23 | #feed { 24 | position: absolute; 25 | z-index: 1; 26 | left: 250px; 27 | top: 0; 28 | bottom: 0; 29 | right: 0; 30 | 31 | #toolbar { 32 | > .narrow-article { 33 | display: inline-block; 34 | } 35 | } 36 | 37 | #feed-container, #settings-container, #about-container, #wizard-container { 38 | position: absolute; 39 | left: 0; 40 | bottom: 0; 41 | top: 44px; 42 | right: 0; 43 | overflow-y: auto; 44 | display: none; 45 | } 46 | 47 | #feed-container { 48 | > .feed-item { 49 | .content { 50 | .feed-item-description { 51 | line-height: 1.6; 52 | } 53 | } 54 | } 55 | 56 | &.narrow { 57 | > .feed-item { 58 | max-width: 800px; 59 | margin-left: auto; 60 | margin-right: auto; 61 | } 62 | } 63 | } 64 | } 65 | 66 | ::-webkit-scrollbar { 67 | width: 16px; 68 | } 69 | 70 | ::-webkit-scrollbar-track { 71 | background: #eee; 72 | } 73 | 74 | ::-webkit-scrollbar-thumb { 75 | background: #ccc; 76 | } -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/stylesheets/_mixins.less: -------------------------------------------------------------------------------- 1 | .border-radius (@radius) { 2 | border-radius: @radius; 3 | -moz-border-radius: @radius; 4 | -webkit-border-radius: @radius; 5 | } 6 | 7 | .linear-gradient(@type, @from, @to) { 8 | background-image: -webkit-linear-gradient(@type, @from, @to); 9 | background-image: -moz-linear-gradient(@type, @from, @to); 10 | background-image: -ms-linear-gradient(@type, @from, @to); 11 | background-image: -o-linear-gradient(@type, @from, @to); 12 | } 13 | 14 | .transition(@property, @duration) { 15 | transition: @property @duration; 16 | -moz-transition: @property @duration; 17 | -webkit-transition: @property @duration; 18 | } -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/stylesheets/_smartphone-small.less: -------------------------------------------------------------------------------- 1 | // Feed 2 | #feed { 3 | #toolbar { 4 | > .category-button { 5 | display: none; 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /reader-web/src/main/webapp/src/stylesheets/theme/default.less: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/main/webapp/src/stylesheets/theme/default.less -------------------------------------------------------------------------------- /reader-web/src/prod/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootCategory=WARN, MEMORY 2 | log4j.appender.MEMORY=com.sismics.util.log4j.MemoryAppender 3 | log4j.appender.MEMORY.size=1000 4 | 5 | log4j.logger.com.sismics=INFO -------------------------------------------------------------------------------- /reader-web/src/test/java/com/sismics/reader/rest/TestLocaleResource.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.rest; 2 | 3 | import org.codehaus.jettison.json.JSONArray; 4 | import org.codehaus.jettison.json.JSONException; 5 | import org.codehaus.jettison.json.JSONObject; 6 | import org.junit.Test; 7 | 8 | import static junit.framework.Assert.assertTrue; 9 | 10 | /** 11 | * Test the locale resource. 12 | * 13 | * @author jtremeaux 14 | */ 15 | public class TestLocaleResource extends BaseJerseyTest { 16 | /** 17 | * Test the locale resource. 18 | * 19 | */ 20 | @Test 21 | public void testLocaleResource() throws JSONException { 22 | GET("/locale"); 23 | assertIsOk(); 24 | JSONObject json = getJsonResult(); 25 | JSONArray locale = json.getJSONArray("locales"); 26 | assertTrue(locale.length() > 0); 27 | } 28 | } -------------------------------------------------------------------------------- /reader-web/src/test/java/com/sismics/reader/rest/TestThemeResource.java: -------------------------------------------------------------------------------- 1 | package com.sismics.reader.rest; 2 | 3 | import org.codehaus.jettison.json.JSONArray; 4 | import org.codehaus.jettison.json.JSONException; 5 | import org.codehaus.jettison.json.JSONObject; 6 | import org.junit.Test; 7 | 8 | import static junit.framework.Assert.assertTrue; 9 | 10 | /** 11 | * Test the theme resource. 12 | * 13 | * @author jtremeaux 14 | */ 15 | public class TestThemeResource extends BaseJerseyTest { 16 | /** 17 | * Test the theme resource. 18 | * 19 | */ 20 | @Test 21 | public void testThemeResource() throws JSONException { 22 | GET("/theme"); 23 | assertIsOk(); 24 | JSONObject json = getJsonResult(); 25 | JSONArray theme = json.getJSONArray("themes"); 26 | assertTrue(theme.length() > 0); 27 | } 28 | } -------------------------------------------------------------------------------- /reader-web/src/test/resources/hibernate.properties: -------------------------------------------------------------------------------- 1 | hibernate.connection.driver_class=org.hsqldb.jdbcDriver 2 | hibernate.connection.url=jdbc:hsqldb:mem:reader;get_column_name=false 3 | hibernate.connection.username=sa 4 | hibernate.connection.password= 5 | hibernate.dialect=org.hibernate.dialect.HSQLDialect 6 | hibernate.show_sql=false 7 | hibernate.format_sql=false 8 | hibernate.max_fetch_depth=5 9 | hibernate.cache.use_second_level_cache=false 10 | -------------------------------------------------------------------------------- /reader-web/src/test/resources/http/feeds/deleted/deleted2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | Deleted feeds 10 | 11 | http://localhost:9997/ 12 | Deleted feeds 13 | Sun, 9 Jun 2017 11:00:00 +0000 14 | fr-FR 15 | 16 | Article deleted3 17 | http://localhost:9997/deleted/003.html 18 | http://localhost:9997/deleted/003.html#comments 19 | Mon, 2 Jan 2017 10:05:00 +0000 20 | Sismics 21 | 22 | http://localhost:9997/deleted.xml/?p=003 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /reader-web/src/test/resources/http/feeds/future_date.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | Feed from the future 10 | 11 | http://localhost:9997/ 12 | Feed from the future 13 | Sun, 24 Mar 2033 07:03:43 +0000 14 | fr-FR 15 | 16 | This is an article from the future 17 | http://localhost:9997/future_date/xxx.html 18 | http://localhost:9997/future_date/xxx.html#comments 19 | Sun, 24 Mar 2033 07:03:43 +0000 20 | Sismics 21 | 22 | http://localhost:9997/future_date.xml/?p=1000 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /reader-web/src/test/resources/import/greader_subscriptions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Abonnements de Naku dans Google Reader 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /reader-web/src/test/resources/import/issue_110@gmail.com-takeout.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/test/resources/import/issue_110@gmail.com-takeout.zip -------------------------------------------------------------------------------- /reader-web/src/test/resources/import/test@gmail.com-takeout.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/reader-web/src/test/resources/import/test@gmail.com-takeout.zip -------------------------------------------------------------------------------- /reader-web/src/test/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootCategory=WARN, CONSOLE, MEMORY 2 | #log4j.rootCategory=DEBUG, CONSOLE, MEMORY 3 | log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender 4 | log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout 5 | log4j.appender.CONSOLE.layout.ConversionPattern=%d{DATE} %p %l %m %n 6 | log4j.appender.MEMORY=com.sismics.util.log4j.MemoryAppender 7 | log4j.appender.MEMORY.size=1000 8 | 9 | #log4j.logger.com.sismics=DEBUG 10 | log4j.logger.org.hibernate.internal.util.EntityPrinter=INFO -------------------------------------------------------------------------------- /reader.xml: -------------------------------------------------------------------------------- 1 | 2 | / 3 | /webapps/reader.war 4 | 5 | 6 | reader.home 7 | /data 8 | 9 | 10 | application.log.enabled 11 | false 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /rssman.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sismics/reader/b1c6506462d7980244034ac102ebe1544db9b16e/rssman.ai --------------------------------------------------------------------------------