mirror of
https://github.com/Athou/commafeed.git
synced 2026-03-21 21:37:29 +00:00
Compare commits
50 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1dac2e064 | ||
|
|
f707993188 | ||
|
|
ea612d9d53 | ||
|
|
b44e737448 | ||
|
|
bb429afd95 | ||
|
|
475a8f8a28 | ||
|
|
c7ba5ca894 | ||
|
|
3023f0a7cc | ||
|
|
ddaefbc952 | ||
|
|
0b3a0fb3ed | ||
|
|
7f40a430fd | ||
|
|
05f5d3b25c | ||
|
|
c3ca0b18b3 | ||
|
|
696e0b1fa7 | ||
|
|
201f7dbd3e | ||
|
|
0bfd3e906c | ||
|
|
71ac2bfc45 | ||
|
|
5370db7c5e | ||
|
|
bcc30e40ba | ||
|
|
2f70f654f7 | ||
|
|
b64115dcbd | ||
|
|
c9c71d8582 | ||
|
|
689bc19296 | ||
|
|
27498ab649 | ||
|
|
678a11f998 | ||
|
|
e9ef98716f | ||
|
|
b3ce43eaf7 | ||
|
|
72083b7e87 | ||
|
|
0cc94c2033 | ||
|
|
1d6296b400 | ||
|
|
7ad5da2a9e | ||
|
|
a7665a9994 | ||
|
|
a4cd3f26e8 | ||
|
|
fcdb33b64b | ||
|
|
7fd6119bcf | ||
|
|
b4d4b2473c | ||
|
|
91f715c3c3 | ||
|
|
ea5fccfe5f | ||
|
|
86835eec73 | ||
|
|
2bccee2333 | ||
|
|
2d01b0d714 | ||
|
|
44bf37b05a | ||
|
|
cf617f0a64 | ||
|
|
eeeaffd883 | ||
|
|
d178302d34 | ||
|
|
83a5364903 | ||
|
|
aef76db664 | ||
|
|
c3b3240191 | ||
|
|
f381974955 | ||
|
|
bd16dd98c4 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,6 +3,7 @@ config.yml
|
||||
|
||||
# build directory
|
||||
target
|
||||
target-ide
|
||||
|
||||
# log files
|
||||
log
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
language: java
|
||||
jdk:
|
||||
- oraclejdk8
|
||||
- openjdk8
|
||||
|
||||
@@ -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
|
||||
|
||||
18
README.md
18
README.md
@@ -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).
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
153
pom.xml
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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に変更する",
|
||||
|
||||
@@ -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" : "перейти к подписке по названию"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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("‍", "‍");
|
||||
map.put("‌", "‌");
|
||||
|
||||
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()]);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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())) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import lombok.Data;
|
||||
@Data
|
||||
public class IDRequest implements Serializable {
|
||||
|
||||
@ApiModelProperty
|
||||
@ApiModelProperty(required = true)
|
||||
private Long id;
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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)">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user