Compare commits

...

50 Commits
2.4.0 ... 2.5.0

Author SHA1 Message Date
Athou
c1dac2e064 2.5.0 release 2020-09-02 21:20:20 +02:00
Jérémie Panzer
f707993188 fix travis build 2020-08-15 08:33:12 +02:00
Athou
ea612d9d53 add missing validCheckSum 2020-05-18 09:42:08 +02:00
Jeremie Panzer
b44e737448 fix liquibase script when running on an empty postgresql database 2020-03-12 13:45:06 +01:00
Jeremie Panzer
bb429afd95 ignore swagger in eclipse 2020-03-12 12:54:20 +01:00
dependabot[bot]
475a8f8a28 Bump bower from 1.4.1 to 1.8.8 (#920)
Bumps [bower](https://github.com/bower/bower) from 1.4.1 to 1.8.8.
- [Release notes](https://github.com/bower/bower/releases)
- [Changelog](https://github.com/bower/bower/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bower/bower/compare/v1.4.1...v1.8.8)

Signed-off-by: dependabot[bot] <support@github.com>
2019-09-30 09:01:55 +02:00
Athou
c7ba5ca894 make swagger aware that dates are serialized as longs 2019-05-03 22:01:18 +02:00
Athou
3023f0a7cc fix build 2019-05-03 18:57:02 +02:00
Athou
ddaefbc952 deduplicate method names across all the api (swagger requires unique api operations) 2019-05-03 18:40:50 +02:00
Jeremie Panzer
0b3a0fb3ed add missing required 2019-05-02 13:42:49 +02:00
Athou
7f40a430fd hide securitycheck user from swagger documentation 2019-05-01 23:33:55 +02:00
Athou
05f5d3b25c add missing "required" flags 2019-05-01 20:31:48 +02:00
Athou
c3ca0b18b3 value field of annotation is actually the name of the class 2019-05-01 19:57:52 +02:00
Athou
696e0b1fa7 maven config for swagger plugin changed 2019-05-01 19:56:48 +02:00
Athou
201f7dbd3e restore cookieMaxAge behavior 2019-04-23 01:14:26 +02:00
Athou
0bfd3e906c stop hibernate HHH90000015 spam 2019-04-22 20:55:39 +02:00
Jérémie Panzer
71ac2bfc45 support for Java9+ (#906)
* initial java9+ support

* restore session management, updated for jetty 9.4

* Session actually implements EntityManager

* reusable method for setting the timeout
2019-04-22 20:30:06 +02:00
Athou
5370db7c5e rename for clarity 2019-03-17 07:05:29 +01:00
Athou
bcc30e40ba Merge branch 'ildar-shaimordanov-master' 2019-03-17 06:46:51 +01:00
Athou
2f70f654f7 extensible mechanism for feed url building 2019-03-17 06:44:09 +01:00
ildar-shaimordanov
b64115dcbd improve youtube feed URL getter 2019-03-12 05:52:00 +04:00
ildar-shaimordanov
c9c71d8582 workaround for youtube channels 2019-03-12 02:13:41 +04:00
Jérémie Panzer
689bc19296 Merge pull request #896 from nelsonblaha/patch-1
English correction for configuration comment
2019-02-10 20:33:12 +01:00
Ben Nelson
27498ab649 English correction for configuration comment 2019-02-10 11:35:46 -06:00
Athou
678a11f998 blur event seems to trigger twice for some reason, make sure we don't fetch the feed twice (#825) 2018-07-31 15:51:48 +02:00
Athou
e9ef98716f configurable user agent string (#825) 2018-07-31 15:21:45 +02:00
Athou
b3ce43eaf7 faster replace for large feeds (#881) 2018-07-11 17:13:38 +02:00
Jérémie Panzer
72083b7e87 Merge pull request #880 from Athou/snyk-fix-0oenl9
[Snyk] Fix for 6 vulnerable dependencies
2018-06-23 13:49:14 +02:00
snyk-bot
0cc94c2033 fix: pom.xml to reduce vulnerabilities
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JAVA-COMH2DATABASE-31685
- https://snyk.io/vuln/SNYK-JAVA-MYSQL-31399
- https://snyk.io/vuln/SNYK-JAVA-MYSQL-31449
- https://snyk.io/vuln/SNYK-JAVA-MYSQL-31580
- https://snyk.io/vuln/SNYK-JAVA-ORGAPACHEHTTPCOMPONENTS-31517
- https://snyk.io/vuln/SNYK-JAVA-ORGJSOUP-31218
2018-06-14 05:55:43 +00:00
Jérémie Panzer
1d6296b400 Merge pull request #870 from asny23/update-japanese-translation
improve japanese translation
2018-04-12 12:18:50 +02:00
Unknown
7ad5da2a9e translate and improve japanese in ja.js 2018-04-11 23:27:56 +09:00
Athou
a7665a9994 add current year to filtering context 2018-02-25 13:38:37 +01:00
Jérémie Panzer
a4cd3f26e8 Update README.md 2018-02-22 18:21:48 +01:00
Athou
fcdb33b64b utility for testing feeds 2018-02-06 15:17:37 +01:00
Athou
7fd6119bcf add author to rss generated feeds (#858) 2017-12-22 18:50:32 +01:00
Jérémie Panzer
b4d4b2473c Merge pull request #854 from Busimus/patch-7
Updated Russian translation
2017-11-08 15:34:32 +01:00
Alexander Bus
91f715c3c3 Updated Russian translation 2017-10-28 01:16:57 +07:00
Athou
ea5fccfe5f fix build 2017-10-12 12:10:04 +02:00
Athou
86835eec73 request may not be a HttpUriRequest when using a proxy (#850) 2017-10-12 10:21:11 +02:00
Jérémie Panzer
2bccee2333 Merge pull request #849 from ema-pe/update-italian-translation
Update italian translation
2017-09-27 15:00:56 +02:00
Emanuele Petriglia
2d01b0d714 Update italian translation 2017-09-27 14:09:37 +02:00
Jérémie Panzer
44bf37b05a Update bower.json
fix alignment
2017-08-18 16:10:51 +02:00
Jérémie Panzer
cf617f0a64 Merge pull request #847 from sometoby/missing-shortcut-help
Add missing shortcut help for 'r'
2017-08-18 14:27:13 +02:00
Jérémie Panzer
eeeaffd883 Merge pull request #846 from sometoby/tinycon-unread-badge
Use tinycon to display unread article count
2017-08-18 14:25:07 +02:00
Tobias Umbach
d178302d34 Add comment so shortcut code is easier to find 2017-08-18 08:40:05 +02:00
Tobias Umbach
83a5364903 Add missing shortcut help for 'r', refresh 2017-08-18 08:39:49 +02:00
Tobias Umbach
aef76db664 Update CHANGELOG 2017-08-18 08:21:36 +02:00
Tobias Umbach
c3b3240191 Use tinycon to display unread article count 2017-08-14 11:15:43 +02:00
Athou
f381974955 prepare for next version 2017-08-01 13:55:11 +02:00
Athou
bd16dd98c4 update readme 2017-08-01 13:55:04 +02:00
70 changed files with 690 additions and 453 deletions

1
.gitignore vendored
View File

@@ -3,6 +3,7 @@ config.yml
# build directory
target
target-ide
# log files
log

View File

@@ -1,3 +1,3 @@
language: java
jdk:
- oraclejdk8
- openjdk8

View File

@@ -1,3 +1,9 @@
v 2.5.0
- unread count is now displayed in a favicon badge when supported
- the user agent string for the bot fetching feeds is now configurable
- feed parsing performance improvements
- support for java9+ runtime
- can now properly start from an empty postgresql database
v 2.4.0
- users were not able to change password or delete account
- fix api key generation
@@ -51,4 +57,4 @@ v2.0.0
- The backend has been completely rewritten using Dropwizard instead of TomEE, resulting in a lot less memory consumption and better overall performances.
See the README on how to build CommaFeed from now on.
- CommaFeed should no longer fetch the same feed multiple times in a row
- Users can use their username or email to log in
- Users can use their username or email to log in

View File

@@ -17,8 +17,8 @@ Browser extensions: [Chrome](https://github.com/Athou/commafeed-chrome) - [Firef
### The very short version (download precompiled package)
mkdir commafeed && cd commafeed
wget https://github.com/Athou/commafeed/releases/download/2.3.0/commafeed.jar
wget https://raw.githubusercontent.com/Athou/commafeed/2.3.0/config.yml.example -O config.yml
wget https://github.com/Athou/commafeed/releases/download/2.4.0/commafeed.jar
wget https://raw.githubusercontent.com/Athou/commafeed/2.4.0/config.yml.example -O config.yml
vi config.yml
java -Djava.net.preferIPv4Stack=true -jar commafeed.jar server config.yml
@@ -67,20 +67,6 @@ Issue the following command to run the app, the server will listen by default on
You can use a proxy http server such as nginx or apache.
## Deployment on OpenShift
[OpenShift](https://openshift.redhat.com) is Red Hat's Platform-as-a-Service (PaaS) that allows developers to quickly develop, host, and scale applications in a cloud environment. CommaFeed runs perfectly on OpenShift and can even be used in the free tier. Follow the [Getting Started](https://developers.openshift.com/en/getting-started-overview.html) guide and after you sign up and install the Command Line Tools (RHC), do:
rhc create-app commafeed diy-0.1 mysql-5.5
cd commafeed
git remote add upstream -m master https://github.com/Athou/commafeed.git
git pull -s recursive -X theirs upstream master
git push
# To upgrade an existing openshift installation
git pull upstream master
git push
## Translate CommaFeed into your language
Files for internationalization are located [here](https://github.com/Athou/commafeed/tree/master/src/main/app/i18n).

View File

@@ -28,7 +28,8 @@
"devicejs": "0.2.4",
"readabilicons": "arc90/readability-readabilicons#34c55561c5b8ec6e90714b50237c06b13cb9d59c",
"zocial-less": "1.0.0",
"swagger-ui": "2.1.0"
"swagger-ui": "2.1.0",
"tinycon": "0.6.5"
},
"resolutions": {
"angular": "1.3.14",

View File

@@ -67,6 +67,9 @@ app:
# announcement string displayed on the main page
announcement:
# user-agent string that will be used by the http client, leave empty for the default one
userAgent:
# Database connection
# -------------------
# for MySQL

View File

@@ -4,7 +4,7 @@ app:
# url used to access commafeed
publicUrl: http://localhost:8082/
# wether to allow user registrations
# whether to allow user registrations
allowRegistrations: false
# create a demo account the first time the app starts
@@ -68,6 +68,9 @@ app:
# announcement string displayed on the main page
announcement:
# user-agent string that will be used by the http client, leave empty for the default one
userAgent:
# Database connection
# -------------------
# for MySQL
@@ -108,6 +111,7 @@ logging:
com.commafeed: INFO
liquibase: INFO
io.dropwizard.server.ServerFactory: INFO
org.hibernate.orm.deprecation: "OFF"
appenders:
- type: console
- type: file
@@ -128,4 +132,4 @@ redis:
timeout: 2000
database: 0
maxTotal: 500

View File

@@ -4,7 +4,7 @@
"main": "main.js",
"private": true,
"devDependencies": {
"bower": "1.4.1",
"bower": "1.8.8",
"gulp": "3.8.11",
"gulp-rev": "4.0.0",
"gulp-rev-replace": "0.4.1",

153
pom.xml
View File

@@ -4,16 +4,16 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.commafeed</groupId>
<artifactId>commafeed</artifactId>
<version>2.4.0</version>
<version>2.5.0</version>
<packaging>jar</packaging>
<name>CommaFeed</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<dropwizard.version>0.9.1</dropwizard.version>
<guice.version>4.0</guice.version>
<querydsl.version>4.0.2</querydsl.version>
<dropwizard.version>1.3.20</dropwizard.version>
<guice.version>4.2.2</guice.version>
<querydsl.version>4.2.1</querydsl.version>
<rome.version>1.5.0</rome.version>
</properties>
@@ -32,43 +32,11 @@
</resource>
</resources>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<versionRange>[0.0.22,)</versionRange>
<goals>
<goal>npm</goal>
<goal>gulp</goal>
<goal>bower</goal>
</goals>
</pluginExecutionFilter>
<action>
<execute>
<runOnIncremental>false</runOnIncremental>
</execute>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<version>3.8.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
@@ -128,11 +96,15 @@
<plugin>
<groupId>com.github.kongchen</groupId>
<artifactId>swagger-maven-plugin</artifactId>
<version>3.1.1</version>
<version>3.1.7</version>
<configuration>
<apiSources>
<apiSource>
<locations>com.commafeed.frontend.resource;com.commafeed.frontend.model;com.commafeed.frontend.model.request</locations>
<locations>
<location>com.commafeed.frontend.resource</location>
<location>com.commafeed.frontend.model</location>
<location>com.commafeed.frontend.model.request</location>
</locations>
<swaggerDirectory>target/swagger</swaggerDirectory>
<basePath>/rest</basePath>
<info>
@@ -157,7 +129,7 @@
<plugin>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<version>0.0.25</version>
<version>1.6</version>
<executions>
<execution>
<id>install node and npm</id>
@@ -166,7 +138,7 @@
</goals>
<phase>compile</phase>
<configuration>
<nodeVersion>v0.10.39</nodeVersion>
<nodeVersion>v6.11.4</nodeVersion>
<npmVersion>3.10.6</npmVersion>
</configuration>
</execution>
@@ -202,7 +174,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<version>3.1.1</version>
<configuration>
<archive>
<manifest>
@@ -214,11 +186,70 @@
</plugins>
</build>
<profiles>
<profile>
<id>only-eclipse</id>
<activation>
<property>
<name>m2e.version</name>
</property>
</activation>
<build>
<directory>target-ide</directory>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<versionRange>[0.0.22,)</versionRange>
<goals>
<goal>npm</goal>
<goal>gulp</goal>
<goal>bower</goal>
</goals>
</pluginExecutionFilter>
<action>
<execute>
<runOnIncremental>false</runOnIncremental>
</execute>
</action>
</pluginExecution>
<pluginExecution>
<pluginExecutionFilter>
<groupId>com.github.kongchen</groupId>
<artifactId>swagger-maven-plugin</artifactId>
<versionRange>[3.1.7,)</versionRange>
<goals>
<goal>generate</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore></ignore>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
</profiles>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.4</version>
<version>1.18.6</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -279,16 +310,21 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-graphite</artifactId>
<version>3.1.2</version>
</dependency>
<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-graphite</artifactId>
<version>3.1.2</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5</version>
<version>4.5.2</version>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
@@ -300,7 +336,7 @@
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.5.0</version>
<version>1.5.22</version>
</dependency>
<dependency>
@@ -316,11 +352,6 @@
<version>${querydsl.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
@@ -386,11 +417,15 @@
<artifactId>jdom2</artifactId>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>org.ahocorasick</groupId>
<artifactId>ahocorasick</artifactId>
<version>0.4.0</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.8.2</version>
<version>1.8.3</version>
</dependency>
<dependency>
<groupId>com.ibm.icu</groupId>
@@ -418,12 +453,12 @@
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.3.176</version>
<version>1.4.197</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.37</version>
<version>5.1.42</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>

View File

@@ -175,7 +175,8 @@
"font_size" : "increase/decrease font size of the current entry ",
"go_to_all" : "go to the All view ",
"go_to_starred" : "go to the Starred view ",
"feed_search" : "navigate to a subscription by entering the subscription name"
"feed_search" : "navigate to a subscription by entering the subscription name",
"refresh": "refresh"
}
}
}
}

View File

@@ -177,7 +177,8 @@
"font_size" : "increase/decrease font size of the current entry",
"go_to_all" : "go to the All view",
"go_to_starred" : "go to the Starred view",
"feed_search" : "navigate to a subscription by entering the subscription name"
"feed_search" : "navigate to a subscription by entering the subscription name",
"refresh": "refresh"
}
}
}
}

View File

@@ -41,7 +41,7 @@
"refresh" : "Aggiorna",
"refresh_all" : "Forza l'aggiornamento di tutti i feed",
"sort_by_asc_desc" : "Ordina per data crescente/decrescente",
"sort_by_abc_zyx" : "Sort Alphabetically",
"sort_by_abc_zyx" : "Ordina alfabeticamente",
"titles_only" : "Solo i titoli",
"expanded_view" : "Espandi",
"mark_all_as_read" : "Segna tutti come già letti",
@@ -57,8 +57,8 @@
"donate" : "Dona"
},
"view" : {
"entry_source" : "da",
"entry_author" : "di",
"entry_source" : "da ",
"entry_author" : "di ",
"error_while_loading_feed" : "Si è verificato un errore durante il caricamento del feed",
"keep_unread" : "Mantieni come da leggere",
"no_unread_items" : "non contiene elementi da leggere",
@@ -82,9 +82,9 @@
},
"appearance" : "Aspetto",
"scroll_speed" : "Velocità di scorrimento quando navighi tra i feed (in millisecondi)",
"scroll_speed_help" : "Imposta su 0 per disabilitare",
"scroll_speed_help" : "imposta su 0 per disabilitare",
"theme" : "Tema",
"submit_your_theme" : "Sottoponi il tuo tema",
"submit_your_theme" : "Inserisci il tuo tema",
"custom_css" : "CSS personalizzato"
},
"details" : {
@@ -130,7 +130,7 @@
"line1" : "CommaFeed è basato su JAX-RS e AngularJS. Pertanto è disponibile una REST API.",
"link_to_documentation" : "Link alla documentazione."
},
"keyboard_shortcuts" : "Scorciatoie da tastiera",
"keyboard_shortcuts" : "Scorciatoie da tastiera",
"version" : "Versione di CommaFeed",
"line1_prefix" : "CommaFeed è un progetto open source. Trovi i sorgenti su ",
"line1_suffix" : ".",
@@ -148,12 +148,12 @@
"subscribe_bookmarklet" : "Aggiungi la sottoscrizione ai segnalibri (clicca)",
"subscribe_bookmarklet_asc" : "Prima i vecchi",
"subscribe_bookmarklet_desc" : "Prima i recenti",
"next_unread_bookmarklet" : "Bookmarklet al prossimo elemento da leggere (trascinalo nella barra dei segnalibri)"
"next_unread_bookmarklet" : "Segnalibro al prossimo elemento da leggere (trascinalo nella barra dei segnalibri)"
},
"translation" : {
"value" : "Traduzioni",
"message" : "Abbiamo bisogno del tuo aiuto per tradurre CommaFeed.",
"link" : "Scopri come aiutarci nella traduzioni."
"link" : "Scopri come aiutarci nelle traduzioni."
},
"announcements" : "Annunci",
"shortcuts" : {
@@ -177,7 +177,8 @@
"font_size" : "aumenta/decrementa la dimensione del font per la voce corrente",
"go_to_all" : "vai alla vista Tutti",
"go_to_starred" : "vai alla vista Preferiti",
"feed_search" : "raggiungi una sottoscrizione scrivendo il suo nome"
"feed_search" : "raggiungi una sottoscrizione scrivendo il suo nome",
"refresh" : "aggiorna"
}
}
}

View File

@@ -3,7 +3,7 @@
"save" : "保存",
"cancel" : "取り消し",
"delete" : "削除",
"required" : "Required",
"required" : "必須",
"download" : "ダウンロード",
"link" : "リンク",
"bookmark" : "ブックマーク",
@@ -15,7 +15,7 @@
"import" : "インポート",
"new_category" : "新しいカテゴリー",
"all" : "全て",
"starred" : "スター付"
"starred" : "スター付"
},
"subscribe" : {
"feed_url" : "フィードURL",
@@ -40,8 +40,8 @@
"next_entry" : "次のエントリー",
"refresh" : "更新",
"refresh_all" : "全てのフィードを更新",
"sort_by_asc_desc" : "昇順/降順にソート",
"sort_by_abc_zyx" : "Sort Alphabetically",
"sort_by_asc_desc" : "日時でソート",
"sort_by_abc_zyx" : "名前でソート",
"titles_only" : "タイトルのみ",
"expanded_view" : "拡張ビュー",
"mark_all_as_read" : "全て既読にする",
@@ -101,8 +101,8 @@
"feed_url" : "フィードURL",
"generate_api_key_first" : "最初にあなたのAPIキーを生成して下さい。",
"unsubscribe" : "購読解除",
"unsubscribe_confirmation" : "Are you sure you want to unsubscribe from this feed? ",
"delete_category_confirmation" : "Are you sure you want to delete this category? ",
"unsubscribe_confirmation" : "フィードの購読を解除してよろしいですか?",
"delete_category_confirmation" : "カテゴリーを削除してよろしいですか?",
"category_details" : "カテゴリー詳細",
"tag_details" : "タグ詳細",
"parent_category" : "親カテゴリー"
@@ -117,10 +117,10 @@
"api_key" : "APIキー",
"api_key_not_generated" : "APIキーが生成されていません",
"generate_new_api_key" : "新しいAPIキーを生成",
"generate_new_api_key_info" : "パスワード変更新しいAPIキーが生成されます",
"generate_new_api_key_info" : "パスワード変更すると新しいAPIキーが生成されます",
"opml_export" : "OPMLエクスポート",
"delete_account" : "アカウント削除",
"delete_account_confirmation" : "Delete your acount? There's no turning back! "
"delete_account_confirmation" : "アカウントを削除してよろしいですか? 削除すると戻すことはできません!"
},
"about" : {
"rest_api" : {
@@ -150,10 +150,10 @@
},
"translation" : {
"value" : "翻訳",
"message" : "CommaFeedの翻訳に助けが必要です",
"link" : "どうやって翻訳に貢献できるか見て下さい。"
"message" : "CommaFeedの翻訳にご協力ください",
"link" : "翻訳にあたっての案内はこちら"
},
"announcements" : "Announcements",
"announcements" : "お知らせ",
"shortcuts" : {
"mouse_middleclick" : "中クリック",
"open_next_entry" : "次のエントリーを開く",
@@ -171,7 +171,7 @@
"mark_current_entry" : "現在のエントリーを既読/未読にする",
"mark_all_as_read" : "全エントリーを既読にする",
"open_in_new_tab_mark_as_read" : "エントリーを既読にして新しいタブで開く",
"fullscreen" : "フルスクリーントグル",
"fullscreen" : "フルスクリーン切り替え",
"font_size" : "現在のエントリーのフォントサイズを大きく/小さくする",
"go_to_all" : "All viewに変更する",
"go_to_starred" : "スター付きviewに変更する",

View File

@@ -41,7 +41,7 @@
"refresh" : "Обновить",
"refresh_all" : "Обновить все подписки вручную",
"sort_by_asc_desc" : "Сначала новые/старые",
"sort_by_abc_zyx" : "Sort Alphabetically",
"sort_by_abc_zyx" : "По алфавиту",
"titles_only" : "Только заголовки",
"expanded_view" : "Развёрнутый вид",
"mark_all_as_read" : "Отметить всё как прочитанное",
@@ -178,4 +178,4 @@
"feed_search" : "перейти к подписке по названию"
}
}
}
}

View File

@@ -70,6 +70,7 @@
<script type="text/javascript" src="lib/mousetrap/mousetrap.js"></script>
<script type="text/javascript" src="lib/momentjs/min/moment-with-locales.js"></script>
<script type="text/javascript" src="lib/devicejs/lib/device.js"></script>
<script type="text/javascript" src="lib/tinycon/tinycon.js"></script>
<script type="text/javascript" src="js/controllers.js"></script>
<script type="text/javascript" src="js/directives.js"></script>

View File

@@ -43,7 +43,7 @@ module.controller('SubscribeCtrl', ['$scope', '$location', 'FeedService', 'Categ
// 'ok', 'loading' or 'failed'
$scope.state = 'ok';
$scope.urlChanged = function() {
if ($scope.sub.url) {
if ($scope.sub.url && $scope.state != 'loading') {
$scope.state = 'loading';
$scope.sub.title = 'Loading...';
FeedService.fetch({
@@ -194,11 +194,7 @@ module.controller('CategoryTreeCtrl', [
};
$scope.$watch(rootUnreadCount, function(value) {
var label = 'CommaFeed';
if (value > 0) {
label = '(' + value + ') ' + label;
}
$window.document.title = label;
Tinycon.setBubble(value);
});
var mark = function(node, entry) {
@@ -1061,6 +1057,7 @@ module.controller('FeedListCtrl', [
}
};
// keyboard shortcuts
Mousetrap.bind('j', function(e) {
$scope.$apply(function() {
$scope.navigationMode = 'keyboard';

View File

@@ -1,4 +1,7 @@
<dl class="dl-horizontal">
<dt>r</dt>
<dd>{{ 'about.shortcuts.refresh' | translate }}</dd>
<dt>j</dt>
<dd>{{ 'about.shortcuts.open_next_entry' | translate }}</dd>
@@ -68,4 +71,4 @@
</dt>
<dd>{{ 'about.shortcuts.feed_search' | translate }}</dd>
</dl>
</dl>

View File

@@ -13,7 +13,6 @@ import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.eclipse.jetty.server.session.SessionHandler;
import org.hibernate.cfg.AvailableSettings;
import com.commafeed.backend.feed.FeedRefreshTaskGiver;
@@ -111,7 +110,7 @@ public class CommaFeedApplication extends Application<CommaFeedConfiguration> {
Injector injector = Guice.createInjector(new CommaFeedModule(hibernateBundle.getSessionFactory(), config, environment.metrics()));
// session management
environment.servlets().setSessionHandler(new SessionHandler(config.getSessionManagerFactory().build()));
environment.servlets().setSessionHandler(config.getSessionHandlerFactory().build());
// support for "@SecurityCheck User user" injection
environment.jersey().register(new SecurityCheckFactoryProvider.Binder(injector.getInstance(UserService.class)));

View File

@@ -1,8 +1,5 @@
package com.commafeed;
import io.dropwizard.Configuration;
import io.dropwizard.db.DataSourceFactory;
import java.util.Date;
import java.util.ResourceBundle;
@@ -10,15 +7,17 @@ import javax.validation.Valid;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import lombok.Getter;
import org.apache.commons.lang3.time.DateUtils;
import org.hibernate.validator.constraints.NotBlank;
import com.commafeed.backend.cache.RedisPoolFactory;
import com.commafeed.frontend.session.SessionManagerFactory;
import com.commafeed.frontend.session.SessionHandlerFactory;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.dropwizard.Configuration;
import io.dropwizard.db.DataSourceFactory;
import lombok.Getter;
@Getter
public class CommaFeedConfiguration extends Configuration {
@@ -45,7 +44,7 @@ public class CommaFeedConfiguration extends Configuration {
@Valid
@NotNull
@JsonProperty("session")
private SessionManagerFactory sessionManagerFactory = new SessionManagerFactory();
private SessionHandlerFactory SessionHandlerFactory = new SessionHandlerFactory();
@Valid
@NotNull
@@ -138,10 +137,11 @@ public class CommaFeedConfiguration extends Configuration {
@Valid
private CacheType cache;
@NotNull
@Valid
private String announcement;
private String userAgent;
public Date getUnreadThreshold() {
int keepStatusDays = getKeepStatusDays();
return keepStatusDays > 0 ? DateUtils.addDays(new Date(), -1 * keepStatusDays) : null;

View File

@@ -26,6 +26,9 @@ import com.commafeed.backend.task.OldStatusesCleanupTask;
import com.commafeed.backend.task.OrphanedContentsCleanupTask;
import com.commafeed.backend.task.OrphanedFeedsCleanupTask;
import com.commafeed.backend.task.ScheduledTask;
import com.commafeed.backend.urlprovider.FeedURLProvider;
import com.commafeed.backend.urlprovider.InPageReferenceFeedURLProvider;
import com.commafeed.backend.urlprovider.YoutubeFeedURLProvider;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.multibindings.Multibinder;
@@ -55,6 +58,10 @@ public class CommaFeedModule extends AbstractModule {
faviconMultibinder.addBinding().to(FacebookFaviconFetcher.class);
faviconMultibinder.addBinding().to(DefaultFaviconFetcher.class);
Multibinder<FeedURLProvider> urlProviderMultibinder = Multibinder.newSetBinder(binder(), FeedURLProvider.class);
urlProviderMultibinder.addBinding().to(InPageReferenceFeedURLProvider.class);
urlProviderMultibinder.addBinding().to(YoutubeFeedURLProvider.class);
Multibinder<ScheduledTask> taskMultibinder = Multibinder.newSetBinder(binder(), ScheduledTask.class);
taskMultibinder.addBinding().to(OldStatusesCleanupTask.class);
taskMultibinder.addBinding().to(OldEntriesCleanupTask.class);

View File

@@ -70,7 +70,10 @@ public class HttpGetter {
@Inject
public HttpGetter(CommaFeedConfiguration config) {
this.userAgent = String.format("CommaFeed/%s (https://github.com/Athou/commafeed)", config.getVersion());
this.userAgent = config.getApplicationSettings().getUserAgent();
if (this.userAgent == null) {
this.userAgent = String.format("CommaFeed/%s (https://github.com/Athou/commafeed)", config.getVersion());
}
}
public HttpResult getBinary(String url, int timeout) throws ClientProtocolException, IOException, NotModifiedException {
@@ -151,9 +154,13 @@ public class HttpGetter {
contentType = entity.getContentType().getValue();
}
}
HttpUriRequest req = (HttpUriRequest) context.getRequest();
HttpHost host = context.getTargetHost();
String urlAfterRedirect = req.getURI().isAbsolute() ? req.getURI().toString() : host.toURI() + req.getURI();
String urlAfterRedirect = url;
if (context.getRequest() instanceof HttpUriRequest) {
HttpUriRequest req = (HttpUriRequest) context.getRequest();
HttpHost host = context.getTargetHost();
urlAfterRedirect = req.getURI().isAbsolute() ? req.getURI().toString() : host.toURI() + req.getURI();
}
long duration = System.currentTimeMillis() - start;
result = new HttpResult(content, contentType, lastModifiedHeaderValue, eTagHeaderValue, duration, urlAfterRedirect);
@@ -219,4 +226,11 @@ public class HttpGetter {
return null;
}
}
public static void main(String[] args) throws Exception {
CommaFeedConfiguration config = new CommaFeedConfiguration();
HttpGetter getter = new HttpGetter(config);
HttpResult result = getter.getBinary("https://sourceforge.net/projects/mpv-player-windows/rss", 30000);
System.out.println(new String(result.content));
}
}

View File

@@ -17,7 +17,6 @@ import com.commafeed.backend.model.QUser;
import com.google.common.collect.Iterables;
import com.querydsl.jpa.JPAExpressions;
import com.querydsl.jpa.JPQLQuery;
import com.querydsl.jpa.hibernate.HibernateQuery;
@Singleton
public class FeedDAO extends GenericDAO<Feed> {
@@ -30,7 +29,7 @@ public class FeedDAO extends GenericDAO<Feed> {
}
public List<Feed> findNextUpdatable(int count, Date lastLoginThreshold) {
HibernateQuery<Feed> query = query().selectFrom(feed);
JPQLQuery<Feed> query = query().selectFrom(feed);
query.where(feed.disabledUntil.isNull().or(feed.disabledUntil.lt(new Date())));
if (lastLoginThreshold != null) {
@@ -60,7 +59,6 @@ public class FeedDAO extends GenericDAO<Feed> {
public List<Feed> findWithoutSubscriptions(int max) {
QFeedSubscription sub = QFeedSubscription.feedSubscription;
return query().selectFrom(feed).where(JPAExpressions.selectOne().from(sub).where(sub.feed.eq(feed)).notExists()).limit(max)
.fetch();
return query().selectFrom(feed).where(JPAExpressions.selectOne().from(sub).where(sub.feed.eq(feed)).notExists()).limit(max).fetch();
}
}

View File

@@ -33,7 +33,7 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Ordering;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.Tuple;
import com.querydsl.jpa.hibernate.HibernateQuery;
import com.querydsl.jpa.impl.JPAQuery;
@Singleton
public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
@@ -67,7 +67,7 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
};
private static final Comparator<FeedEntryStatus> STATUS_COMPARATOR_ASC = Ordering.from(STATUS_COMPARATOR_DESC).reverse();
private static final Comparator<FeedEntryStatus> STATUS_COMPARATOR_ABC = new Comparator<FeedEntryStatus>() {
@Override
public int compare(FeedEntryStatus o1, FeedEntryStatus o2) {
@@ -77,9 +77,8 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
return builder.toComparison();
}
};
private static final Comparator<FeedEntryStatus> STATUS_COMPARATOR_ZYX = Ordering.from(STATUS_COMPARATOR_ABC).reverse();
private static final Comparator<FeedEntryStatus> STATUS_COMPARATOR_ZYX = Ordering.from(STATUS_COMPARATOR_ABC).reverse();
public FeedEntryStatus getStatus(User user, FeedSubscription sub, FeedEntry entry) {
List<FeedEntryStatus> statuses = query().selectFrom(status).where(status.entry.eq(entry), status.subscription.eq(sub)).fetch();
@@ -107,26 +106,23 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
}
public List<FeedEntryStatus> findStarred(User user, Date newerThan, int offset, int limit, ReadingOrder order, boolean includeContent) {
HibernateQuery<FeedEntryStatus> query = query().selectFrom(status).where(status.user.eq(user), status.starred.isTrue());
JPAQuery<FeedEntryStatus> query = query().selectFrom(status).where(status.user.eq(user), status.starred.isTrue());
if (newerThan != null) {
query.where(status.entryInserted.gt(newerThan));
}
if (order == ReadingOrder.asc) {
query.orderBy(status.entryUpdated.asc(), status.id.asc());
} else if (order == ReadingOrder.desc){
} else if (order == ReadingOrder.desc) {
query.orderBy(status.entryUpdated.desc(), status.id.desc());
} else if (order == ReadingOrder.abc) {
query.orderBy(status.entry.content.title.asc(), status.id.desc());
} else { //order == ReadingOrder.xyz
} else { // order == ReadingOrder.xyz
query.orderBy(status.entry.content.title.desc(), status.id.desc());
}
query.offset(offset).limit(limit);
int timeout = config.getApplicationSettings().getQueryTimeout();
if (timeout > 0) {
query.setTimeout(timeout / 1000);
}
setTimeout(query, config.getApplicationSettings().getQueryTimeout());
List<FeedEntryStatus> statuses = query.fetch();
for (FeedEntryStatus status : statuses) {
@@ -136,10 +132,10 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
return lazyLoadContent(includeContent, statuses);
}
private HibernateQuery<FeedEntry> buildQuery(User user, FeedSubscription sub, boolean unreadOnly, List<FeedEntryKeyword> keywords,
private JPAQuery<FeedEntry> buildQuery(User user, FeedSubscription sub, boolean unreadOnly, List<FeedEntryKeyword> keywords,
Date newerThan, int offset, int limit, ReadingOrder order, FeedEntryStatus last, String tag) {
HibernateQuery<FeedEntry> query = query().selectFrom(entry).where(entry.feed.eq(sub.getFeed()));
JPAQuery<FeedEntry> query = query().selectFrom(entry).where(entry.feed.eq(sub.getFeed()));
if (CollectionUtils.isNotEmpty(keywords)) {
query.join(entry.content, content);
@@ -187,14 +183,14 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
} else if (order == ReadingOrder.abc) {
query.join(entry.content, content);
query.where(content.title.lt(last.getEntry().getContent().getTitle()));
} else { //order == ReadingOrder.zyx
} else { // order == ReadingOrder.zyx
query.join(entry.content, content);
query.where(content.title.gt(last.getEntry().getContent().getTitle()));
}
} else if (order != null && (order == ReadingOrder.abc || order == ReadingOrder.zyx)) {
query.join(entry.content, content);
}
if (order != null) {
if (order == ReadingOrder.asc) {
query.orderBy(entry.updated.asc(), entry.id.asc());
@@ -202,7 +198,7 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
query.orderBy(entry.updated.desc(), entry.id.desc());
} else if (order == ReadingOrder.abc) {
query.orderBy(content.title.asc(), entry.id.asc());
} else { //order == ReadingOrder.zyx
} else { // order == ReadingOrder.zyx
query.orderBy(content.title.desc(), entry.id.desc());
}
}
@@ -212,10 +208,7 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
if (limit > -1) {
query.limit(limit);
}
int timeout = config.getApplicationSettings().getQueryTimeout();
if (timeout > 0) {
query.setTimeout(timeout / 1000);
}
setTimeout(query, config.getApplicationSettings().getQueryTimeout());
return query;
}
@@ -223,7 +216,7 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
List<FeedEntryKeyword> keywords, Date newerThan, int offset, int limit, ReadingOrder order, boolean includeContent,
boolean onlyIds, String tag) {
int capacity = offset + limit;
Comparator<FeedEntryStatus> comparator;
if (order == ReadingOrder.desc) {
comparator = STATUS_COMPARATOR_DESC;
@@ -238,7 +231,7 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
FixedSizeSortedSet<FeedEntryStatus> set = new FixedSizeSortedSet<FeedEntryStatus>(capacity, comparator);
for (FeedSubscription sub : subs) {
FeedEntryStatus last = (order != null && set.isFull()) ? set.last() : null;
HibernateQuery<FeedEntry> query = buildQuery(user, sub, unreadOnly, keywords, newerThan, -1, capacity, order, last, tag);
JPAQuery<FeedEntry> query = buildQuery(user, sub, unreadOnly, keywords, newerThan, -1, capacity, order, last, tag);
List<Tuple> tuples = query.select(entry.id, entry.updated, status.id, entry.content.title).fetch();
for (Tuple tuple : tuples) {
@@ -291,7 +284,7 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
public UnreadCount getUnreadCount(User user, FeedSubscription subscription) {
UnreadCount uc = null;
HibernateQuery<FeedEntry> query = buildQuery(user, subscription, true, null, null, -1, -1, null, null, null);
JPAQuery<FeedEntry> query = buildQuery(user, subscription, true, null, null, -1, -1, null, null, null);
List<Tuple> tuples = query.select(entry.count(), entry.updated.max()).fetch();
for (Tuple tuple : tuples) {
Long count = tuple.get(entry.count());

View File

@@ -16,7 +16,7 @@ import com.commafeed.backend.model.Models;
import com.commafeed.backend.model.QFeedSubscription;
import com.commafeed.backend.model.User;
import com.google.common.collect.Iterables;
import com.querydsl.jpa.hibernate.HibernateQuery;
import com.querydsl.jpa.JPQLQuery;
@Singleton
public class FeedSubscriptionDAO extends GenericDAO<FeedSubscription> {
@@ -44,13 +44,13 @@ public class FeedSubscriptionDAO extends GenericDAO<FeedSubscription> {
}
public List<FeedSubscription> findAll(User user) {
List<FeedSubscription> subs = query().selectFrom(sub).where(sub.user.eq(user)).leftJoin(sub.feed).fetchJoin()
.leftJoin(sub.category).fetchJoin().fetch();
List<FeedSubscription> subs = query().selectFrom(sub).where(sub.user.eq(user)).leftJoin(sub.feed).fetchJoin().leftJoin(sub.category)
.fetchJoin().fetch();
return initRelations(subs);
}
public List<FeedSubscription> findByCategory(User user, FeedCategory category) {
HibernateQuery<FeedSubscription> query = query().selectFrom(sub).where(sub.user.eq(user));
JPQLQuery<FeedSubscription> query = query().selectFrom(sub).where(sub.user.eq(user));
if (category == null) {
query.where(sub.category.isNull());
} else {

View File

@@ -3,22 +3,24 @@ package com.commafeed.backend.dao;
import java.util.Collection;
import org.hibernate.SessionFactory;
import org.hibernate.annotations.QueryHints;
import com.commafeed.backend.model.AbstractModel;
import com.querydsl.jpa.hibernate.HibernateQueryFactory;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import io.dropwizard.hibernate.AbstractDAO;
public abstract class GenericDAO<T extends AbstractModel> extends AbstractDAO<T> {
private HibernateQueryFactory factory;
private JPAQueryFactory factory;
protected GenericDAO(SessionFactory sessionFactory) {
super(sessionFactory);
this.factory = new HibernateQueryFactory(() -> currentSession());
this.factory = new JPAQueryFactory(() -> currentSession());
}
protected HibernateQueryFactory query() {
protected JPAQueryFactory query() {
return factory;
}
@@ -49,4 +51,10 @@ public abstract class GenericDAO<T extends AbstractModel> extends AbstractDAO<T>
return objects.size();
}
protected void setTimeout(JPAQuery<?> query, int timeoutMs) {
if (timeoutMs > 0) {
query.setHint(QueryHints.TIMEOUT_JPA, timeoutMs);
}
}
}

View File

@@ -2,26 +2,24 @@ package com.commafeed.backend.feed;
import java.io.IOException;
import java.util.Date;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.StringUtils;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.client.ClientProtocolException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import com.commafeed.backend.HttpGetter;
import com.commafeed.backend.HttpGetter.HttpResult;
import com.commafeed.backend.HttpGetter.NotModifiedException;
import com.commafeed.backend.model.Feed;
import com.commafeed.backend.urlprovider.FeedURLProvider;
import com.rometools.rome.io.FeedException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
@Singleton
@@ -29,9 +27,10 @@ public class FeedFetcher {
private final FeedParser parser;
private final HttpGetter getter;
private final Set<FeedURLProvider> urlProviders;
public FetchedFeed fetch(String feedUrl, boolean extractFeedUrlFromHtml, String lastModified, String eTag, Date lastPublishedDate,
String lastContentHash) throws FeedException, ClientProtocolException, IOException, NotModifiedException {
String lastContentHash) throws FeedException, IOException, NotModifiedException {
log.debug("Fetching feed {}", feedUrl);
FetchedFeed fetchedFeed = null;
@@ -44,7 +43,7 @@ public class FeedFetcher {
fetchedFeed = parser.parse(result.getUrlAfterRedirect(), content);
} catch (FeedException e) {
if (extractFeedUrlFromHtml) {
String extractedUrl = extractFeedUrl(StringUtils.newStringUtf8(result.getContent()), feedUrl);
String extractedUrl = extractFeedUrl(urlProviders, feedUrl, StringUtils.newStringUtf8(result.getContent()));
if (org.apache.commons.lang3.StringUtils.isNotBlank(extractedUrl)) {
feedUrl = extractedUrl;
@@ -84,20 +83,13 @@ public class FeedFetcher {
return fetchedFeed;
}
private String extractFeedUrl(String html, String baseUri) {
String foundUrl = null;
Document doc = Jsoup.parse(html, baseUri);
String root = doc.children().get(0).tagName();
if ("html".equals(root)) {
Elements atom = doc.select("link[type=application/atom+xml]");
Elements rss = doc.select("link[type=application/rss+xml]");
if (!atom.isEmpty()) {
foundUrl = atom.get(0).attr("abs:href");
} else if (!rss.isEmpty()) {
foundUrl = rss.get(0).attr("abs:href");
}
private static String extractFeedUrl(Set<FeedURLProvider> urlProviders, String url, String urlContent) {
for (FeedURLProvider urlProvider : urlProviders) {
String feedUrl = urlProvider.get(url, urlContent);
if (feedUrl != null)
return feedUrl;
}
return foundUrl;
return null;
}
}

View File

@@ -6,6 +6,7 @@ import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
@@ -13,6 +14,9 @@ import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.ahocorasick.trie.Emit;
import org.ahocorasick.trie.Trie;
import org.ahocorasick.trie.Trie.TrieBuilder;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
@@ -132,7 +136,32 @@ public class FeedUtils {
}
public static String replaceHtmlEntitiesWithNumericEntities(String source) {
return StringUtils.replaceEach(source, HtmlEntities.HTML_ENTITIES, HtmlEntities.NUMERIC_ENTITIES);
// Create a buffer sufficiently large that re-allocations are minimized.
StringBuilder sb = new StringBuilder(source.length() << 1);
TrieBuilder builder = Trie.builder();
builder.ignoreOverlaps();
for (String key : HtmlEntities.HTML_ENTITIES) {
builder.addKeyword(key);
}
Trie trie = builder.build();
Collection<Emit> emits = trie.parseText(source);
int prevIndex = 0;
for (Emit emit : emits) {
int matchIndex = emit.getStart();
sb.append(source.substring(prevIndex, matchIndex));
sb.append(HtmlEntities.HTML_TO_NUMERIC_MAP.get(emit.getKeyword()));
prevIndex = emit.getEnd() + 1;
}
// Add the remainder of the string (contains no more matches).
sb.append(source.substring(prevIndex));
return sb.toString();
}
/**

View File

@@ -1,9 +1,11 @@
package com.commafeed.backend.feed;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
public class HtmlEntities {
public static final Map<String, String> HTML_TO_NUMERIC_MAP;
public static final String[] HTML_ENTITIES;
public static final String[] NUMERIC_ENTITIES;
@@ -260,6 +262,7 @@ public class HtmlEntities {
map.put("&zwj;", "&#8205;");
map.put("&zwnj;", "&#8204;");
HTML_TO_NUMERIC_MAP = Collections.unmodifiableMap(map);
HTML_ENTITIES = map.keySet().toArray(new String[map.size()]);
NUMERIC_ENTITIES = map.values().toArray(new String[map.size()]);
}

View File

@@ -8,11 +8,11 @@ import javax.persistence.Lob;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.annotations.Type;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.Type;
@Entity
@Table(name = "FEEDENTRYCONTENTS")
@SuppressWarnings("serial")
@@ -28,7 +28,7 @@ public class FeedEntryContent extends AbstractModel {
@Lob
@Column(length = Integer.MAX_VALUE)
@Type(type = "org.hibernate.type.StringClobType")
@Type(type = "org.hibernate.type.TextType")
private String content;
@Column(length = 40)

View File

@@ -10,11 +10,11 @@ import javax.persistence.Lob;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import org.hibernate.annotations.Type;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.Type;
@Entity
@Table(name = "USERSETTINGS")
@SuppressWarnings("serial")
@@ -61,7 +61,7 @@ public class UserSettings extends AbstractModel {
@Lob
@Column(length = Integer.MAX_VALUE)
@Type(type = "org.hibernate.type.StringClobType")
@Type(type = "org.hibernate.type.TextType")
private String customCss;
@Column(name = "scroll_speed")

View File

@@ -8,18 +8,19 @@ import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.ObjectUtils;
import com.commafeed.backend.dao.FeedCategoryDAO;
import com.commafeed.backend.dao.FeedSubscriptionDAO;
import com.commafeed.backend.model.FeedCategory;
import com.commafeed.backend.model.FeedSubscription;
import com.commafeed.backend.model.User;
import com.google.common.base.MoreObjects;
import com.rometools.opml.feed.opml.Attribute;
import com.rometools.opml.feed.opml.Opml;
import com.rometools.opml.feed.opml.Outline;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
@Singleton
public class OPMLExporter {
@@ -35,11 +36,11 @@ public class OPMLExporter {
List<FeedCategory> categories = feedCategoryDAO.findAll(user);
Collections.sort(categories,
(e1, e2) -> MoreObjects.firstNonNull(e1.getPosition(), 0) - MoreObjects.firstNonNull(e2.getPosition(), 0));
(e1, e2) -> ObjectUtils.firstNonNull(e1.getPosition(), 0) - ObjectUtils.firstNonNull(e2.getPosition(), 0));
List<FeedSubscription> subscriptions = feedSubscriptionDAO.findAll(user);
Collections.sort(subscriptions,
(e1, e2) -> MoreObjects.firstNonNull(e1.getPosition(), 0) - MoreObjects.firstNonNull(e2.getPosition(), 0));
(e1, e2) -> ObjectUtils.firstNonNull(e1.getPosition(), 0) - ObjectUtils.firstNonNull(e2.getPosition(), 0));
// export root categories
for (FeedCategory cat : categories.stream().filter(c -> c.getParent() == null).collect(Collectors.toList())) {

View File

@@ -1,5 +1,6 @@
package com.commafeed.backend.service;
import java.time.Year;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
@@ -91,6 +92,8 @@ public class FeedEntryFilteringService {
context.set("url", entry.getUrl() == null ? "" : entry.getUrl().toLowerCase());
context.set("categories", entry.getContent().getCategories() == null ? "" : entry.getContent().getCategories().toLowerCase());
context.set("year", Year.now().getValue());
Callable<Object> callable = script.callable(context);
Future<Object> future = executor.submit(callable);
Object result = null;

View File

@@ -0,0 +1,10 @@
package com.commafeed.backend.urlprovider;
/**
* Tries to find a feed url given the url and page content
*/
public interface FeedURLProvider {
String get(String url, String urlContent);
}

View File

@@ -0,0 +1,28 @@
package com.commafeed.backend.urlprovider;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
public class InPageReferenceFeedURLProvider implements FeedURLProvider {
@Override
public String get(String url, String urlContent) {
String foundUrl = null;
Document doc = Jsoup.parse(urlContent, url);
String root = doc.children().get(0).tagName();
if ("html".equals(root)) {
Elements atom = doc.select("link[type=application/atom+xml]");
Elements rss = doc.select("link[type=application/rss+xml]");
if (!atom.isEmpty()) {
foundUrl = atom.get(0).attr("abs:href");
} else if (!rss.isEmpty()) {
foundUrl = rss.get(0).attr("abs:href");
}
}
return foundUrl;
}
}

View File

@@ -0,0 +1,22 @@
package com.commafeed.backend.urlprovider;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Workaround for Youtube channels
*
* converts the channel URL https://www.youtube.com/channel/CHANNEL_ID to the valid feed URL
* https://www.youtube.com/feeds/videos.xml?channel_id=CHANNEL_ID
*/
public class YoutubeFeedURLProvider implements FeedURLProvider {
private static final Pattern REGEXP = Pattern.compile("(.*\\byoutube\\.com)\\/channel\\/([^\\/]+)", Pattern.CASE_INSENSITIVE);
@Override
public String get(String url, String urlContent) {
Matcher matcher = REGEXP.matcher(url);
return matcher.find() ? matcher.group(1) + "/feeds/videos.xml?channel_id=" + matcher.group(2) : null;
}
}

View File

@@ -9,28 +9,28 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@SuppressWarnings("serial")
@ApiModel("Entry details")
@ApiModel(description = "Entry details")
@Data
public class Category implements Serializable {
@ApiModelProperty("category id")
@ApiModelProperty(value = "category id", required = true)
private String id;
@ApiModelProperty("parent category id")
@ApiModelProperty(value = "parent category id")
private String parentId;
@ApiModelProperty("category id")
@ApiModelProperty(value = "category id", required = true)
private String name;
@ApiModelProperty("category children categories")
@ApiModelProperty(value = "category children categories", required = true)
private List<Category> children = new ArrayList<>();
@ApiModelProperty("category feeds")
@ApiModelProperty(value = "category feeds", required = true)
private List<Subscription> feeds = new ArrayList<>();
@ApiModelProperty("wether the category is expanded or collapsed")
@ApiModelProperty(value = "wether the category is expanded or collapsed", required = true)
private boolean expanded;
@ApiModelProperty("position of the category in the list")
@ApiModelProperty(value = "position of the category in the list", required = true)
private Integer position;
}

View File

@@ -9,38 +9,40 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@SuppressWarnings("serial")
@ApiModel("List of entries with some metadata")
@ApiModel(description = "List of entries with some metadata")
@Data
public class Entries implements Serializable {
@ApiModelProperty("name of the feed or the category requested")
@ApiModelProperty(value = "name of the feed or the category requested", required = true)
private String name;
@ApiModelProperty("error or warning message")
@ApiModelProperty(value = "error or warning message")
private String message;
@ApiModelProperty("times the server tried to refresh the feed and failed")
@ApiModelProperty(value = "times the server tried to refresh the feed and failed", required = true)
private int errorCount;
@ApiModelProperty("URL of the website, extracted from the feed")
@ApiModelProperty(value = "URL of the website, extracted from the feed", required = true)
private String feedLink;
@ApiModelProperty("list generation timestamp")
@ApiModelProperty(value = "list generation timestamp", required = true)
private long timestamp;
@ApiModelProperty("if the query has more elements")
@ApiModelProperty(value = "if the query has more elements", required = true)
private boolean hasMore;
@ApiModelProperty("the requested offset")
@ApiModelProperty(value = "the requested offset")
private int offset;
@ApiModelProperty("the requested limit")
@ApiModelProperty(value = "the requested limit")
private int limit;
@ApiModelProperty("list of entries")
@ApiModelProperty(value = "list of entries", required = true)
private List<Entry> entries = new ArrayList<>();
@ApiModelProperty("if true, the unread flag was ignored in the request, all entries are returned regardless of their read status")
@ApiModelProperty(
value = "if true, the unread flag was ignored in the request, all entries are returned regardless of their read status",
required = true)
private boolean ignoredReadStatus;
}

View File

@@ -25,7 +25,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@SuppressWarnings("serial")
@ApiModel("Entry details")
@ApiModel(description = "Entry details")
@Data
public class Entry implements Serializable {
@@ -58,7 +58,8 @@ public class Entry implements Serializable {
entry.setAuthor(content.getAuthor());
entry.setEnclosureType(content.getEnclosureType());
entry.setEnclosureUrl(proxyImages && StringUtils.contains(content.getEnclosureType(), "image")
? FeedUtils.proxyImage(content.getEnclosureUrl(), publicUrl) : content.getEnclosureUrl());
? FeedUtils.proxyImage(content.getEnclosureUrl(), publicUrl)
: content.getEnclosureUrl());
entry.setCategories(content.getCategories());
}
@@ -70,6 +71,7 @@ public class Entry implements Serializable {
entry.setUri(getGuid());
entry.setTitle(getTitle());
entry.setAuthor(getAuthor());
SyndContentImpl content = new SyndContentImpl();
content.setValue(getContent());
@@ -87,66 +89,66 @@ public class Entry implements Serializable {
return entry;
}
@ApiModelProperty("entry id")
@ApiModelProperty(value = "entry id", required = true)
private String id;
@ApiModelProperty("entry guid")
@ApiModelProperty(value = "entry guid", required = true)
private String guid;
@ApiModelProperty("entry title")
@ApiModelProperty(value = "entry title", required = true)
private String title;
@ApiModelProperty("entry content")
@ApiModelProperty(value = "entry content", required = true)
private String content;
@ApiModelProperty("comma-separated list of categories")
@ApiModelProperty(value = "comma-separated list of categories")
private String categories;
@ApiModelProperty("wether entry content and title are rtl")
@ApiModelProperty(value = "wether entry content and title are rtl", required = true)
private boolean rtl;
@ApiModelProperty("entry author")
@ApiModelProperty(value = "entry author")
private String author;
@ApiModelProperty("entry enclosure url, if any")
@ApiModelProperty(value = "entry enclosure url, if any")
private String enclosureUrl;
@ApiModelProperty("entry enclosure mime type, if any")
@ApiModelProperty(value = "entry enclosure mime type, if any")
private String enclosureType;
@ApiModelProperty("entry publication date")
@ApiModelProperty(value = "entry publication date", dataType = "number", required = true)
private Date date;
@ApiModelProperty("entry insertion date in the database")
@ApiModelProperty(value = "entry insertion date in the database", dataType = "number", required = true)
private Date insertedDate;
@ApiModelProperty("feed id")
@ApiModelProperty(value = "feed id", required = true)
private String feedId;
@ApiModelProperty("feed name")
@ApiModelProperty(value = "feed name", required = true)
private String feedName;
@ApiModelProperty("this entry's feed url")
@ApiModelProperty(value = "this entry's feed url", required = true)
private String feedUrl;
@ApiModelProperty("this entry's website url")
@ApiModelProperty(value = "this entry's website url", required = true)
private String feedLink;
@ApiModelProperty(value = "The favicon url to use for this feed")
@ApiModelProperty(value = "The favicon url to use for this feed", required = true)
private String iconUrl;
@ApiModelProperty("entry url")
@ApiModelProperty(value = "entry url", required = true)
private String url;
@ApiModelProperty("read sttaus")
@ApiModelProperty(value = "read status", required = true)
private boolean read;
@ApiModelProperty("starred status")
@ApiModelProperty(value = "starred status", required = true)
private boolean starred;
@ApiModelProperty("wether the entry is still markable (old entry statuses are discarded)")
@ApiModelProperty(value = "wether the entry is still markable (old entry statuses are discarded)", required = true)
private boolean markable;
@ApiModelProperty("tags")
@ApiModelProperty(value = "tags", required = true)
private List<String> tags;
}

View File

@@ -3,14 +3,18 @@ package com.commafeed.frontend.model;
import java.io.Serializable;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@SuppressWarnings("serial")
@ApiModel("Feed details")
@ApiModel(description = "Feed details")
@Data
public class FeedInfo implements Serializable {
@ApiModelProperty(value = "url", required = true)
private String url;
@ApiModelProperty(value = "title", required = true)
private String title;
}

View File

@@ -3,18 +3,30 @@ package com.commafeed.frontend.model;
import java.io.Serializable;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@SuppressWarnings("serial")
@ApiModel("Server infos")
@ApiModel(description = "Server infos")
@Data
public class ServerInfo implements Serializable {
@ApiModelProperty
private String announcement;
@ApiModelProperty(required = true)
private String version;
@ApiModelProperty(required = true)
private String gitCommit;
@ApiModelProperty(required = true)
private boolean allowRegistrations;
@ApiModelProperty
private String googleAnalyticsCode;
@ApiModelProperty(required = true)
private boolean smtpEnabled;
}

View File

@@ -7,11 +7,11 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@SuppressWarnings("serial")
@ApiModel("User settings")
@ApiModel(description = "User settings")
@Data
public class Settings implements Serializable {
@ApiModelProperty(value = "user's preferred language, english if none")
@ApiModelProperty(value = "user's preferred language, english if none", required = true)
private String language;
@ApiModelProperty(value = "user reads all entries or unread entries only", allowableValues = "all,unread", required = true)
@@ -35,18 +35,37 @@ public class Settings implements Serializable {
@ApiModelProperty(value = "user's custom css for the website")
private String customCss;
@ApiModelProperty(value = "user's preferred scroll speed when navigating between entries")
@ApiModelProperty(value = "user's preferred scroll speed when navigating between entries", required = true)
private int scrollSpeed;
@ApiModelProperty(required = true)
private boolean email;
@ApiModelProperty(required = true)
private boolean gmail;
@ApiModelProperty(required = true)
private boolean facebook;
@ApiModelProperty(required = true)
private boolean twitter;
@ApiModelProperty(required = true)
private boolean googleplus;
@ApiModelProperty(required = true)
private boolean tumblr;
@ApiModelProperty(required = true)
private boolean pocket;
@ApiModelProperty(required = true)
private boolean instapaper;
@ApiModelProperty(required = true)
private boolean buffer;
@ApiModelProperty(required = true)
private boolean readability;
}

View File

@@ -13,7 +13,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@SuppressWarnings("serial")
@ApiModel("User information")
@ApiModel(description = "User information")
@Data
public class Subscription implements Serializable {
@@ -51,10 +51,13 @@ public class Subscription implements Serializable {
@ApiModelProperty(value = "error count", required = true)
private int errorCount;
@ApiModelProperty(value = "last time the feed was refreshed", required = true)
@ApiModelProperty(value = "last time the feed was refreshed", dataType = "number", required = true)
private Date lastRefresh;
@ApiModelProperty(value = "next time the feed refresh is planned, null if refresh is already queued", required = true)
@ApiModelProperty(
value = "next time the feed refresh is planned, null if refresh is already queued",
dataType = "number",
required = true)
private Date nextRefresh;
@ApiModelProperty(value = "this subscription's feed url", required = true)
@@ -63,7 +66,7 @@ public class Subscription implements Serializable {
@ApiModelProperty(value = "this subscription's website url", required = true)
private String feedLink;
@ApiModelProperty(value = "The favicon url to use for this feed")
@ApiModelProperty(value = "The favicon url to use for this feed", required = true)
private String iconUrl;
@ApiModelProperty(value = "unread count", required = true)
@@ -75,7 +78,7 @@ public class Subscription implements Serializable {
@ApiModelProperty("position of the subscription's in the list")
private Integer position;
@ApiModelProperty("date of the newest item")
@ApiModelProperty(value = "date of the newest item", dataType = "number")
private Date newestItemTime;
@ApiModelProperty(value = "JEXL string evaluated on new entries to mark them as read if they do not match")

View File

@@ -4,15 +4,21 @@ import java.io.Serializable;
import java.util.Date;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@SuppressWarnings("serial")
@ApiModel("Unread count")
@ApiModel(description = "Unread count")
@Data
public class UnreadCount implements Serializable {
@ApiModelProperty
private long feedId;
@ApiModelProperty
private long unreadCount;
@ApiModelProperty(dataType = "number")
private Date newestItemTime;
public UnreadCount() {

View File

@@ -8,7 +8,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@SuppressWarnings("serial")
@ApiModel("User information")
@ApiModel(description = "User information")
@Data
public class UserModel implements Serializable {
@@ -27,16 +27,16 @@ public class UserModel implements Serializable {
@ApiModelProperty(value = "user password, never returned by the api")
private String password;
@ApiModelProperty(value = "account status")
@ApiModelProperty(value = "account status", required = true)
private boolean enabled;
@ApiModelProperty(value = "account creation date")
@ApiModelProperty(value = "account creation date", dataType = "number", required = true)
private Date created;
@ApiModelProperty(value = "last login date")
@ApiModelProperty(value = "last login date", dataType = "number")
private Date lastLogin;
@ApiModelProperty(value = "user is admin")
@ApiModelProperty(value = "user is admin", required = true)
private boolean admin;
}

View File

@@ -7,7 +7,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@SuppressWarnings("serial")
@ApiModel("Add Category Request")
@ApiModel(description = "Add Category Request")
@Data
public class AddCategoryRequest implements Serializable {

View File

@@ -7,7 +7,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@SuppressWarnings("serial")
@ApiModel("Category modification request")
@ApiModel(description = "Category modification request")
@Data
public class CategoryModificationRequest implements Serializable {

View File

@@ -7,7 +7,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@SuppressWarnings("serial")
@ApiModel("Mark Request")
@ApiModel(description = "Mark Request")
@Data
public class CollapseRequest implements Serializable {

View File

@@ -7,7 +7,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@SuppressWarnings("serial")
@ApiModel("Feed information request")
@ApiModel(description = "Feed information request")
@Data
public class FeedInfoRequest implements Serializable {

View File

@@ -8,7 +8,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@SuppressWarnings("serial")
@ApiModel("Feed merge Request")
@ApiModel(description = "Feed merge Request")
@Data
public class FeedMergeRequest implements Serializable {

View File

@@ -7,7 +7,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@SuppressWarnings("serial")
@ApiModel("Feed modification request")
@ApiModel(description = "Feed modification request")
@Data
public class FeedModificationRequest implements Serializable {

View File

@@ -11,7 +11,7 @@ import lombok.Data;
@Data
public class IDRequest implements Serializable {
@ApiModelProperty
@ApiModelProperty(required = true)
private Long id;
}

View File

@@ -8,14 +8,14 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@SuppressWarnings("serial")
@ApiModel("Mark Request")
@ApiModel(description = "Mark Request")
@Data
public class MarkRequest implements Serializable {
@ApiModelProperty(value = "entry id, category id, 'all' or 'starred'", required = true)
private String id;
@ApiModelProperty(value = "mark as read or unread")
@ApiModelProperty(value = "mark as read or unread", required = true)
private boolean read;
@ApiModelProperty(
@@ -25,7 +25,7 @@ public class MarkRequest implements Serializable {
@ApiModelProperty(value = "only mark read if a feed has these keywords in the title or rss content", required = false)
private String keywords;
@ApiModelProperty(value = "if marking a category or 'all', exclude those subscriptions from the marking", required = false)
private List<Long> excludedSubscriptions;

View File

@@ -8,7 +8,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@SuppressWarnings("serial")
@ApiModel("Multiple Mark Request")
@ApiModel(description = "Multiple Mark Request")
@Data
public class MultipleMarkRequest implements Serializable {

View File

@@ -7,7 +7,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@SuppressWarnings("serial")
@ApiModel("Profile modification request")
@ApiModel(description = "Profile modification request")
@Data
public class ProfileModificationRequest implements Serializable {

View File

@@ -7,7 +7,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@SuppressWarnings("serial")
@ApiModel("Star Request")
@ApiModel(description = "Star Request")
@Data
public class StarRequest implements Serializable {
@@ -17,7 +17,7 @@ public class StarRequest implements Serializable {
@ApiModelProperty(value = "feed id", required = true)
private Long feedId;
@ApiModelProperty(value = "starred or not")
@ApiModelProperty(value = "starred or not", required = true)
private boolean starred;
}

View File

@@ -7,7 +7,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@SuppressWarnings("serial")
@ApiModel("Subscription request")
@ApiModel(description = "Subscription request")
@Data
public class SubscribeRequest implements Serializable {

View File

@@ -8,14 +8,14 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@SuppressWarnings("serial")
@ApiModel("Tag Request")
@ApiModel(description = "Tag Request")
@Data
public class TagRequest implements Serializable {
@ApiModelProperty(value = "entry id", required = true)
private Long entryId;
@ApiModelProperty(value = "tags")
@ApiModelProperty(value = "tags", required = true)
private List<String> tags;
}

View File

@@ -46,7 +46,7 @@ import lombok.RequiredArgsConstructor;
@Api(value = "/admin")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@RequiredArgsConstructor(onConstructor = @__({ @Inject }) )
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
@Singleton
public class AdminREST {
@@ -62,7 +62,8 @@ public class AdminREST {
@UnitOfWork
@ApiOperation(value = "Save or update a user", notes = "Save or update a user. If the id is not specified, a new user will be created")
@Timed
public Response save(@SecurityCheck(Role.ADMIN) User user, @ApiParam(required = true) UserModel userModel) {
public Response adminSaveUser(@ApiParam(hidden = true) @SecurityCheck(Role.ADMIN) User user,
@ApiParam(required = true) UserModel userModel) {
Preconditions.checkNotNull(userModel);
Preconditions.checkNotNull(userModel.getName());
@@ -117,7 +118,8 @@ public class AdminREST {
@UnitOfWork
@ApiOperation(value = "Get user information", notes = "Get user information", response = UserModel.class)
@Timed
public Response getUser(@SecurityCheck(Role.ADMIN) User user, @ApiParam(value = "user id", required = true) @PathParam("id") Long id) {
public Response adminGetUser(@ApiParam(hidden = true) @SecurityCheck(Role.ADMIN) User user,
@ApiParam(value = "user id", required = true) @PathParam("id") Long id) {
Preconditions.checkNotNull(id);
User u = userDAO.findById(id);
UserModel userModel = new UserModel();
@@ -134,7 +136,7 @@ public class AdminREST {
@UnitOfWork
@ApiOperation(value = "Get all users", notes = "Get all users", response = UserModel.class, responseContainer = "List")
@Timed
public Response getUsers(@SecurityCheck(Role.ADMIN) User user) {
public Response adminGetUsers(@ApiParam(hidden = true) @SecurityCheck(Role.ADMIN) User user) {
Map<Long, UserModel> users = new HashMap<>();
for (UserRole role : userRoleDAO.findAll()) {
User u = role.getUser();
@@ -162,7 +164,8 @@ public class AdminREST {
@UnitOfWork
@ApiOperation(value = "Delete a user", notes = "Delete a user, and all his subscriptions")
@Timed
public Response delete(@SecurityCheck(Role.ADMIN) User user, @ApiParam(required = true) IDRequest req) {
public Response adminDeleteUser(@ApiParam(hidden = true) @SecurityCheck(Role.ADMIN) User user,
@ApiParam(required = true) IDRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
@@ -182,7 +185,7 @@ public class AdminREST {
@UnitOfWork
@ApiOperation(value = "Retrieve application settings", notes = "Retrieve application settings", response = ApplicationSettings.class)
@Timed
public Response getSettings(@SecurityCheck(Role.ADMIN) User user) {
public Response getApplicationSettings(@ApiParam(hidden = true) @SecurityCheck(Role.ADMIN) User user) {
return Response.ok(config.getApplicationSettings()).build();
}
@@ -191,7 +194,7 @@ public class AdminREST {
@UnitOfWork
@ApiOperation(value = "Retrieve server metrics")
@Timed
public Response getMetrics(@SecurityCheck(Role.ADMIN) User user) {
public Response getMetrics(@ApiParam(hidden = true) @SecurityCheck(Role.ADMIN) User user) {
return Response.ok(metrics).build();
}

View File

@@ -74,7 +74,7 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@RequiredArgsConstructor(onConstructor = @__({ @Inject }) )
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
@Singleton
public class CategoryREST {
@@ -94,7 +94,7 @@ public class CategoryREST {
@UnitOfWork
@ApiOperation(value = "Get category entries", notes = "Get a list of category entries", response = Entries.class)
@Timed
public Response getCategoryEntries(@SecurityCheck User user,
public Response getCategoryEntries(@ApiParam(hidden = true) @SecurityCheck User user,
@ApiParam(value = "id of the category, 'all' or 'starred'", required = true) @QueryParam("id") String id,
@ApiParam(
value = "all entries or only unread ones",
@@ -103,7 +103,9 @@ public class CategoryREST {
@ApiParam(value = "only entries newer than this") @QueryParam("newerThan") Long newerThan,
@ApiParam(value = "offset for paging") @DefaultValue("0") @QueryParam("offset") int offset,
@ApiParam(value = "limit for paging, default 20, maximum 1000") @DefaultValue("20") @QueryParam("limit") int limit,
@ApiParam(value = "ordering", allowableValues = "asc,desc,abc,zyx") @QueryParam("order") @DefaultValue("desc") ReadingOrder order,
@ApiParam(
value = "ordering",
allowableValues = "asc,desc,abc,zyx") @QueryParam("order") @DefaultValue("desc") ReadingOrder order,
@ApiParam(
value = "search for keywords in either the title or the content of the entries, separated by spaces, 3 characters minimum") @QueryParam("keywords") String keywords,
@ApiParam(value = "return only entry ids") @DefaultValue("false") @QueryParam("onlyIds") boolean onlyIds,
@@ -191,7 +193,7 @@ public class CategoryREST {
@ApiOperation(value = "Get category entries as feed", notes = "Get a feed of category entries")
@Produces(MediaType.APPLICATION_XML)
@Timed
public Response getCategoryEntriesAsFeed(@SecurityCheck(apiKeyAllowed = true) User user,
public Response getCategoryEntriesAsFeed(@ApiParam(hidden = true) @SecurityCheck(apiKeyAllowed = true) User user,
@ApiParam(value = "id of the category, 'all' or 'starred'", required = true) @QueryParam("id") String id,
@ApiParam(
value = "all entries or only unread ones",
@@ -238,7 +240,7 @@ public class CategoryREST {
@UnitOfWork
@ApiOperation(value = "Mark category entries", notes = "Mark feed entries of this category as read")
@Timed
public Response markCategoryEntries(@SecurityCheck User user,
public Response markCategoryEntries(@ApiParam(hidden = true) @SecurityCheck User user,
@ApiParam(value = "category id, or 'all'", required = true) MarkRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
@@ -280,7 +282,7 @@ public class CategoryREST {
@UnitOfWork
@ApiOperation(value = "Add a category", notes = "Add a new feed category", response = Long.class)
@Timed
public Response addCategory(@SecurityCheck User user, @ApiParam(required = true) AddCategoryRequest req) {
public Response addCategory(@ApiParam(hidden = true) @SecurityCheck User user, @ApiParam(required = true) AddCategoryRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getName());
@@ -304,7 +306,7 @@ public class CategoryREST {
@UnitOfWork
@ApiOperation(value = "Delete a category", notes = "Delete an existing feed category")
@Timed
public Response deleteCategory(@SecurityCheck User user, @ApiParam(required = true) IDRequest req) {
public Response deleteCategory(@ApiParam(hidden = true) @SecurityCheck User user, @ApiParam(required = true) IDRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
@@ -337,7 +339,8 @@ public class CategoryREST {
@UnitOfWork
@ApiOperation(value = "Rename a category", notes = "Rename an existing feed category")
@Timed
public Response modifyCategory(@SecurityCheck User user, @ApiParam(required = true) CategoryModificationRequest req) {
public Response modifyCategory(@ApiParam(hidden = true) @SecurityCheck User user,
@ApiParam(required = true) CategoryModificationRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
@@ -392,7 +395,7 @@ public class CategoryREST {
@UnitOfWork
@ApiOperation(value = "Collapse a category", notes = "Save collapsed or expanded status for a category")
@Timed
public Response collapse(@SecurityCheck User user, @ApiParam(required = true) CollapseRequest req) {
public Response collapseCategory(@ApiParam(hidden = true) @SecurityCheck User user, @ApiParam(required = true) CollapseRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
@@ -411,7 +414,7 @@ public class CategoryREST {
@UnitOfWork
@ApiOperation(value = "Get unread count for feed subscriptions", response = UnreadCount.class, responseContainer = "List")
@Timed
public Response getUnreadCount(@SecurityCheck User user) {
public Response getUnreadCount(@ApiParam(hidden = true) @SecurityCheck User user) {
Map<Long, UnreadCount> unreadCount = feedSubscriptionService.getUnreadCount(user);
return Response.ok(Lists.newArrayList(unreadCount.values())).build();
}
@@ -419,9 +422,9 @@ public class CategoryREST {
@GET
@Path("/get")
@UnitOfWork
@ApiOperation(value = "Get feed categories", notes = "Get all categories and subscriptions of the user", response = Category.class)
@ApiOperation(value = "Get root category", notes = "Get all categories and subscriptions of the user", response = Category.class)
@Timed
public Response getSubscriptions(@SecurityCheck User user) {
public Response getRootCategory(@ApiParam(hidden = true) @SecurityCheck User user) {
Category root = cache.getUserRootCategory(user);
if (root == null) {
log.debug("tree cache miss for {}", user.getId());

View File

@@ -34,7 +34,7 @@ import lombok.RequiredArgsConstructor;
@Api(value = "/entry")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@RequiredArgsConstructor(onConstructor = @__({ @Inject }) )
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
@Singleton
public class EntryREST {
@@ -47,7 +47,8 @@ public class EntryREST {
@UnitOfWork
@ApiOperation(value = "Mark a feed entry", notes = "Mark a feed entry as read/unread")
@Timed
public Response markFeedEntry(@SecurityCheck User user, @ApiParam(value = "Mark Request", required = true) MarkRequest req) {
public Response markEntry(@ApiParam(hidden = true) @SecurityCheck User user,
@ApiParam(value = "Mark Request", required = true) MarkRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
@@ -60,13 +61,13 @@ public class EntryREST {
@UnitOfWork
@ApiOperation(value = "Mark multiple feed entries", notes = "Mark feed entries as read/unread")
@Timed
public Response markFeedEntries(@SecurityCheck User user,
public Response markEntries(@ApiParam(hidden = true) @SecurityCheck User user,
@ApiParam(value = "Multiple Mark Request", required = true) MultipleMarkRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getRequests());
for (MarkRequest r : req.getRequests()) {
markFeedEntry(user, r);
markEntry(user, r);
}
return Response.ok().build();
@@ -77,7 +78,8 @@ public class EntryREST {
@UnitOfWork
@ApiOperation(value = "Mark a feed entry", notes = "Mark a feed entry as read/unread")
@Timed
public Response starFeedEntry(@SecurityCheck User user, @ApiParam(value = "Star Request", required = true) StarRequest req) {
public Response starEntry(@ApiParam(hidden = true) @SecurityCheck User user,
@ApiParam(value = "Star Request", required = true) StarRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
Preconditions.checkNotNull(req.getFeedId());
@@ -92,7 +94,7 @@ public class EntryREST {
@UnitOfWork
@ApiOperation(value = "Get list of tags for the user", notes = "Get list of tags for the user")
@Timed
public Response getTags(@SecurityCheck User user) {
public Response getTags(@ApiParam(hidden = true) @SecurityCheck User user) {
List<String> tags = feedEntryTagDAO.findByUser(user);
return Response.ok(tags).build();
}
@@ -102,7 +104,8 @@ public class EntryREST {
@UnitOfWork
@ApiOperation(value = "Mark a feed entry", notes = "Mark a feed entry as read/unread")
@Timed
public Response tagFeedEntry(@SecurityCheck User user, @ApiParam(value = "Tag Request", required = true) TagRequest req) {
public Response tagEntry(@ApiParam(hidden = true) @SecurityCheck User user,
@ApiParam(value = "Tag Request", required = true) TagRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getEntryId());

View File

@@ -95,7 +95,7 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@RequiredArgsConstructor(onConstructor = @__({ @Inject }) )
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
@Singleton
public class FeedREST {
@@ -132,7 +132,7 @@ public class FeedREST {
@UnitOfWork
@ApiOperation(value = "Get feed entries", notes = "Get a list of feed entries", response = Entries.class)
@Timed
public Response getFeedEntries(@SecurityCheck User user,
public Response getFeedEntries(@ApiParam(hidden = true) @SecurityCheck User user,
@ApiParam(value = "id of the feed", required = true) @QueryParam("id") String id,
@ApiParam(
value = "all entries or only unread ones",
@@ -141,7 +141,9 @@ public class FeedREST {
@ApiParam(value = "only entries newer than this") @QueryParam("newerThan") Long newerThan,
@ApiParam(value = "offset for paging") @DefaultValue("0") @QueryParam("offset") int offset,
@ApiParam(value = "limit for paging, default 20, maximum 1000") @DefaultValue("20") @QueryParam("limit") int limit,
@ApiParam(value = "ordering", allowableValues = "asc,desc,abc,zyx") @QueryParam("order") @DefaultValue("desc") ReadingOrder order,
@ApiParam(
value = "ordering",
allowableValues = "asc,desc,abc,zyx") @QueryParam("order") @DefaultValue("desc") ReadingOrder order,
@ApiParam(
value = "search for keywords in either the title or the content of the entries, separated by spaces, 3 characters minimum") @QueryParam("keywords") String keywords,
@ApiParam(value = "return only entry ids") @DefaultValue("false") @QueryParam("onlyIds") boolean onlyIds) {
@@ -200,7 +202,7 @@ public class FeedREST {
@ApiOperation(value = "Get feed entries as a feed", notes = "Get a feed of feed entries")
@Produces(MediaType.APPLICATION_XML)
@Timed
public Response getFeedEntriesAsFeed(@SecurityCheck(apiKeyAllowed = true) User user,
public Response getFeedEntriesAsFeed(@ApiParam(hidden = true) @SecurityCheck(apiKeyAllowed = true) User user,
@ApiParam(value = "id of the feed", required = true) @QueryParam("id") String id,
@ApiParam(
value = "all entries or only unread ones",
@@ -260,7 +262,8 @@ public class FeedREST {
@UnitOfWork
@ApiOperation(value = "Fetch a feed", notes = "Fetch a feed by its url", response = FeedInfo.class)
@Timed
public Response fetchFeed(@SecurityCheck User user, @ApiParam(value = "feed url", required = true) FeedInfoRequest req) {
public Response fetchFeed(@ApiParam(hidden = true) @SecurityCheck User user,
@ApiParam(value = "feed url", required = true) FeedInfoRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getUrl());
@@ -279,7 +282,7 @@ public class FeedREST {
@UnitOfWork
@ApiOperation(value = "Queue all feeds of the user for refresh", notes = "Manually add all feeds of the user to the refresh queue")
@Timed
public Response queueAllForRefresh(@SecurityCheck User user) {
public Response queueAllForRefresh(@ApiParam(hidden = true) @SecurityCheck User user) {
feedSubscriptionService.refreshAll(user);
return Response.ok().build();
}
@@ -289,7 +292,8 @@ public class FeedREST {
@UnitOfWork
@ApiOperation(value = "Queue a feed for refresh", notes = "Manually add a feed to the refresh queue")
@Timed
public Response queueForRefresh(@SecurityCheck User user, @ApiParam(value = "Feed id") IDRequest req) {
public Response queueForRefresh(@ApiParam(hidden = true) @SecurityCheck User user,
@ApiParam(value = "Feed id", required = true) IDRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
@@ -308,7 +312,8 @@ public class FeedREST {
@UnitOfWork
@ApiOperation(value = "Mark feed entries", notes = "Mark feed entries as read (unread is not supported)")
@Timed
public Response markFeedEntries(@SecurityCheck User user, @ApiParam(value = "Mark request") MarkRequest req) {
public Response markFeedEntries(@ApiParam(hidden = true) @SecurityCheck User user,
@ApiParam(value = "Mark request", required = true) MarkRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
@@ -326,9 +331,10 @@ public class FeedREST {
@GET
@Path("/get/{id}")
@UnitOfWork
@ApiOperation(value = "", notes = "")
@ApiOperation(value = "get feed", response = Subscription.class)
@Timed
public Response get(@SecurityCheck User user, @ApiParam(value = "user id", required = true) @PathParam("id") Long id) {
public Response getFeed(@ApiParam(hidden = true) @SecurityCheck User user,
@ApiParam(value = "user id", required = true) @PathParam("id") Long id) {
Preconditions.checkNotNull(id);
FeedSubscription sub = feedSubscriptionDAO.findById(user, id);
@@ -344,7 +350,8 @@ public class FeedREST {
@UnitOfWork
@ApiOperation(value = "Fetch a feed's icon", notes = "Fetch a feed's icon")
@Timed
public Response getFavicon(@SecurityCheck User user, @ApiParam(value = "subscription id") @PathParam("id") Long id) {
public Response getFeedFavicon(@ApiParam(hidden = true) @SecurityCheck User user,
@ApiParam(value = "subscription id", required = true) @PathParam("id") Long id) {
Preconditions.checkNotNull(id);
FeedSubscription subscription = feedSubscriptionDAO.findById(user, id);
@@ -374,7 +381,8 @@ public class FeedREST {
@UnitOfWork
@ApiOperation(value = "Subscribe to a feed", notes = "Subscribe to a feed")
@Timed
public Response subscribe(@SecurityCheck User user, @ApiParam(value = "subscription request", required = true) SubscribeRequest req) {
public Response subscribe(@ApiParam(hidden = true) @SecurityCheck User user,
@ApiParam(value = "subscription request", required = true) SubscribeRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getTitle());
Preconditions.checkNotNull(req.getUrl());
@@ -401,7 +409,8 @@ public class FeedREST {
@UnitOfWork
@ApiOperation(value = "Subscribe to a feed", notes = "Subscribe to a feed")
@Timed
public Response subscribe(@SecurityCheck User user, @ApiParam(value = "feed url", required = true) @QueryParam("url") String url) {
public Response subscribeFromUrl(@ApiParam(hidden = true) @SecurityCheck User user,
@ApiParam(value = "feed url", required = true) @QueryParam("url") String url) {
try {
Preconditions.checkNotNull(url);
@@ -429,7 +438,7 @@ public class FeedREST {
@UnitOfWork
@ApiOperation(value = "Unsubscribe from a feed", notes = "Unsubscribe from a feed")
@Timed
public Response unsubscribe(@SecurityCheck User user, @ApiParam(required = true) IDRequest req) {
public Response unsubscribe(@ApiParam(hidden = true) @SecurityCheck User user, @ApiParam(required = true) IDRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
@@ -446,7 +455,8 @@ public class FeedREST {
@UnitOfWork
@ApiOperation(value = "Modify a subscription", notes = "Modify a feed subscription")
@Timed
public Response modify(@SecurityCheck User user, @ApiParam(value = "subscription id", required = true) FeedModificationRequest req) {
public Response modifyFeed(@ApiParam(hidden = true) @SecurityCheck User user,
@ApiParam(value = "subscription id", required = true) FeedModificationRequest req) {
Preconditions.checkNotNull(req);
Preconditions.checkNotNull(req.getId());
@@ -506,7 +516,8 @@ public class FeedREST {
@Consumes(MediaType.MULTIPART_FORM_DATA)
@ApiOperation(value = "OPML import", notes = "Import an OPML file, posted as a FORM with the 'file' name")
@Timed
public Response importOpml(@SecurityCheck User user, @FormDataParam("file") InputStream input) {
public Response importOpml(@ApiParam(hidden = true) @SecurityCheck User user,
@ApiParam(value = "ompl file", required = true) @FormDataParam("file") InputStream input) {
String publicUrl = config.getApplicationSettings().getPublicUrl();
if (StringUtils.isBlank(publicUrl)) {
@@ -533,7 +544,7 @@ public class FeedREST {
@Produces(MediaType.APPLICATION_XML)
@ApiOperation(value = "OPML export", notes = "Export an OPML file of the user's subscriptions")
@Timed
public Response exportOpml(@SecurityCheck User user) {
public Response exportOpml(@ApiParam(hidden = true) @SecurityCheck User user) {
Opml opml = opmlExporter.export(user);
WireFeedOutput output = new WireFeedOutput();
String opmlString = null;

View File

@@ -25,13 +25,14 @@ import com.commafeed.frontend.model.ServerInfo;
import io.dropwizard.hibernate.UnitOfWork;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
@Path("/server")
@Api(value = "/server")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@RequiredArgsConstructor(onConstructor = @__({ @Inject }) )
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
@Singleton
public class ServerREST {
@@ -43,7 +44,7 @@ public class ServerREST {
@UnitOfWork
@ApiOperation(value = "Get server infos", notes = "Get server infos", response = ServerInfo.class)
@Timed
public Response get() {
public Response getServerInfos() {
ServerInfo infos = new ServerInfo();
infos.setAnnouncement(config.getApplicationSettings().getAnnouncement());
infos.setVersion(config.getVersion());
@@ -60,7 +61,8 @@ public class ServerREST {
@ApiOperation(value = "proxy image")
@Produces("image/png")
@Timed
public Response get(@SecurityCheck User user, @QueryParam("u") String url) {
public Response getProxiedImage(@ApiParam(hidden = true) @SecurityCheck User user,
@ApiParam(value = "image url", required = true) @QueryParam("u") String url) {
if (!config.getApplicationSettings().getImageProxyEnabled()) {
return Response.status(Status.FORBIDDEN).build();
}

View File

@@ -83,7 +83,7 @@ public class UserREST {
@UnitOfWork
@ApiOperation(value = "Retrieve user settings", notes = "Retrieve user settings", response = Settings.class)
@Timed
public Response getSettings(@SecurityCheck User user) {
public Response getUserSettings(@ApiParam(hidden = true) @SecurityCheck User user) {
Settings s = new Settings();
UserSettings settings = userSettingsDAO.findByUser(user);
if (settings != null) {
@@ -138,7 +138,7 @@ public class UserREST {
@UnitOfWork
@ApiOperation(value = "Save user settings", notes = "Save user settings")
@Timed
public Response saveSettings(@SecurityCheck User user, @ApiParam(required = true) Settings settings) {
public Response saveUserSettings(@ApiParam(hidden = true) @SecurityCheck User user, @ApiParam(required = true) Settings settings) {
Preconditions.checkNotNull(settings);
UserSettings s = userSettingsDAO.findByUser(user);
@@ -177,7 +177,7 @@ public class UserREST {
@UnitOfWork
@ApiOperation(value = "Retrieve user's profile", response = UserModel.class)
@Timed
public Response get(@SecurityCheck User user) {
public Response getUserProfile(@ApiParam(hidden = true) @SecurityCheck User user) {
UserModel userModel = new UserModel();
userModel.setId(user.getId());
userModel.setName(user.getName());
@@ -197,7 +197,8 @@ public class UserREST {
@UnitOfWork
@ApiOperation(value = "Save user's profile")
@Timed
public Response save(@SecurityCheck User user, @ApiParam(required = true) ProfileModificationRequest request) {
public Response saveUserProfile(@ApiParam(hidden = true) @SecurityCheck User user,
@ApiParam(required = true) ProfileModificationRequest request) {
Preconditions.checkArgument(StringUtils.isBlank(request.getPassword()) || request.getPassword().length() >= 6);
if (StringUtils.isNotBlank(request.getEmail())) {
User u = userDAO.findByEmail(request.getEmail());
@@ -226,7 +227,8 @@ public class UserREST {
@UnitOfWork
@ApiOperation(value = "Register a new account")
@Timed
public Response register(@Valid @ApiParam(required = true) RegistrationRequest req, @Context SessionHelper sessionHelper) {
public Response registerUser(@Valid @ApiParam(required = true) RegistrationRequest req,
@Context @ApiParam(hidden = true) SessionHelper sessionHelper) {
try {
User registeredUser = userService.register(req.getName(), req.getPassword(), req.getEmail(), Arrays.asList(Role.USER));
userService.login(req.getName(), req.getPassword());
@@ -243,7 +245,7 @@ public class UserREST {
@UnitOfWork
@ApiOperation(value = "Login and create a session")
@Timed
public Response login(@ApiParam(required = true) LoginRequest req, @Context SessionHelper sessionHelper) {
public Response login(@ApiParam(required = true) LoginRequest req, @ApiParam(hidden = true) @Context SessionHelper sessionHelper) {
Optional<User> user = userService.login(req.getName(), req.getPassword());
if (user.isPresent()) {
sessionHelper.setLoggedInUser(user.get());
@@ -258,7 +260,7 @@ public class UserREST {
@UnitOfWork
@ApiOperation(value = "send a password reset email")
@Timed
public Response sendPasswordReset(@Valid PasswordResetRequest req) {
public Response sendPasswordReset(@Valid @ApiParam(required = true) PasswordResetRequest req) {
User user = userDAO.findByEmail(req.getEmail());
if (user == null) {
return Response.status(Status.PRECONDITION_FAILED).entity("Email not found.").type(MediaType.TEXT_PLAIN).build();
@@ -294,7 +296,8 @@ public class UserREST {
@UnitOfWork
@Produces(MediaType.TEXT_HTML)
@Timed
public Response passwordRecoveryCallback(@QueryParam("email") String email, @QueryParam("token") String token) {
public Response passwordRecoveryCallback(@ApiParam(required = true) @QueryParam("email") String email,
@ApiParam(required = true) @QueryParam("token") String token) {
Preconditions.checkNotNull(email);
Preconditions.checkNotNull(token);
@@ -330,7 +333,7 @@ public class UserREST {
@UnitOfWork
@ApiOperation(value = "Delete the user account")
@Timed
public Response delete(@SecurityCheck User user) {
public Response deleteUser(@ApiParam(hidden = true) @SecurityCheck User user) {
if (CommaFeedApplication.USERNAME_ADMIN.equals(user.getName()) || CommaFeedApplication.USERNAME_DEMO.equals(user.getName())) {
return Response.status(Status.FORBIDDEN).build();
}

View File

@@ -0,0 +1,48 @@
package com.commafeed.frontend.session;
import java.io.File;
import javax.servlet.SessionTrackingMode;
import org.eclipse.jetty.server.session.DefaultSessionCache;
import org.eclipse.jetty.server.session.FileSessionDataStore;
import org.eclipse.jetty.server.session.SessionCache;
import org.eclipse.jetty.server.session.SessionHandler;
import com.google.common.collect.ImmutableSet;
import io.dropwizard.util.Duration;
public class SessionHandlerFactory {
private String path = "sessions";
private Duration cookieMaxAge = Duration.days(30);
private Duration cookieRefreshAge = Duration.days(1);
private Duration maxInactiveInterval = Duration.days(30);
private Duration savePeriod = Duration.minutes(5);
public SessionHandler build() {
SessionHandler sessionHandler = new SessionHandler() {
{
// no setter available for maxCookieAge
_maxCookieAge = (int) cookieMaxAge.toSeconds();
}
};
SessionCache sessionCache = new DefaultSessionCache(sessionHandler);
sessionHandler.setSessionCache(sessionCache);
FileSessionDataStore dataStore = new FileSessionDataStore();
sessionCache.setSessionDataStore(dataStore);
sessionHandler.setHttpOnly(true);
sessionHandler.setSessionTrackingModes(ImmutableSet.of(SessionTrackingMode.COOKIE));
sessionHandler.setMaxInactiveInterval((int) maxInactiveInterval.toSeconds());
sessionHandler.setRefreshCookieAge((int) cookieRefreshAge.toSeconds());
dataStore.setDeleteUnrestorableFiles(true);
dataStore.setStoreDir(new File(path));
dataStore.setSavePeriodSec((int) savePeriod.toSeconds());
return sessionHandler;
}
}

View File

@@ -1,45 +0,0 @@
package com.commafeed.frontend.session;
import io.dropwizard.util.Duration;
import java.io.File;
import java.io.IOException;
import javax.servlet.SessionTrackingMode;
import lombok.Getter;
import org.eclipse.jetty.server.SessionManager;
import org.eclipse.jetty.server.session.HashSessionManager;
import com.google.common.collect.ImmutableSet;
@Getter
public class SessionManagerFactory {
private String path = "sessions";
private Duration cookieMaxAge = Duration.days(30);
private Duration cookieRefreshAge = Duration.days(1);
private Duration maxInactiveInterval = Duration.days(30);
private Duration idleSavePeriod = Duration.hours(2);
private Duration savePeriod = Duration.minutes(5);
private Duration scavengePeriod = Duration.minutes(5);
public SessionManager build() throws IOException {
HashSessionManager manager = new HashSessionManager();
manager.setSessionTrackingModes(ImmutableSet.of(SessionTrackingMode.COOKIE));
manager.setHttpOnly(true);
manager.getSessionCookieConfig().setHttpOnly(true);
manager.setDeleteUnrestorableSessions(true);
manager.setStoreDirectory(new File(getPath()));
manager.getSessionCookieConfig().setMaxAge((int) cookieMaxAge.toSeconds());
manager.setRefreshCookieAge((int) cookieRefreshAge.toSeconds());
manager.setMaxInactiveInterval((int) maxInactiveInterval.toSeconds());
manager.setIdleSavePeriod((int) idleSavePeriod.toSeconds());
manager.setSavePeriod((int) savePeriod.toSeconds());
manager.setScavengePeriod((int) scavengePeriod.toSeconds());
return manager;
}
}

View File

@@ -6,6 +6,7 @@
<changeSet author="athou" id="create-app-settings">
<validCheckSum>7:6d3ad493d25dd9c50067e804efc9ffcc</validCheckSum>
<validCheckSum>7:896a68c1651397288c40f717ce0397b4</validCheckSum>
<validCheckSum>8:1b0879c4739d483c3b1d779e08fe770b</validCheckSum>
<preConditions onFail="MARK_RAN" onFailMessage="existing table skipping">
<not>
<tableExists tableName="APPLICATIONSETTINGS" />
@@ -15,7 +16,7 @@
<column name="id" type="BIGINT">
<constraints nullable="false" primaryKey="true" />
</column>
<column name="allowRegistrations" type="BIT">
<column name="allowRegistrations" type="BOOLEAN">
<constraints nullable="false" />
</column>
<column name="backgroundThreads" type="INT">
@@ -29,20 +30,20 @@
<column name="smtpPort" type="INT">
<constraints nullable="false" />
</column>
<column name="smtpTls" type="BIT">
<column name="smtpTls" type="BOOLEAN">
<constraints nullable="false" />
</column>
<column name="smtpUserName" type="VARCHAR(255)" />
<column name="googleAnalyticsDomainName" type="VARCHAR(255)" />
<column name="googleAnalyticsTrackingCode" type="VARCHAR(255)" />
<column name="announcement" type="VARCHAR(255)" />
<column name="feedbackButton" type="BIT">
<column name="feedbackButton" type="BOOLEAN">
<constraints nullable="false" />
</column>
<column name="heavyLoad" type="BIT">
<column name="heavyLoad" type="BOOLEAN">
<constraints nullable="false" />
</column>
<column name="pubsubhubbub" type="BIT">
<column name="pubsubhubbub" type="BOOLEAN">
<constraints nullable="false" />
</column>
<column name="databaseUpdateThreads" type="INT">
@@ -79,6 +80,7 @@
<changeSet author="athou" id="create-cat">
<validCheckSum>7:93155e15f0feabe936e1de35711bf85b</validCheckSum>
<validCheckSum>7:c52f258e54d34156208cbfd2d8547fbd</validCheckSum>
<validCheckSum>8:c59e763e4cc7d59ae58d843937cf4e77</validCheckSum>
<preConditions onFail="MARK_RAN" onFailMessage="existing table skipping">
<not>
<tableExists tableName="FEEDCATEGORIES" />
@@ -88,7 +90,7 @@
<column name="id" type="BIGINT">
<constraints nullable="false" primaryKey="true" />
</column>
<column name="collapsed" type="BIT">
<column name="collapsed" type="BOOLEAN">
<constraints nullable="false" />
</column>
<column name="name" type="VARCHAR(128)">
@@ -160,6 +162,7 @@
<changeSet author="athou" id="create-statuses">
<validCheckSum>7:a9cf194a01c16b937a897aea934f09ae</validCheckSum>
<validCheckSum>7:6a386e0b08e98bdba9ce55e26ab90eba</validCheckSum>
<validCheckSum>8:ccfbff3df6f16c8686229c2da514e8b1</validCheckSum>
<preConditions onFail="MARK_RAN" onFailMessage="existing table skipping">
<not>
<tableExists tableName="FEEDENTRYSTATUSES" />
@@ -169,8 +172,8 @@
<column name="id" type="BIGINT">
<constraints nullable="false" primaryKey="true" />
</column>
<column name="read_status" type="BIT" />
<column name="starred" type="BIT">
<column name="read_status" type="BOOLEAN" />
<column name="starred" type="BOOLEAN">
<constraints nullable="false" />
</column>
<column name="entry_id" type="BIGINT">
@@ -298,6 +301,8 @@
<changeSet author="athou" id="create-users">
<validCheckSum>7:750e0990a8edebd0252df7d4adc7aa7c</validCheckSum>
<validCheckSum>8:dd1676f356c3c70822d69d5103947948</validCheckSum>
<validCheckSum>8:ca2d6edef0263a78cab9cc0942972d50</validCheckSum>
<preConditions onFail="MARK_RAN" onFailMessage="existing table skipping">
<not>
<tableExists tableName="USERS" />
@@ -307,17 +312,17 @@
<column name="id" type="BIGINT">
<constraints nullable="false" primaryKey="true" />
</column>
<column name="disabled" type="BIT">
<column name="disabled" type="BOOLEAN">
<constraints nullable="false" />
</column>
<column name="email" type="VARCHAR(255)" />
<column name="name" type="VARCHAR(32)">
<constraints nullable="false" />
</column>
<column name="password" type="BLOB">
<column name="password" type="${blob_type}">
<constraints nullable="false" />
</column>
<column name="salt" type="BLOB">
<column name="salt" type="${blob_type}">
<constraints nullable="false" />
</column>
<column name="lastLogin" type="DATETIME" />
@@ -333,6 +338,7 @@
<changeSet author="athou" id="create-user-settings">
<validCheckSum>7:985d6607a4350e032ea345d9a2f2f0c0</validCheckSum>
<validCheckSum>7:722eaff49d04d43c5b26da0929d3f707</validCheckSum>
<validCheckSum>8:451004f3bc72abac6a38d813881d3a87</validCheckSum>
<preConditions onFail="MARK_RAN" onFailMessage="existing table skipping">
<not>
<tableExists tableName="USERSETTINGS" />
@@ -349,16 +355,16 @@
<column name="readingOrder" type="VARCHAR(255)">
<constraints nullable="false" />
</column>
<column name="showRead" type="BIT">
<column name="showRead" type="BOOLEAN">
<constraints nullable="false" />
</column>
<column name="user_id" type="BIGINT">
<constraints nullable="false" />
</column>
<column name="socialButtons" type="BIT">
<column name="socialButtons" type="BOOLEAN">
<constraints nullable="false" />
</column>
<column name="scrollMarks" type="BIT">
<column name="scrollMarks" type="BOOLEAN">
<constraints nullable="false" />
</column>
<column name="viewMode" type="VARCHAR(255)">

View File

@@ -16,7 +16,7 @@
<column name="read_status" />
</createIndex>
</changeSet>
<changeSet author="athou" id="drop-fes-index">
<preConditions onFail="MARK_RAN" onFailMessage="index not found, skip drop index">
<indexExists tableName="FEEDENTRYSTATUSES" indexName="subscription_id" />
@@ -66,7 +66,7 @@
<column name="logLevel" type="VARCHAR(255)" />
</addColumn>
</changeSet>
<changeSet author="athou" id="add-push-hub">
<preConditions onFail="MARK_RAN" onFailMessage="column already exists">
<not>
@@ -78,7 +78,7 @@
<column name="pushHub" type="VARCHAR(2048)" />
</addColumn>
</changeSet>
<changeSet author="athou" id="add-push-topic">
<preConditions onFail="MARK_RAN" onFailMessage="column already exists">
<not>
@@ -90,7 +90,7 @@
<column name="pushTopic" type="VARCHAR(2048)" />
</addColumn>
</changeSet>
<changeSet author="athou" id="add-push-lastping">
<preConditions onFail="MARK_RAN" onFailMessage="column already exists">
<not>
@@ -102,7 +102,7 @@
<column name="pushLastPing" type="DATETIME" />
</addColumn>
</changeSet>
<changeSet author="athou" id="add-lastpublished">
<preConditions onFail="MARK_RAN" onFailMessage="column already exists">
<not>
@@ -113,8 +113,8 @@
<addColumn tableName="FEEDS">
<column name="lastPublishedDate" type="DATETIME" />
</addColumn>
</changeSet>
</changeSet>
<changeSet author="athou" id="add-lastcontenthash">
<preConditions onFail="MARK_RAN" onFailMessage="column already exists">
<not>
@@ -125,8 +125,8 @@
<addColumn tableName="FEEDS">
<column name="lastContentHash" type="VARCHAR(40)" />
</addColumn>
</changeSet>
</changeSet>
<changeSet author="athou" id="add-lastinterval">
<preConditions onFail="MARK_RAN" onFailMessage="column already exists">
<not>
@@ -137,8 +137,8 @@
<addColumn tableName="FEEDS">
<column name="averageEntryInterval" type="BIGINT" />
</addColumn>
</changeSet>
</changeSet>
<changeSet author="athou" id="add-lastentrydate">
<preConditions onFail="MARK_RAN" onFailMessage="column already exists">
<not>
@@ -150,7 +150,7 @@
<column name="lastEntryDate" type="DATETIME" />
</addColumn>
</changeSet>
<changeSet author="athou" id="add-cat-position">
<preConditions onFail="MARK_RAN" onFailMessage="column already exists">
<not>
@@ -162,7 +162,7 @@
<column name="position" type="INT" />
</addColumn>
</changeSet>
<changeSet author="athou" id="add-sub-position">
<preConditions onFail="MARK_RAN" onFailMessage="column already exists">
<not>
@@ -174,26 +174,26 @@
<column name="position" type="INT" />
</addColumn>
</changeSet>
<changeSet author="athou" id="drop-sequence">
<preConditions onFail="MARK_RAN" onFailMessage="table does not exist">
<tableExists tableName="hibernate_sequence" />
</preConditions>
<dropTable tableName="hibernate_sequence" />
</changeSet>
<changeSet author="athou" id="drop-old-pushinfos">
<preConditions onFail="MARK_RAN" onFailMessage="table does not exist">
<tableExists tableName="FEEDPUSHINFOS" />
</preConditions>
<dropTable tableName="FEEDPUSHINFOS" />
</changeSet>
<changeSet author="athou" id="add-topic-hash">
<addColumn tableName="FEEDS">
<column name="push_topic_hash" type="VARCHAR(40)" />
</addColumn>
<createIndex tableName="FEEDS" indexName="push_topic_hash_index">
<column name="push_topic_hash"></column>
</createIndex>
@@ -203,83 +203,85 @@
<addColumn tableName="FEEDENTRIES">
<column name="author" type="VARCHAR(128)" />
</addColumn>
</changeSet>
</changeSet>
<changeSet author="athou" id="add-inserted-index">
<createIndex tableName="FEEDENTRIES" indexName="inserted_index">
<column name="inserted"></column>
</createIndex>
</changeSet>
</changeSet>
<changeSet author="athou" id="rename-lang">
<renameColumn tableName="USERSETTINGS" oldColumnName="language" newColumnName="user_lang" columnDataType="VARCHAR(4)" />
</changeSet>
<changeSet author="athou" id="norwegian-migration">
<sql>update USERSETTINGS set user_lang='nb' where user_lang='no'</sql>
</changeSet>
<changeSet author="athou" id="add-user-created">
<validCheckSum>3:b1bbf8d559ac25b785751704f2d24a91</validCheckSum>
<validCheckSum>7:5bd8b28aadce012b56f003539ce99957</validCheckSum>
<addColumn tableName="USERS">
<column name="created" type="DATETIME" />
<column name="created" type="DATETIME" />
</addColumn>
</changeSet>
</changeSet>
<changeSet author="athou" id="add-proxy-setting">
<validCheckSum>7:ffca06665d2dc182bd3cb718e62e98f0</validCheckSum>
<validCheckSum>8:a1b2bfccb0b37fec8eb107220f76e3bd</validCheckSum>
<addColumn tableName="APPLICATIONSETTINGS">
<column name="imageProxyEnabled" type="BIT" />
<column name="imageProxyEnabled" type="BOOLEAN" />
</addColumn>
<update tableName="APPLICATIONSETTINGS">
<column name="imageProxyEnabled" valueBoolean="false"></column>
</update>
</update>
</changeSet>
<changeSet author="athou" id="add-query-timeout-setting">
<addColumn tableName="APPLICATIONSETTINGS">
<column name="queryTimeout" type="INT" />
<column name="queryTimeout" type="INT" />
</addColumn>
<update tableName="APPLICATIONSETTINGS">
<column name="queryTimeout" valueNumeric="0"></column>
</update>
</update>
</changeSet>
<changeSet author="athou" id="add-normalized-url">
<addColumn tableName="FEEDS">
<column name="normalizedUrl" type="VARCHAR(2048)" />
<column name="normalizedUrl" type="VARCHAR(2048)" />
</addColumn>
<addColumn tableName="FEEDS">
<column name="normalizedUrlHash" type="VARCHAR(40)" />
<column name="normalizedUrlHash" type="VARCHAR(40)" />
</addColumn>
<createIndex indexName="norm_url_hash_index" tableName="FEEDS"
unique="false">
<column name="normalizedUrlHash" />
</createIndex>
</changeSet>
<changeSet author="athou" id="add-pause-crawling">
<validCheckSum>8:4473505a94945268fcca0f2d77e4be4a</validCheckSum>
<addColumn tableName="APPLICATIONSETTINGS">
<column name="crawlingPaused" type="BIT" />
<column name="crawlingPaused" type="BOOLEAN" />
</addColumn>
<update tableName="APPLICATIONSETTINGS">
<column name="crawlingPaused" valueBoolean="false"></column>
</update>
</update>
</changeSet>
<changeSet author="athou" id="add-content-hash-index">
<createIndex tableName="FEEDS" indexName="last_content_hash_index">
<column name="lastContentHash"></column>
</createIndex>
</changeSet>
<changeSet author="athou" id="create-settings-index">
<createIndex tableName="USERSETTINGS" indexName="user_id_index" unique="true">
<column name="user_id"></column>
</createIndex>
</changeSet>
<changeSet author="athou" id="denormalize-statuses">
<validCheckSum>7:c73f70fbcbc8bb30f9629028ec8ddb06</validCheckSum>
<addColumn tableName="FEEDENTRYSTATUSES">
@@ -290,18 +292,18 @@
<column name="entryUpdated" type="DATETIME" />
</addColumn>
</changeSet>
<changeSet author="athou" id="populate-status-dates">
<validCheckSum>7:d6b5ab6920948b0a84e614870128e2f5</validCheckSum>
<sql>update FEEDENTRYSTATUSES SET entryUpdated = (select e.updated from FEEDENTRIES e where e.id = FEEDENTRYSTATUSES.entry_id)</sql>
</changeSet>
<changeSet author="athou" id="populate-status-users">
<validCheckSum>7:4227fdf2e7b9fe8e59544d536a7ee963</validCheckSum>
<sql>update FEEDENTRYSTATUSES SET user_id = (select sub.user_id from FEEDSUBSCRIPTIONS sub where sub.id = FEEDENTRYSTATUSES.subscription_id)</sql>
</changeSet>
<changeSet author="athou" id="recreate-fes-index-2">
<changeSet author="athou" id="recreate-fes-index-2">
<createIndex indexName="sub_entry_index" tableName="FEEDENTRYSTATUSES">
<column name="subscription_id" />
<column name="entry_id" />
@@ -317,28 +319,28 @@
<column name="entryUpdated" />
</createIndex>
</changeSet>
<changeSet author="athou" id="drop-fes-index-2">
<dropIndex tableName="FEEDENTRYSTATUSES" indexName="sub_entry_read_index" />
</changeSet>
<changeSet author="athou" id="add-entry-updated-to-ffe">
<addColumn tableName="FEED_FEEDENTRIES">
<column name="entryUpdated" type="DATETIME"></column>
</addColumn>
</changeSet>
<changeSet author="athou" id="populate-entry-dates">
<sql>update FEED_FEEDENTRIES SET entryUpdated = (select e.updated from FEEDENTRIES e where e.id = FEED_FEEDENTRIES.feedentry_id)</sql>
</changeSet>
<changeSet author="athou" id="create-ffe-entry-updated-index">
<createIndex tableName="FEED_FEEDENTRIES" indexName="feed_updated_index">
<column name="FEED_ID"></column>
<column name="entryUpdated"></column>
</createIndex>
</changeSet>
<changeSet author="athou" id="create-count-index">
<createIndex indexName="user_read_sub_index" tableName="FEEDENTRYSTATUSES">
<column name="user_id" />
@@ -346,21 +348,21 @@
<column name="subscription_id" />
</createIndex>
</changeSet>
<changeSet author="athou" id="add-trim-status-setting">
<addColumn tableName="APPLICATIONSETTINGS">
<column name="keepStatusDays" type="INT" />
<column name="keepStatusDays" type="INT" />
</addColumn>
<update tableName="APPLICATIONSETTINGS">
<column name="keepStatusDays" valueNumeric="0"></column>
</update>
</update>
</changeSet>
<changeSet author="athou" id="status-cleanup">
<validCheckSum>7:cf40ae235c2d4086c5fa6ac64102c6a9</validCheckSum>
<delete tableName="FEEDENTRYSTATUSES">
<where>read_status = false and starred = false</where>
</delete>
</changeSet>
</databaseChangeLog>

View File

@@ -3,35 +3,36 @@
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<changeSet id="add-detailed-social-options" author="athou">
<validCheckSum>8:58e8060bba0ec9d448f4346eb35d815c</validCheckSum>
<addColumn tableName="USERSETTINGS">
<column name="email" type="BIT"></column>
<column name="email" type="BOOLEAN"></column>
</addColumn>
<addColumn tableName="USERSETTINGS">
<column name="gmail" type="BIT"></column>
<column name="gmail" type="BOOLEAN"></column>
</addColumn>
<addColumn tableName="USERSETTINGS">
<column name="facebook" type="BIT"></column>
<column name="facebook" type="BOOLEAN"></column>
</addColumn>
<addColumn tableName="USERSETTINGS">
<column name="twitter" type="BIT"></column>
<column name="twitter" type="BOOLEAN"></column>
</addColumn>
<addColumn tableName="USERSETTINGS">
<column name="googleplus" type="BIT"></column>
<column name="googleplus" type="BOOLEAN"></column>
</addColumn>
<addColumn tableName="USERSETTINGS">
<column name="tumblr" type="BIT"></column>
<column name="tumblr" type="BOOLEAN"></column>
</addColumn>
<addColumn tableName="USERSETTINGS">
<column name="pocket" type="BIT"></column>
<column name="pocket" type="BOOLEAN"></column>
</addColumn>
<addColumn tableName="USERSETTINGS">
<column name="instapaper" type="BIT"></column>
<column name="instapaper" type="BOOLEAN"></column>
</addColumn>
<addColumn tableName="USERSETTINGS">
<column name="buffer" type="BIT"></column>
<column name="buffer" type="BOOLEAN"></column>
</addColumn>
<addColumn tableName="USERSETTINGS">
<column name="readability" type="BIT"></column>
<column name="readability" type="BOOLEAN"></column>
</addColumn>
<dropColumn tableName="USERSETTINGS" columnName="socialButtons" />
@@ -49,7 +50,7 @@
<column name="readability" valueBoolean="true"></column>
</update>
</changeSet>
<changeSet id="delete-settings" author="athou">
<dropTable tableName="APPLICATIONSETTINGS" />
</changeSet>

View File

@@ -2,6 +2,11 @@
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<property name="blob_type" value="bytea" dbms="postgresql"/>
<property name="blob_type" value="blob" dbms="h2" />
<property name="blob_type" value="blob" dbms="mysql" />
<property name="blob_type" value="blob" dbms="mssql" />
<include file="changelogs/db.changelog-1.0.xml" />
<include file="changelogs/db.changelog-1.1.xml" />

View File

@@ -80,7 +80,7 @@ public class UserRestTest {
SessionHelper sessionHelper = mock(SessionHelper.class);
UserREST userREST = new UserREST(null, null, null, service, null, null, null);
userREST.register(req, sessionHelper);
userREST.registerUser(req, sessionHelper);
inOrder.verify(service).register("user", "password", "test@test.com", Arrays.asList(Role.USER));
inOrder.verify(service).login("user", "password");
@@ -104,7 +104,7 @@ public class UserRestTest {
SessionHelper sessionHelper = mock(SessionHelper.class);
UserREST userREST = new UserREST(null, null, null, service, null, null, null);
userREST.register(req, sessionHelper);
userREST.registerUser(req, sessionHelper);
verify(sessionHelper).setLoggedInUser(user);
}