forked from Archives/Athou_commafeed
Compare commits
53 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
535f947f88 | ||
|
|
f27e243cc4 | ||
|
|
6a699ed5f1 | ||
|
|
9c1f5efab5 | ||
|
|
6b7ce56f6b | ||
|
|
b76ee4a2d0 | ||
|
|
b444a74a44 | ||
|
|
d43820cc82 | ||
|
|
e74e8fe1c2 | ||
|
|
9eb6e8ec27 | ||
|
|
fae94d3696 | ||
|
|
68e5ed64c9 | ||
|
|
f912d3b8bd | ||
|
|
fc03d2ee91 | ||
|
|
523b2b8db4 | ||
|
|
d547e9b6d7 | ||
|
|
71efc9f854 | ||
|
|
4f289f7467 | ||
|
|
02ef8bee71 | ||
|
|
ff5c1b00d7 | ||
|
|
30264be311 | ||
|
|
8ea44ab8c7 | ||
|
|
1b8ff7ca61 | ||
|
|
f00a066c22 | ||
|
|
859cf468aa | ||
|
|
5b486a917b | ||
|
|
9ace6b70f0 | ||
|
|
447029ae70 | ||
|
|
8ac52690fd | ||
|
|
6934b2bd27 | ||
|
|
6647e4fcd4 | ||
|
|
21710f55f3 | ||
|
|
27bd9a7489 | ||
|
|
630d37125c | ||
|
|
9424237534 | ||
|
|
cba3fbeb5f | ||
|
|
58778ccf43 | ||
|
|
6c61d47d78 | ||
|
|
35e02f9d98 | ||
|
|
58c1650863 | ||
|
|
9b14ffa14c | ||
|
|
96c09bf4cd | ||
|
|
737cec744a | ||
|
|
13ed92bb94 | ||
|
|
076594c78e | ||
|
|
b6b1b4ebbe | ||
|
|
4007f37492 | ||
|
|
532d671feb | ||
|
|
fed7a1ac84 | ||
|
|
ddfd170ea8 | ||
|
|
bae5c67dfa | ||
|
|
84f51603fb | ||
|
|
f73ddc03e9 |
@@ -1,3 +1,8 @@
|
||||
v 2.3.0
|
||||
- dropwizard upgrade 0.9.1
|
||||
- feed enclosures are hidden if they already displayed in the content
|
||||
- fix youtube favicons
|
||||
- various internationalization fixes
|
||||
v 2.2.0
|
||||
- fix youtube and instagram favicon fetching
|
||||
- mark as read filter was lost when a feed was rearranged with drag&drop
|
||||
|
||||
39
README.md
39
README.md
@@ -13,32 +13,43 @@ Browser extensions: [Chrome](https://github.com/Athou/commafeed-chrome) - [Firef
|
||||
|
||||
## Deployment on your own server
|
||||
|
||||
### The short version
|
||||
### The very short version (download precompiled package)
|
||||
|
||||
mkdir commafeed && cd commafeed
|
||||
wget https://github.com/Athou/commafeed/releases/download/2.2.0/commafeed.jar
|
||||
wget https://raw.githubusercontent.com/Athou/commafeed/2.2.0/config.yml.example -O config.yml
|
||||
vi config.yml
|
||||
java -Djava.net.preferIPv4Stack=true -jar commafeed.jar server config.yml
|
||||
|
||||
### The short version (build from sources)
|
||||
|
||||
git clone https://github.com/Athou/commafeed.git
|
||||
cd commafeed
|
||||
mvn clean package
|
||||
cp config.yml.example config.yml
|
||||
vi config.yml
|
||||
java -Djava.net.preferIPv4Stack=true -jar target/commafeed.jar server config.yml
|
||||
cd commafeed
|
||||
./mvnw clean package
|
||||
cp config.yml.example config.yml
|
||||
vi config.yml
|
||||
java -Djava.net.preferIPv4Stack=true -jar target/commafeed.jar server config.yml
|
||||
|
||||
### The long version
|
||||
### The long version (same as the short version, but more detailed)
|
||||
|
||||
CommaFeed 2.0 has been rewritten to use Dropwizard and gulp instead of using tomee and wro4j. The latest version of the 1.x branch is available [here](https://github.com/Athou/commafeed/tree/1.x).
|
||||
|
||||
For storage, you can either use an embedded H2 database (use it only to test CommaFeed) or an external MySQL, PostgreSQL or SQLServer database.
|
||||
You also need Maven 3.x (and a Java 1.8+ JDK) installed in order to build the application.
|
||||
You also need the Java 1.8+ JDK in order to build the application.
|
||||
|
||||
To install maven and openjdk on Ubuntu, issue the following commands
|
||||
To install the required packages to build CommaFeed on Ubuntu, issue the following commands
|
||||
|
||||
# if openjdk-8-jdk is not available on your ubuntu version (14.04 LTS), add the following repo first
|
||||
sudo add-apt-repository ppa:openjdk-r/ppa
|
||||
sudo apt-get update
|
||||
|
||||
sudo apt-get install g++ build-essential openjdk-8-jdk
|
||||
|
||||
sudo apt-get install g++ build-essential openjdk-8-jdk maven
|
||||
# Make sure java8 is the selected java version
|
||||
sudo update-alternatives --config java
|
||||
sudo update-alternatives --config javac
|
||||
|
||||
|
||||
On Windows and other operating systems, just download maven 3.x from the [official site](http://maven.apache.org/), extract it somewhere and add the `bin` directory to your `PATH` environment variable.
|
||||
|
||||
Clone this repository. If you don't have git you can download the sources as a zip file from [here](https://github.com/Athou/commafeed/archive/master.zip)
|
||||
|
||||
git clone https://github.com/Athou/commafeed.git
|
||||
@@ -46,7 +57,7 @@ Clone this repository. If you don't have git you can download the sources as a z
|
||||
|
||||
Now build the application
|
||||
|
||||
mvn clean package
|
||||
./mvnw clean package
|
||||
|
||||
Copy `config.yml.example` to `config.yml` then edit the file to your liking.
|
||||
Issue the following command to run the app, the server will listen by default on `http://localhost:8082`. The default user is `admin` and the default password is `admin`.
|
||||
@@ -112,7 +123,7 @@ Steps to configuring a development environment for CommaFeed may include, but ma
|
||||
|
||||
## Copyright and license
|
||||
|
||||
Copyright 2013-2014 CommaFeed.
|
||||
Copyright 2013-2015 CommaFeed.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this work except in compliance with the License.
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
"devicejs": "0.2.4",
|
||||
"readabilicons": "arc90/readability-readabilicons#34c55561c5b8ec6e90714b50237c06b13cb9d59c",
|
||||
"zocial-less": "1.0.0",
|
||||
"swagger-ui": "2.1.8-M1"
|
||||
"swagger-ui": "2.1.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"angular": "1.3.14",
|
||||
|
||||
@@ -49,8 +49,9 @@ gulp.task('select2', function() {
|
||||
|
||||
gulp.task('swagger-ui', function() {
|
||||
var index_html = SRC_DIR + 'api/index.html';
|
||||
var swagger_json = 'target/swagger/swagger.json';
|
||||
var lib = SRC_DIR + 'lib/swagger-ui/dist/**/*';
|
||||
return gulp.src([lib, index_html]).pipe(gulp.dest(BUILD_DIR + 'api'));
|
||||
return gulp.src([lib, index_html, swagger_json]).pipe(gulp.dest(BUILD_DIR + 'api'));
|
||||
});
|
||||
|
||||
gulp.task('template-cache', function() {
|
||||
|
||||
BIN
maven/maven-wrapper.jar
Normal file
BIN
maven/maven-wrapper.jar
Normal file
Binary file not shown.
3
maven/maven-wrapper.properties
Normal file
3
maven/maven-wrapper.properties
Normal file
@@ -0,0 +1,3 @@
|
||||
#Maven download properties
|
||||
#Sat Jul 04 09:06:32 CEST 2015
|
||||
distributionUrl=https\://repository.apache.org/content/repositories/releases/org/apache/maven/apache-maven/3.3.3/apache-maven-3.3.3-bin.zip
|
||||
234
mvnw
vendored
Executable file
234
mvnw
vendored
Executable file
@@ -0,0 +1,234 @@
|
||||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------------
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Maven2 Start Up Batch script
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
# JAVA_HOME - location of a JDK home dir
|
||||
#
|
||||
# Optional ENV vars
|
||||
# -----------------
|
||||
# M2_HOME - location of maven2's installed home dir
|
||||
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
# e.g. to debug Maven itself, use
|
||||
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
if [ -z "$MAVEN_SKIP_RC" ] ; then
|
||||
|
||||
if [ -f /etc/mavenrc ] ; then
|
||||
. /etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f "$HOME/.mavenrc" ] ; then
|
||||
. "$HOME/.mavenrc"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# OS specific support. $var _must_ be set to either true or false.
|
||||
cygwin=false;
|
||||
darwin=false;
|
||||
mingw=false
|
||||
case "`uname`" in
|
||||
CYGWIN*) cygwin=true ;;
|
||||
MINGW*) mingw=true;;
|
||||
Darwin*) darwin=true
|
||||
#
|
||||
# Look for the Apple JDKs first to preserve the existing behaviour, and then look
|
||||
# for the new JDKs provided by Oracle.
|
||||
#
|
||||
if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then
|
||||
#
|
||||
# Apple JDKs
|
||||
#
|
||||
export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then
|
||||
#
|
||||
# Apple JDKs
|
||||
#
|
||||
export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then
|
||||
#
|
||||
# Oracle JDKs
|
||||
#
|
||||
export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then
|
||||
#
|
||||
# Apple JDKs
|
||||
#
|
||||
export JAVA_HOME=`/usr/libexec/java_home`
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
if [ -r /etc/gentoo-release ] ; then
|
||||
JAVA_HOME=`java-config --jre-home`
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$M2_HOME" ] ; then
|
||||
## resolve links - $0 may be a link to maven's home
|
||||
PRG="$0"
|
||||
|
||||
# need this for relative symlinks
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG="`dirname "$PRG"`/$link"
|
||||
fi
|
||||
done
|
||||
|
||||
saveddir=`pwd`
|
||||
|
||||
M2_HOME=`dirname "$PRG"`/..
|
||||
|
||||
# make it fully qualified
|
||||
M2_HOME=`cd "$M2_HOME" && pwd`
|
||||
|
||||
cd "$saveddir"
|
||||
# echo Using m2 at $M2_HOME
|
||||
fi
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched
|
||||
if $cygwin ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --unix "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
|
||||
fi
|
||||
|
||||
# For Migwn, ensure paths are in UNIX format before anything is touched
|
||||
if $mingw ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME="`(cd "$M2_HOME"; pwd)`"
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
|
||||
# TODO classpath?
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
javaExecutable="`which javac`"
|
||||
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
|
||||
# readlink(1) is not available as standard on Solaris 10.
|
||||
readLink=`which readlink`
|
||||
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
|
||||
if $darwin ; then
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
|
||||
else
|
||||
javaExecutable="`readlink -f \"$javaExecutable\"`"
|
||||
fi
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
|
||||
JAVA_HOME="$javaHome"
|
||||
export JAVA_HOME
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$JAVACMD" ] ; then
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
else
|
||||
JAVACMD="`which java`"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
echo "Error: JAVA_HOME is not defined correctly." >&2
|
||||
echo " We cannot execute $JAVACMD" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
echo "Warning: JAVA_HOME environment variable is not set."
|
||||
fi
|
||||
|
||||
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --path --windows "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
|
||||
fi
|
||||
|
||||
# traverses directory structure from process work directory to filesystem root
|
||||
# first directory with .mvn subdirectory is considered project base directory
|
||||
find_maven_basedir() {
|
||||
local basedir=$(pwd)
|
||||
local wdir=$(pwd)
|
||||
while [ "$wdir" != '/' ] ; do
|
||||
wdir=$(cd "$wdir/.."; pwd)
|
||||
if [ -d "$wdir"/.mvn ] ; then
|
||||
basedir=$wdir
|
||||
break
|
||||
fi
|
||||
done
|
||||
echo "${basedir}"
|
||||
}
|
||||
|
||||
# concatenates all lines of a file
|
||||
concat_lines() {
|
||||
if [ -f "$1" ]; then
|
||||
echo "$(tr -s '\n' ' ' < "$1")"
|
||||
fi
|
||||
}
|
||||
|
||||
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)}
|
||||
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||
|
||||
# Provide a "standardized" way to retrieve the CLI args that will
|
||||
# work with both Windows and non-Windows executions.
|
||||
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
|
||||
export MAVEN_CMD_LINE_ARGS
|
||||
|
||||
WRAPPER_LAUNCHER="org.apache.maven.wrapper.MavenWrapperMain"
|
||||
|
||||
exec "$JAVACMD" \
|
||||
$MAVEN_OPTS \
|
||||
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||
-classpath \
|
||||
"$MAVEN_PROJECTBASEDIR/maven/maven-wrapper.jar" \
|
||||
${WRAPPER_LAUNCHER} "$@"
|
||||
141
mvnw.bat
Normal file
141
mvnw.bat
Normal file
@@ -0,0 +1,141 @@
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||
@REM or more contributor license agreements. See the NOTICE file
|
||||
@REM distributed with this work for additional information
|
||||
@REM regarding copyright ownership. The ASF licenses this file
|
||||
@REM to you under the Apache License, Version 2.0 (the
|
||||
@REM "License"); you may not use this file except in compliance
|
||||
@REM with the License. You may obtain a copy of the License at
|
||||
@REM
|
||||
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||
@REM
|
||||
@REM Unless required by applicable law or agreed to in writing,
|
||||
@REM software distributed under the License is distributed on an
|
||||
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
@REM KIND, either express or implied. See the License for the
|
||||
@REM specific language governing permissions and limitations
|
||||
@REM under the License.
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Maven2 Start Up Batch script
|
||||
@REM
|
||||
@REM Required ENV vars:
|
||||
@REM JAVA_HOME - location of a JDK home dir
|
||||
@REM
|
||||
@REM Optional ENV vars
|
||||
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
|
||||
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
|
||||
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
@REM e.g. to debug Maven itself, use
|
||||
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
|
||||
@echo off
|
||||
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
|
||||
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
|
||||
|
||||
@REM set %HOME% to equivalent of $HOME
|
||||
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
|
||||
|
||||
@REM Execute a user defined script before this one
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
|
||||
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
|
||||
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
|
||||
:skipRcPre
|
||||
|
||||
@setlocal
|
||||
|
||||
set ERROR_CODE=0
|
||||
|
||||
@REM To isolate internal variables from possible post scripts, we use another setlocal
|
||||
@setlocal
|
||||
|
||||
@REM ==== START VALIDATION ====
|
||||
if not "%JAVA_HOME%" == "" goto OkJHome
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME not found in your environment. >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
:OkJHome
|
||||
if exist "%JAVA_HOME%\bin\java.exe" goto init
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME is set to an invalid directory. >&2
|
||||
echo JAVA_HOME = "%JAVA_HOME%" >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
:init
|
||||
|
||||
set MAVEN_CMD_LINE_ARGS=%*
|
||||
|
||||
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
|
||||
@REM Fallback to current working directory if not found.
|
||||
|
||||
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
|
||||
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
|
||||
|
||||
set EXEC_DIR=%CD%
|
||||
set WDIR=%EXEC_DIR%
|
||||
:findBaseDir
|
||||
IF EXIST "%WDIR%"\.mvn goto baseDirFound
|
||||
cd ..
|
||||
IF "%WDIR%"=="%CD%" goto baseDirNotFound
|
||||
set WDIR=%CD%
|
||||
goto findBaseDir
|
||||
|
||||
:baseDirFound
|
||||
set MAVEN_PROJECTBASEDIR=%WDIR%
|
||||
cd "%EXEC_DIR%"
|
||||
goto endDetectBaseDir
|
||||
|
||||
:baseDirNotFound
|
||||
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
|
||||
cd "%EXEC_DIR%"
|
||||
|
||||
:endDetectBaseDir
|
||||
|
||||
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
|
||||
|
||||
@setlocal EnableExtensions EnableDelayedExpansion
|
||||
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
|
||||
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
|
||||
|
||||
:endReadAdditionalConfig
|
||||
|
||||
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
||||
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\maven\maven-wrapper.jar"
|
||||
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
%MAVEN_JAVA_EXE% -Dmaven.multiModuleProjectDirectory="" %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS%
|
||||
|
||||
if ERRORLEVEL 1 goto error
|
||||
goto end
|
||||
|
||||
:error
|
||||
set ERROR_CODE=1
|
||||
|
||||
:end
|
||||
@endlocal & set ERROR_CODE=%ERROR_CODE%
|
||||
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
|
||||
@REM check for post script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
|
||||
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
|
||||
:skipRcPost
|
||||
|
||||
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
|
||||
if "%MAVEN_BATCH_PAUSE%" == "on" pause
|
||||
|
||||
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
|
||||
|
||||
exit /B %ERROR_CODE%
|
||||
@@ -13,7 +13,7 @@
|
||||
"gulp-filter": "2.0.2",
|
||||
"gulp-connect": "2.2.0",
|
||||
"connect-modrewrite": "0.8.1",
|
||||
"gulp-sass": "2.0.1",
|
||||
"gulp-sass": "2.0.2",
|
||||
"gulp-useref": "1.1.2",
|
||||
"gulp-angular-templatecache": "1.6.0"
|
||||
}
|
||||
|
||||
91
pom.xml
91
pom.xml
@@ -4,20 +4,20 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.commafeed</groupId>
|
||||
<artifactId>commafeed</artifactId>
|
||||
<version>2.2.0</version>
|
||||
<version>2.3.0</version>
|
||||
<packaging>jar</packaging>
|
||||
<name>CommaFeed</name>
|
||||
|
||||
<prerequisites>
|
||||
<maven>3.0.5</maven>
|
||||
<maven>3.1.0</maven>
|
||||
</prerequisites>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
<dropwizard.version>0.8.1</dropwizard.version>
|
||||
<dropwizard.version>0.9.1</dropwizard.version>
|
||||
<guice.version>4.0</guice.version>
|
||||
<querydsl.version>3.6.4</querydsl.version>
|
||||
<querydsl.version>4.0.2</querydsl.version>
|
||||
<rome.version>1.5.0</rome.version>
|
||||
</properties>
|
||||
|
||||
@@ -129,20 +129,49 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.github.kongchen</groupId>
|
||||
<artifactId>swagger-maven-plugin</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<configuration>
|
||||
<apiSources>
|
||||
<apiSource>
|
||||
<locations>com.commafeed.frontend.resource;com.commafeed.frontend.model;com.commafeed.frontend.model.request</locations>
|
||||
<swaggerDirectory>target/swagger</swaggerDirectory>
|
||||
<basePath>/rest</basePath>
|
||||
<info>
|
||||
<title>CommaFeed</title>
|
||||
<version>${project.version}</version>
|
||||
</info>
|
||||
<typesToSkip>
|
||||
<typeToSkip>com.commafeed.backend.model.User</typeToSkip>
|
||||
</typesToSkip>
|
||||
</apiSource>
|
||||
</apiSources>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>generate</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.github.eirslett</groupId>
|
||||
<artifactId>frontend-maven-plugin</artifactId>
|
||||
<version>0.0.22</version>
|
||||
<version>0.0.25</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>install node and npm</id>
|
||||
<goals>
|
||||
<goal>install-node-and-npm</goal>
|
||||
</goals>
|
||||
<phase>generate-resources</phase>
|
||||
<phase>compile</phase>
|
||||
<configuration>
|
||||
<nodeVersion>v0.12.4</nodeVersion>
|
||||
<npmVersion>2.10.1</npmVersion>
|
||||
<nodeVersion>v0.10.39</nodeVersion>
|
||||
<npmVersion>2.12.1</npmVersion>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
@@ -150,13 +179,17 @@
|
||||
<goals>
|
||||
<goal>npm</goal>
|
||||
</goals>
|
||||
<phase>generate-resources</phase>
|
||||
<phase>compile</phase>
|
||||
<configuration>
|
||||
<arguments>install --loglevel info</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>bower install</id>
|
||||
<goals>
|
||||
<goal>bower</goal>
|
||||
</goals>
|
||||
<phase>compile</phase>
|
||||
<configuration>
|
||||
<arguments>install</arguments>
|
||||
</configuration>
|
||||
@@ -166,7 +199,7 @@
|
||||
<goals>
|
||||
<goal>gulp</goal>
|
||||
</goals>
|
||||
<phase>generate-resources</phase>
|
||||
<phase>compile</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
@@ -213,6 +246,16 @@
|
||||
<groupId>io.dropwizard</groupId>
|
||||
<artifactId>dropwizard-core</artifactId>
|
||||
<version>${dropwizard.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.glassfish.hk2.external</groupId>
|
||||
<artifactId>aopalliance-repackaged</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.glassfish.hk2.external</groupId>
|
||||
<artifactId>javax.inject</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dropwizard</groupId>
|
||||
@@ -233,6 +276,12 @@
|
||||
<groupId>io.dropwizard</groupId>
|
||||
<artifactId>dropwizard-forms</artifactId>
|
||||
<version>${dropwizard.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.glassfish.hk2.external</groupId>
|
||||
<artifactId>javax.inject</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -248,26 +297,20 @@
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.wordnik</groupId>
|
||||
<artifactId>swagger-jaxrs</artifactId>
|
||||
<version>1.5.3-M1</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>javax.ws.rs</groupId>
|
||||
<artifactId>jsr311-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
<version>1.5.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.mysema.querydsl</groupId>
|
||||
<groupId>com.querydsl</groupId>
|
||||
<artifactId>querydsl-apt</artifactId>
|
||||
<version>${querydsl.version}</version>
|
||||
<scope>provided</scope>
|
||||
<classifier>hibernate</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mysema.querydsl</groupId>
|
||||
<groupId>com.querydsl</groupId>
|
||||
<artifactId>querydsl-jpa</artifactId>
|
||||
<version>${querydsl.version}</version>
|
||||
</dependency>
|
||||
@@ -374,17 +417,17 @@
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.4.187</version>
|
||||
<version>1.4.190</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.35</version>
|
||||
<version>5.1.37</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>9.4-1201-jdbc41</version>
|
||||
<version>9.4-1205-jdbc42</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.jtds</groupId>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
window.swaggerUi = new SwaggerUi({
|
||||
url: "../rest/swagger.json",
|
||||
url: "./swagger.json",
|
||||
dom_id: "swagger-ui-container",
|
||||
supportedSubmitMethods: ['get', 'post', 'put', 'delete'],
|
||||
onComplete: function(swaggerApi, swaggerUi){
|
||||
|
||||
@@ -7,24 +7,26 @@
|
||||
"download" : "Descargar",
|
||||
"link" : "Enlace",
|
||||
"bookmark" : "Marcador",
|
||||
"close" : "Close ",
|
||||
"tags" : "Tags "
|
||||
"close" : "Cerrar",
|
||||
"tags" : "Etiquetas"
|
||||
},
|
||||
"tree" : {
|
||||
"subscribe" : "Subscribir",
|
||||
"subscribe" : "Suscribirse",
|
||||
"import" : "Importar",
|
||||
"new_category" : "Nueva categoría",
|
||||
"all" : "Todos",
|
||||
"starred" : "Destacado"
|
||||
"starred" : "Destacados"
|
||||
},
|
||||
"subscribe" : {
|
||||
"feed_url" : "URL del Canal",
|
||||
"feed_name" : "Nombre del Canal",
|
||||
"feed_url" : "URL del canal",
|
||||
"filtering_expression" : "Expresión de filtrado",
|
||||
"filtering_expression_help" : "Si no está vacía, una expresión se evalúa como 'cierta' o 'falsa'. Si es falsa, las nueva entradas de este canal se marcarán como leídas automáticamente.\nLas variables disponibles son 'title' (título), 'content'(contenido), 'url' (URL), 'author' (autor), y 'categories' (categorías) y sus contenidos son convertidos a minúsculas para facilitar la comparación de strings (cadenas de texto).\nEjemplo: url.contains('youtube') or (author eq 'athou' and title.contains('github').\nLa sintaxis completa está disponible <a href='http://commons.apache.org/proper/commons-jexl/reference/syntax.html' target='_blank'>aquí</a>.",
|
||||
"feed_name" : "Nombre del canal",
|
||||
"category" : "Categoría"
|
||||
},
|
||||
"import" : {
|
||||
"google_reader_prefix" : "Déjame importar tus canales de tu",
|
||||
"google_reader_suffix" : " cuenta.",
|
||||
"google_reader_prefix" : "Déjame importar tus canales de tu cuenta ",
|
||||
"google_reader_suffix" : ".",
|
||||
"google_download" : "También puedes subir tu archivo subscriptions.xml.",
|
||||
"google_download_link" : "Descárgalo de aquí.",
|
||||
"xml_file" : "Archivo OPML"
|
||||
@@ -34,147 +36,147 @@
|
||||
"parent" : "Padre"
|
||||
},
|
||||
"toolbar" : {
|
||||
"unread" : "Sin Leer",
|
||||
"unread" : "No leídos",
|
||||
"all" : "Todos",
|
||||
"previous_entry" : "Entrada Anterior",
|
||||
"next_entry" : "Próxima Entrada",
|
||||
"previous_entry" : "Entrada anterior",
|
||||
"next_entry" : "Entrada siguiente",
|
||||
"refresh" : "Atualizar",
|
||||
"refresh_all" : "Force refresh all my feeds ",
|
||||
"sort_by_asc_desc" : "Ordenar por fecha asc/desc",
|
||||
"titles_only" : "Sólo Títulos",
|
||||
"expanded_view" : "Vista Expandida",
|
||||
"refresh_all" : "Forzar la actualización de todos mis canales.",
|
||||
"sort_by_asc_desc" : "Ordenar por fecha asc/desc.",
|
||||
"titles_only" : "Sólo títulos",
|
||||
"expanded_view" : "Vista expandida",
|
||||
"mark_all_as_read" : "Marcar todos como leído",
|
||||
"mark_all_older_12_hours" : "Items older than 12 hours ",
|
||||
"mark_all_older_day" : "Artículos anteriores a un día",
|
||||
"mark_all_older_week" : "Artículos más de una semana",
|
||||
"mark_all_older_two_weeks" : "Artículos más de does semanas",
|
||||
"mark_all_older_12_hours" : "Entradas anteriores a 12 horas.",
|
||||
"mark_all_older_day" : "Entradas anteriores a un día.",
|
||||
"mark_all_older_week" : "Entradas anteriores a una semana.",
|
||||
"mark_all_older_two_weeks" : "Entradas anteriores a 2 semanas.",
|
||||
"settings" : "Ajustes",
|
||||
"profile" : "Perfil",
|
||||
"admin" : "Admin",
|
||||
"about" : "Acerca de",
|
||||
"about" : "Acerca de...",
|
||||
"logout" : "Cerrar sesión",
|
||||
"donate" : "Donar"
|
||||
},
|
||||
"view" : {
|
||||
"entry_source" : "from ",
|
||||
"entry_author" : "by ",
|
||||
"error_while_loading_feed" : "Error mientras se cargaba este canal",
|
||||
"keep_unread" : "Guardar no leídos",
|
||||
"no_unread_items" : "no tiene items sin leer.",
|
||||
"mark_up_to_here" : "Mark as read up to here ",
|
||||
"search_for" : "searching for: ",
|
||||
"no_search_results" : "No match found for the requested keywords "
|
||||
"entry_source" : "de ",
|
||||
"entry_author" : "por ",
|
||||
"error_while_loading_feed" : "Error mientras se cargaba este canal.",
|
||||
"keep_unread" : "Mantener como no leído.",
|
||||
"no_unread_items" : "no tiene entradas sin leer.",
|
||||
"mark_up_to_here" : "Marcar como leídos hasta aquí.",
|
||||
"search_for" : "buscando: ",
|
||||
"no_search_results" : "No se han encontrado resultados para las palabras clave especificadas."
|
||||
},
|
||||
"feedsearch" : {
|
||||
"hint" : "Type in a subscription... ",
|
||||
"help" : "Use the return key to select and arrow keys to navigate. ",
|
||||
"result_prefix" : "Your subscriptions: "
|
||||
"hint" : "Introduce una suscripción...",
|
||||
"help" : "Usa la tecla Intro para seleccionar y las teclas de flecha para navegar.",
|
||||
"result_prefix" : "Tus suscripciones:"
|
||||
},
|
||||
"settings" : {
|
||||
"general" : {
|
||||
"value" : "General",
|
||||
"language" : "Lenguaje",
|
||||
"language_contribute" : "Contribuye con traducciones",
|
||||
"language" : "Idioma",
|
||||
"language_contribute" : "Contribuye con traducciones.",
|
||||
"show_unread" : "Mostrar canales y categorías sin entradas no leídas.",
|
||||
"social_buttons" : "Mostrar botones de compartir de redes sociales.",
|
||||
"scroll_marks" : "En vista expandida, el desplazamiento por las entradas las marca como leídas"
|
||||
"social_buttons" : "Mostrar botones para compartir de redes sociales.",
|
||||
"scroll_marks" : "En vista expandida, el desplazamiento por las entradas las marca como leídas."
|
||||
},
|
||||
"appearance" : "Appearance ",
|
||||
"scroll_speed" : "Scrolling speed when navigating between entries (in milliseconds) ",
|
||||
"scroll_speed_help" : "set to 0 to disable ",
|
||||
"theme" : "Theme ",
|
||||
"submit_your_theme" : "Submit your theme ",
|
||||
"custom_css" : "CSS Personalizado"
|
||||
"appearance" : "Apariencia",
|
||||
"scroll_speed" : "Velocidad de desplazamiento al navegar entre entradas (en milisegundos)",
|
||||
"scroll_speed_help" : "ponlo a 0 para desactivarlo",
|
||||
"theme" : "Tema",
|
||||
"submit_your_theme" : "Envía tu tema ",
|
||||
"custom_css" : "CSS personalizado"
|
||||
},
|
||||
"details" : {
|
||||
"feed_details" : "Detalles de Canales",
|
||||
"feed_details" : "Detalles del canal",
|
||||
"url" : "URL",
|
||||
"website" : "Website ",
|
||||
"website" : "Sitio web",
|
||||
"name" : "Nombre",
|
||||
"category" : "Categoría",
|
||||
"position" : "Position ",
|
||||
"position" : "Posicióon",
|
||||
"last_refresh" : "Última actualización",
|
||||
"message" : "Last refresh message ",
|
||||
"next_refresh" : "Next refresh ",
|
||||
"queued_for_refresh" : "Queued for refresh ",
|
||||
"feed_url" : "URL del Canal",
|
||||
"generate_api_key_first" : "Genera una llave API en tu perfil primero.",
|
||||
"unsubscribe" : "Terminar subscripción",
|
||||
"unsubscribe_confirmation" : "Are you sure you want to unsubscribe from this feed? ",
|
||||
"delete_category_confirmation" : "Are you sure you want to delete this category? ",
|
||||
"message" : "Último mensaje de actualización",
|
||||
"next_refresh" : "Próxima actualización",
|
||||
"queued_for_refresh" : "En cola para actualizar",
|
||||
"feed_url" : "URL del canal",
|
||||
"generate_api_key_first" : "Genera una clave API en tu perfil primero.",
|
||||
"unsubscribe" : "Terminar suscripción",
|
||||
"unsubscribe_confirmation" : "¿Estás seguro de querer terminar tu suscripción a este canal?",
|
||||
"delete_category_confirmation" : "¿Estás seguro de querer eliminar esta categoría?",
|
||||
"category_details" : "Detalles de la categoría",
|
||||
"tag_details" : "Tag details ",
|
||||
"tag_details" : "Detalles de las etiuqetas ",
|
||||
"parent_category" : "Categoría principal"
|
||||
},
|
||||
"profile" : {
|
||||
"user_name" : "Nombre de usuario",
|
||||
"email" : "Correo",
|
||||
"email" : "Correo electrónico",
|
||||
"change_password" : "Cambiar contraseña",
|
||||
"confirm_password" : "Confirmar contraseña",
|
||||
"minimum_6_chars" : "Mínimo 6 caracteres",
|
||||
"passwords_do_not_match" : "Las contraseñas no coinciden",
|
||||
"api_key" : "Llave API",
|
||||
"api_key" : "Clave API",
|
||||
"api_key_not_generated" : "No generado todavía",
|
||||
"generate_new_api_key" : "Generar nueva llave API",
|
||||
"generate_new_api_key_info" : "Al cambiar la contraseña se generará una nueva llave API",
|
||||
"generate_new_api_key" : "Generar nueva clave API",
|
||||
"generate_new_api_key_info" : "Al cambiar la contraseña se generará una nueva clave API.",
|
||||
"opml_export" : "Exportación de OPML",
|
||||
"delete_account" : "Eliminar cuenta",
|
||||
"delete_account_confirmation" : "Delete your acount? There's no turning back! "
|
||||
"delete_account_confirmation" : "¿Eliminar tu cuenta? ¡No habrá vuelta atrás! "
|
||||
},
|
||||
"about" : {
|
||||
"rest_api" : {
|
||||
"value" : "REST API",
|
||||
"line1" : "CommaFeed está construido con el uso de JAX-RS y AngularJS. Por eso, un REST API esta disponible.",
|
||||
"link_to_documentation" : "Vínculo de la documentación."
|
||||
"line1" : "CommaFeed está construido sobre JAX-RS y AngularJS. Por lo tanto, una REST API está disponible.",
|
||||
"link_to_documentation" : "Enlace a la documentación."
|
||||
},
|
||||
"keyboard_shortcuts" : "Atajos de teclado",
|
||||
"version" : "CommaFeed version ",
|
||||
"line1_prefix" : "CommaFeed es un proyecto open-source. El código se encuentra en ",
|
||||
"version" : "Versión de CommaFeed",
|
||||
"line1_prefix" : "CommaFeed es un proyecto de código abierto. El código se encuentra en ",
|
||||
"line1_suffix" : ".",
|
||||
"line2_prefix" : "Si encuentras un problema, por favor reportalo en la página de problemas de ",
|
||||
"line2_prefix" : "Si encuentras un problema, por favor repórtalo en la página de problemas de ",
|
||||
"line2_suffix" : " del proyecto.",
|
||||
"line3" : "Si te gusta este proyecto, por favor considera realizar una donacion para apoyar al desarrollador y ayudar a cubrir los costos de mantenimiento.",
|
||||
"line4" : "For those of you who prefer bitcoin, here is the address ",
|
||||
"line3" : "Si te gusta este proyecto, por favor considera realizar una donación para apoyar al desarrollador y ayudar a cubrir los costes de mantenimiento.",
|
||||
"line4" : "Para aquellos de vosotros que prefieran bitcoin, aquí está la dirección ",
|
||||
"goodies" : {
|
||||
"value" : "Goodies",
|
||||
"android_app" : "Android app ",
|
||||
"subscribe_url" : "Subscribe URL ",
|
||||
"chrome_extension" : "Extensión de Chrome",
|
||||
"firefox_extension" : "Extensión de Firefox",
|
||||
"opera_extension" : "Opera extension ",
|
||||
"subscribe_bookmarklet" : "Add subscription bookmarklet (click) ",
|
||||
"subscribe_bookmarklet_asc" : "Oldest first ",
|
||||
"subscribe_bookmarklet_desc" : "Newest first ",
|
||||
"next_unread_bookmarklet" : "Next unread item bookmarklet (drag to bookmark bar) "
|
||||
"value" : "Extras",
|
||||
"android_app" : "Apps para Android",
|
||||
"subscribe_url" : "URL para suscribirse ",
|
||||
"chrome_extension" : "Extensión para Chrome.",
|
||||
"firefox_extension" : "Extensión para Firefox.",
|
||||
"opera_extension" : "Extensón para Opera.",
|
||||
"subscribe_bookmarklet" : "Añadir marcador de suscripción (clic).",
|
||||
"subscribe_bookmarklet_asc" : "Más antiguos primero",
|
||||
"subscribe_bookmarklet_desc" : "Más recientes primero",
|
||||
"next_unread_bookmarklet" : "Marcador a la siguiente entrada no leída (arástralo a la barra de marcadores) "
|
||||
},
|
||||
"translation" : {
|
||||
"value" : "Traducción",
|
||||
"message" : "Necesitamos tu ayuda para ayudar a traducir CommaFeed.",
|
||||
"link" : "Ver como contribuir con traducciones."
|
||||
"link" : "Ver cómo contribuir con traducciones."
|
||||
},
|
||||
"announcements" : "Anuncios",
|
||||
"shortcuts" : {
|
||||
"mouse_middleclick" : "ratón botón medio",
|
||||
"open_next_entry" : "abrir próxima entrada",
|
||||
"open_previous_entry" : "abrir entrada previa",
|
||||
"spacebar" : "space/shift+space ",
|
||||
"move_page_down_up" : "moves the page down/up ",
|
||||
"focus_next_entry" : "Establecer el foco en la próxima entrada sin abrirlo",
|
||||
"focus_previous_entry" : "Establecer el foco en la entrada anterior sin abrirlo",
|
||||
"open_next_feed" : "open next feed or category ",
|
||||
"open_previous_feed" : "open previous feed or category ",
|
||||
"open_close_current_entry" : "abrir/cerrar entrada actual",
|
||||
"open_current_entry_in_new_window" : "abrir entrada actual en una nueva ventana",
|
||||
"open_current_entry_in_new_window_background" : "open current entry in a new window in the background ",
|
||||
"star_unstar" : "marcar/no marcar la entrada actual",
|
||||
"mark_current_entry" : "marcar como leída/no la leída entrada actual",
|
||||
"mouse_middleclick" : "click medio",
|
||||
"open_next_entry" : "abrir la siguiente entrada",
|
||||
"open_previous_entry" : "abrir la entrada anterior",
|
||||
"spacebar" : "espacio/mayúsculas+espacio",
|
||||
"move_page_down_up" : "mueve la página arriba/abajo",
|
||||
"focus_next_entry" : "establecer el foco en la siguiente entrada sin abrirla",
|
||||
"focus_previous_entry" : "establecer el foco en la entrada anterior sin abrirla",
|
||||
"open_next_feed" : "abrir el siguiente canal o categoría",
|
||||
"open_previous_feed" : "abrir el canal o categoría previo",
|
||||
"open_close_current_entry" : "abrir/cerrar la entrada actual",
|
||||
"open_current_entry_in_new_window" : "abrir la entrada actual en una nueva ventana",
|
||||
"open_current_entry_in_new_window_background" : "abrir la entrada actual en una nueva ventana en segundo plano",
|
||||
"star_unstar" : "destacar la entrada actual",
|
||||
"mark_current_entry" : "marcar la entrada actual como leída/no la leída",
|
||||
"mark_all_as_read" : "marcar todas las entradas como leídas",
|
||||
"open_in_new_tab_mark_as_read" : "abrir entrada en una nueva pestaña y marcar como leída",
|
||||
"fullscreen" : "toggle full screen mode ",
|
||||
"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 "
|
||||
"fullscreen" : "activar/desactivar el modo pantalla completa ",
|
||||
"font_size" : "aumentar/reducir el tamaño de la fuente de la entrada actual",
|
||||
"go_to_all" : "ver Todos",
|
||||
"go_to_starred" : "ver Destacados",
|
||||
"feed_search" : "navega a una suscripción al introducir su nombre"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,24 +34,24 @@
|
||||
"parent" : "Parent"
|
||||
},
|
||||
"toolbar" : {
|
||||
"unread" : "Non-lus",
|
||||
"unread" : "Non lus",
|
||||
"all" : "Tous",
|
||||
"previous_entry" : "Article précédent",
|
||||
"next_entry" : "Article suivant",
|
||||
"refresh" : "Rafraîchir",
|
||||
"refresh_all" : "Force refresh all my feeds ",
|
||||
"refresh_all" : "Rafraîchir tous les flux",
|
||||
"sort_by_asc_desc" : "Trier par date croissante/décroissante",
|
||||
"titles_only" : "Titres uniquement",
|
||||
"expanded_view" : "Vue étendue",
|
||||
"mark_all_as_read" : "Tout marquer comme lu",
|
||||
"mark_all_older_12_hours" : "Items older than 12 hours ",
|
||||
"mark_all_older_day" : "Articles de plus d'un jour",
|
||||
"mark_all_older_12_hours" : "Articles de plus de 12 heures",
|
||||
"mark_all_older_day" : "Articles de plus d'une journée",
|
||||
"mark_all_older_week" : "Articles de plus d'une semaine",
|
||||
"mark_all_older_two_weeks" : "Articles de plus d'un mois",
|
||||
"settings" : "Préférences",
|
||||
"profile" : "Profil",
|
||||
"admin" : "Administration",
|
||||
"about" : "A propos",
|
||||
"about" : "À propos",
|
||||
"logout" : "Déconnexion",
|
||||
"donate" : "Faire un don"
|
||||
},
|
||||
@@ -59,16 +59,16 @@
|
||||
"entry_source" : "sur",
|
||||
"entry_author" : "par ",
|
||||
"error_while_loading_feed" : "Erreur durant le chargement de ce flux",
|
||||
"keep_unread" : "Garder non-lu",
|
||||
"no_unread_items" : "n'a pas d'articles non-lus.",
|
||||
"keep_unread" : "Garder non lu",
|
||||
"no_unread_items" : "n'a pas d'articles non lus.",
|
||||
"mark_up_to_here" : "Marquer comme lu jusqu'ici",
|
||||
"search_for" : "searching for: ",
|
||||
"no_search_results" : "No match found for the requested keywords "
|
||||
"search_for" : "recherche : ",
|
||||
"no_search_results" : "Pas de résultats avec le terme indiqué."
|
||||
},
|
||||
"feedsearch" : {
|
||||
"hint" : "Tapez un nom de flux",
|
||||
"help" : "Utilisez la touche entrée pour sélectionner et les flèches pour naviguer",
|
||||
"result_prefix" : "Vos flux:"
|
||||
"result_prefix" : "Vos flux :"
|
||||
},
|
||||
"settings" : {
|
||||
"general" : {
|
||||
@@ -76,12 +76,12 @@
|
||||
"language" : "Langue",
|
||||
"language_contribute" : "Contribuer aux traductions",
|
||||
"show_unread" : "Afficher les flux et les catégories pour lesquels tout est déjà lu",
|
||||
"social_buttons" : "Afficher les boutons de partage sur réseaux sociaux",
|
||||
"scroll_marks" : "En mode de lecture étendu, marquer comme lu les éléments lorsque la fenêtre descend."
|
||||
"social_buttons" : "Afficher les boutons de partage sur les réseaux sociaux",
|
||||
"scroll_marks" : "En mode de lecture étendu, marquer les éléments comme lus lorsque la fenêtre descend."
|
||||
},
|
||||
"appearance" : "Apparence",
|
||||
"scroll_speed" : "Scrolling speed when navigating between entries (in milliseconds) ",
|
||||
"scroll_speed_help" : "set to 0 to disable ",
|
||||
"scroll_speed" : "Vitesse de défilement entre les entrées (en millisecondes) ",
|
||||
"scroll_speed_help" : "Mettez 0 pour désactiver",
|
||||
"theme" : "Thème",
|
||||
"submit_your_theme" : "Soumettez votre thème.",
|
||||
"custom_css" : "CSS personnelle"
|
||||
@@ -94,16 +94,16 @@
|
||||
"category" : "Catégorie",
|
||||
"position" : "Position",
|
||||
"last_refresh" : "Dernière mise à jour",
|
||||
"message" : "Last refresh message ",
|
||||
"message" : "Message de la dernière mise à jour ",
|
||||
"next_refresh" : "Prochaine mise à jour",
|
||||
"queued_for_refresh" : "En file d'attente",
|
||||
"feed_url" : "URL du flux",
|
||||
"generate_api_key_first" : "Générez une clé API dans votre profil d'abord.",
|
||||
"generate_api_key_first" : "Générez d'abord une clé API dans votre profil.",
|
||||
"unsubscribe" : "Se désabonner",
|
||||
"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" : "Êtes-vous sûr de vouloir vous désabonner de de flux ? ",
|
||||
"delete_category_confirmation" : "Êtes-vous sûr de vouloir supprimer cette catégorie ? ",
|
||||
"category_details" : "Détails de la catégorie",
|
||||
"tag_details" : "Tag details ",
|
||||
"tag_details" : "Détails du tag",
|
||||
"parent_category" : "Catégorie parente"
|
||||
},
|
||||
"profile" : {
|
||||
@@ -116,15 +116,15 @@
|
||||
"api_key" : "Clé API",
|
||||
"api_key_not_generated" : "Pas encore générée",
|
||||
"generate_new_api_key" : "Générer une nouvelle clé API",
|
||||
"generate_new_api_key_info" : "Changer de mot de passe va générer une nouvelle clé API",
|
||||
"generate_new_api_key_info" : "Changer de mot de passe générera une nouvelle clé API",
|
||||
"opml_export" : "Export du fichier OPML",
|
||||
"delete_account" : "Effacer le compte",
|
||||
"delete_account_confirmation" : "Delete your acount? There's no turning back! "
|
||||
"delete_account_confirmation" : "Êtes-vous sûr de vouloir supprimer définitivement votre compte ?"
|
||||
},
|
||||
"about" : {
|
||||
"rest_api" : {
|
||||
"value" : "API REST",
|
||||
"line1" : "CommaFeed utilise JAX-RS et AngularJS, donc une API REST est disponible.",
|
||||
"line1" : "CommaFeed utilise JAX-RS et AngularJS, une API REST est donc disponible.",
|
||||
"link_to_documentation" : "Lien vers la documentation."
|
||||
},
|
||||
"keyboard_shortcuts" : "Raccourcis clavier",
|
||||
@@ -145,7 +145,7 @@
|
||||
"subscribe_bookmarklet" : "Bookmarklet d'ajout d'abonnement",
|
||||
"subscribe_bookmarklet_asc" : "Du plus ancien au plus récent",
|
||||
"subscribe_bookmarklet_desc" : "Du plus récent au plus ancien",
|
||||
"next_unread_bookmarklet" : "Bookmarklet vers le prochain article non-lu"
|
||||
"next_unread_bookmarklet" : "Bookmarklet vers le prochain article non lu"
|
||||
},
|
||||
"translation" : {
|
||||
"value" : "Traduction",
|
||||
@@ -165,9 +165,9 @@
|
||||
"open_previous_feed" : "Sélectionner le flux ou la catégorie précédente",
|
||||
"open_close_current_entry" : "Ouvrir/fermer l'article courant",
|
||||
"open_current_entry_in_new_window" : "Ouvrir l'article courant dans une nouvelle fenêtre",
|
||||
"open_current_entry_in_new_window_background" : "Ouvrir l'article courant dans une nouvelle fenêtre en arrière plan",
|
||||
"open_current_entry_in_new_window_background" : "Ouvrir l'article courant dans une nouvelle fenêtre en arrière-plan",
|
||||
"star_unstar" : "Ajouter/enlever l'article courant des favoris",
|
||||
"mark_current_entry" : "Marquer comme lue/non-lue l'article courant",
|
||||
"mark_current_entry" : "Marquer comme lu/non lu l'article courant",
|
||||
"mark_all_as_read" : "Marquer tous les articles comme lus",
|
||||
"open_in_new_tab_mark_as_read" : "Ouvrir l'article courant dans une nouvelle fenêtre et marquer comme lu",
|
||||
"fullscreen" : "Activer/désactiver le mode plein-écran",
|
||||
@@ -177,4 +177,4 @@
|
||||
"feed_search" : "Naviguer vers un flux en entrant son nom"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
{
|
||||
"global" : {
|
||||
"save" : "Salva",
|
||||
"cancel" : "Cancella",
|
||||
"cancel" : "Annulla",
|
||||
"delete" : "Elimina",
|
||||
"required" : "Richiesto",
|
||||
"download" : "Download",
|
||||
"link" : "Link",
|
||||
"bookmark" : "Segnalibro",
|
||||
"close" : "Chiudi",
|
||||
"tags" : "Etichette "
|
||||
"tags" : "Tag"
|
||||
},
|
||||
"tree" : {
|
||||
"subscribe" : "Abbonati",
|
||||
"subscribe" : "Iscriviti",
|
||||
"import" : "Importa",
|
||||
"new_category" : "Nuova categoria",
|
||||
"all" : "Tutto",
|
||||
"all" : "Tutti",
|
||||
"starred" : "Preferiti"
|
||||
},
|
||||
"subscribe" : {
|
||||
"feed_url" : "Feed URL",
|
||||
"feed_url" : "URL feed",
|
||||
"feed_name" : "Nome feed",
|
||||
"category" : "Categoria"
|
||||
},
|
||||
"import" : {
|
||||
"google_reader_prefix" : "Permettimi di importare i tuoi feed dal tuo ",
|
||||
"google_reader_suffix" : " account.",
|
||||
"google_download" : "Oppure, carica il tuo file subscriptions.xml.",
|
||||
"google_download_link" : "Scaricalo da qui.",
|
||||
"xml_file" : "OPML File"
|
||||
"google_reader_prefix" : "Permettimi di importare i feed dal tuo account ",
|
||||
"google_reader_suffix" : ".",
|
||||
"google_download" : "Oppure carica il tuo file subscriptions.xml.",
|
||||
"google_download_link" : "Puoi scaricalo da qui.",
|
||||
"xml_file" : "File OPML"
|
||||
},
|
||||
"new_category" : {
|
||||
"name" : "Nome",
|
||||
@@ -38,12 +38,12 @@
|
||||
"all" : "Tutti",
|
||||
"previous_entry" : "Precedente",
|
||||
"next_entry" : "Successivo",
|
||||
"refresh" : "Ricarica",
|
||||
"refresh_all" : "Forza l'aggiornamento di tutte i miei feed",
|
||||
"sort_by_asc_desc" : "Ordina per data ascendente/decrescente",
|
||||
"refresh" : "Aggiorna",
|
||||
"refresh_all" : "Forza l'aggiornamento di tutti i feed",
|
||||
"sort_by_asc_desc" : "Ordina per data crescente/decrescente",
|
||||
"titles_only" : "Solo i titoli",
|
||||
"expanded_view" : "Espandi",
|
||||
"mark_all_as_read" : "Segna tutto come già letto",
|
||||
"mark_all_as_read" : "Segna tutti come già letti",
|
||||
"mark_all_older_12_hours" : "Elementi più vecchi di 12 ore",
|
||||
"mark_all_older_day" : "Elementi più vecchi di un giorno",
|
||||
"mark_all_older_week" : "Elementi più vecchi di una settimana",
|
||||
@@ -56,56 +56,56 @@
|
||||
"donate" : "Dona"
|
||||
},
|
||||
"view" : {
|
||||
"entry_source" : "da ",
|
||||
"entry_author" : "di ",
|
||||
"error_while_loading_feed" : "Si è verificato un errore durante il caricamento di questo feed",
|
||||
"keep_unread" : "Mantiene come non leggere",
|
||||
"no_unread_items" : "Non ci sono elementi da leggere.",
|
||||
"mark_up_to_here" : "Segna come letto fino qui",
|
||||
"search_for" : "cercando: ",
|
||||
"no_search_results" : "Nessun risultato trovato per le parole chiave cercate"
|
||||
"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",
|
||||
"mark_up_to_here" : "Segna come letto fin qui",
|
||||
"search_for" : "Cerca: ",
|
||||
"no_search_results" : "Nessun risultato per le parole chiave cercate"
|
||||
},
|
||||
"feedsearch" : {
|
||||
"hint" : "Digita in una sottoscrizione... ",
|
||||
"help" : "Usa il tasto invio per selezionare e le frecce per navigare.",
|
||||
"hint" : "Digita il nome di una sottoscrizione... ",
|
||||
"help" : "Usa il tasto Invio per selezionare e le frecce per navigare.",
|
||||
"result_prefix" : "Le tue sottoscrizioni:"
|
||||
},
|
||||
"settings" : {
|
||||
"general" : {
|
||||
"value" : "Generali",
|
||||
"language" : "Lingua",
|
||||
"language_contribute" : "Contribuisci nelle traduzioni",
|
||||
"show_unread" : "Mostra i feed e le categorie con elementi non letti",
|
||||
"social_buttons" : "Mostra i pulsanti social network di condivisione",
|
||||
"scroll_marks" : "In modalità estesa, segna come letto le voci quando scorri"
|
||||
"language_contribute" : "Contribuisci alle traduzioni",
|
||||
"show_unread" : "Mostra i feed e le categorie con voci non lette",
|
||||
"social_buttons" : "Mostra i pulsanti di condivisione social",
|
||||
"scroll_marks" : "In vista estesa, segna come lette le voci che scorri"
|
||||
},
|
||||
"appearance" : "Aspetto",
|
||||
"scroll_speed" : "Velocità dello scorrimento durante la navigazione tra i feed (in millisecondi) ",
|
||||
"scroll_speed_help" : "Imposta 0 per disabilitare",
|
||||
"scroll_speed" : "Velocità di scorrimento quando navighi tra i feed (in millisecondi)",
|
||||
"scroll_speed_help" : "Imposta su 0 per disabilitare",
|
||||
"theme" : "Tema",
|
||||
"submit_your_theme" : "Proponi il tuo tema",
|
||||
"submit_your_theme" : "Sottoponi il tuo tema",
|
||||
"custom_css" : "CSS personalizzato"
|
||||
},
|
||||
"details" : {
|
||||
"feed_details" : "Dettagli feed",
|
||||
"url" : "URL ",
|
||||
"website" : "Sito Web",
|
||||
"url" : "URL",
|
||||
"website" : "Sito web",
|
||||
"name" : "Nome",
|
||||
"category" : "Categoria",
|
||||
"position" : "Posizione",
|
||||
"last_refresh" : "Ultimo aggiornamento",
|
||||
"message" : "Ultimo messaggio di aggiornamento",
|
||||
"next_refresh" : "Prossimo aggiornamento",
|
||||
"queued_for_refresh" : "In attesa per l'aggiornamento",
|
||||
"feed_url" : "URL del feed ",
|
||||
"filtering_expression" : "Espressione del filtro",
|
||||
"filtering_expression_help" : "Se non è vuoto, una espressione viene misurata in 'true' o 'false'. Se falsa, i nuovi elementi di questo feed verranno segnati automaticamente come letti.\nLe variabili accettate sono 'title', 'content', 'url' 'author' e 'categories' e il loro contenuto è convertito in minuscolo per una facile confronto di stringhe.\Esempio: url.contains('youtube') o (author eq 'athou' and title.contains('github').\nLa sintassi completa è disponibile <a href='http://commons.apache.org/proper/commons-jexl/reference/syntax.html' target='_blank'>qui</a>.",
|
||||
"queued_for_refresh" : "In coda per l'aggiornamento",
|
||||
"feed_url" : "URL feed",
|
||||
"filtering_expression" : "Espressione filtro",
|
||||
"filtering_expression_help" : "Quando non è vuota, l'espressione viene applicata a ogni nuovo elemento e valutata come 'vera' o 'falsa'. Se falsa, l'elemento verrà segnato automaticamente come letto.\nLe variabili accettate sono 'title' (titolo), 'content' (contenuto), 'url', 'author' (autore) e 'categories' (categorie); il loro contenuto è convertito in minuscolo per facilitarne il confronto.\nEsempio: url.contains('youtube') or (author eq 'athou' and title.contains('github')).\nLa sintassi completa è disponibile <a href='http://commons.apache.org/proper/commons-jexl/reference/syntax.html' target='_blank'>qui</a> (in inglese).",
|
||||
"generate_api_key_first" : "Genera prima una chiave API nelle impostazioni del tuo profilo.",
|
||||
"unsubscribe" : "Annulla la sottoscrizione",
|
||||
"unsubscribe_confirmation" : "Sei sicuro di voler annullare la sottoscrizione da questo feed?",
|
||||
"unsubscribe" : "Disiscriviti",
|
||||
"unsubscribe_confirmation" : "Sei sicuro di voler annullare la sottoscrizione al feed?",
|
||||
"delete_category_confirmation" : "Sei sicuro di voler eliminare questa categoria?",
|
||||
"category_details" : "Dettagli categoria",
|
||||
"tag_details" : "Dettagli etichette ",
|
||||
"tag_details" : "Dettagli tag",
|
||||
"parent_category" : "Categoria principale"
|
||||
},
|
||||
"profile" : {
|
||||
@@ -117,66 +117,66 @@
|
||||
"passwords_do_not_match" : "Le password non corrispondono",
|
||||
"api_key" : "chiave API",
|
||||
"api_key_not_generated" : "Non ancora generata",
|
||||
"generate_new_api_key" : "Genera una nuova chiave API ",
|
||||
"generate_new_api_key_info" : "Cambiando la password sarà generata una nuova chiave API ì",
|
||||
"generate_new_api_key" : "Genera una nuova chiave API",
|
||||
"generate_new_api_key_info" : "Cambiando la password sarà generata una nuova chiave API",
|
||||
"opml_export" : "Esporta OPML",
|
||||
"delete_account" : "Elimina il profilo",
|
||||
"delete_account_confirmation" : "Eliminare il tuo profilo? Non si può tornare indietro!"
|
||||
"delete_account" : "Elimina account",
|
||||
"delete_account_confirmation" : "Vuoi eliminare il tuo account? Non si può tornare indietro!"
|
||||
},
|
||||
"about" : {
|
||||
"rest_api" : {
|
||||
"value" : "REST API",
|
||||
"line1" : "CommaFeed è costruito sopra JAX-RS e AngularJS. Ed ovviamente, una REST API è disponibile.",
|
||||
"link_to_documentation" : "Collegamento alla documentazione."
|
||||
"line1" : "CommaFeed è basato su JAX-RS e AngularJS. Pertanto è disponibile una REST API.",
|
||||
"link_to_documentation" : "Link alla documentazione."
|
||||
},
|
||||
"keyboard_shortcuts" : "Scorciatoie da tastiera",
|
||||
"version" : "Versione di CommaFeed",
|
||||
"line1_prefix" : "CommaFeed è un progetto open source. I codici sono ospitati su ",
|
||||
"line1_prefix" : "CommaFeed è un progetto open source. Trovi i sorgenti su ",
|
||||
"line1_suffix" : ".",
|
||||
"line2_prefix" : "Se hai qualche problema, segnalalo sulla pagina del ",
|
||||
"line2_suffix" : " progetto.",
|
||||
"line3" : "Se ti piace il progetto, considera una donazione per supportare lo sviluppatore ed a aiutare per coprire i costi di mantenenimento di questo sito online.",
|
||||
"line4" : "Se preferisci i Bitcoin, questo è l'indirizzo",
|
||||
"line2_prefix" : "Se hai qualche problema, segnalalo sulla pagina del progetto ",
|
||||
"line2_suffix" : ".",
|
||||
"line3" : "Se ti piace questo progetto, considera una donazione per supportare lo sviluppatore e aiutare a coprire i costi di manutenzione di questo sito.",
|
||||
"line4" : "Se preferisci Bitcoin, questo è l'indirizzo",
|
||||
"goodies" : {
|
||||
"value" : "Goodies",
|
||||
"value" : "Cose che potrebbero interessarti",
|
||||
"android_app" : "Applicazione Android",
|
||||
"subscribe_url" : "Sottoscrivi URL",
|
||||
"chrome_extension" : "Estensione per Chrome",
|
||||
"firefox_extension" : "Estensione per Firefox",
|
||||
"opera_extension" : "Estensione per Opera",
|
||||
"subscribe_bookmarklet" : "Aggiungi la sottoscrizione ai segnalibri (clicca)",
|
||||
"subscribe_bookmarklet_asc" : "I più vecchi prima",
|
||||
"subscribe_bookmarklet_desc" : "I più nuovi prima",
|
||||
"next_unread_bookmarklet" : "Prossimo elemento non letto nei segnalibri (trascinali nella barra dei segnalibri)"
|
||||
"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)"
|
||||
},
|
||||
"translation" : {
|
||||
"value" : "Traduzioni",
|
||||
"message" : "Abbiamo bisogno del tuo aiuto per tradurre CommaFeed.",
|
||||
"link" : "Vedi come aiutarci nella traduzioni."
|
||||
"link" : "Scopri come aiutarci nella traduzioni."
|
||||
},
|
||||
"announcements" : "Annunci",
|
||||
"shortcuts" : {
|
||||
"mouse_middleclick" : "click centrale del mouse",
|
||||
"open_next_entry" : "apri l'elemento successivo",
|
||||
"open_previous_entry" : "apri l'elemento precedente",
|
||||
"spacebar" : "spazio/shift+spazio",
|
||||
"move_page_down_up" : "muovi la pagina sopra/sotto",
|
||||
"focus_next_entry" : "imposta il fuoco sull'elemento successivo senza aprirlo",
|
||||
"focus_previous_entry" : "imposta il fuoco sull'elemento precedente senza aprirlo",
|
||||
"open_next_feed" : "apri il feed successivo od una categoria",
|
||||
"open_previous_feed" : "apri il feed precedente od una categoria",
|
||||
"open_close_current_entry" : "apri/chiusi la categoria corrente",
|
||||
"open_current_entry_in_new_window" : "apri il corrente elemento in una nuova finestra",
|
||||
"open_current_entry_in_new_window_background" : "apri il corrente elemento in una nuova finestra in secondo piano",
|
||||
"star_unstar" : "segna/togli il segno all'elemento corrente",
|
||||
"mark_current_entry" : "segna come letto/non letto l'elemento corrente",
|
||||
"mark_all_as_read" : "segna come letti tutti gli elementi",
|
||||
"open_in_new_tab_mark_as_read" : "apri l'elemento in una nuova finestra e segnala come letta",
|
||||
"fullscreen" : "alterna la modalità a schermo intero",
|
||||
"font_size" : "aumenta/decrementa la grandezza del font dell'elemento corrente",
|
||||
"go_to_all" : "vai nella visione totale",
|
||||
"go_to_starred" : "vai nella visione dei preferiti",
|
||||
"feed_search" : "naviga in una sottoscrizione scrivendo il suo nome"
|
||||
"open_next_entry" : "apri successivo",
|
||||
"open_previous_entry" : "apri precedente",
|
||||
"spacebar" : "SPAZIO/MAIUSC+SPAZIO",
|
||||
"move_page_down_up" : "muove la pagina in su/giù",
|
||||
"focus_next_entry" : "metti a fuoco l'elemento successivo senza aprirlo",
|
||||
"focus_previous_entry" : "metti a fuoco l'elemento precedente senza aprirlo",
|
||||
"open_next_feed" : "apri il prossimo feed o categoria",
|
||||
"open_previous_feed" : "apri il feed o la categoria precedente",
|
||||
"open_close_current_entry" : "apri/chiudi la voce corrente",
|
||||
"open_current_entry_in_new_window" : "apri la voce corrente in una nuova finestra",
|
||||
"open_current_entry_in_new_window_background" : "apri la voce corrente in una nuova finestra in secondo piano",
|
||||
"star_unstar" : "metti/togli la tua preferenza alla voce corrente",
|
||||
"mark_current_entry" : "segna la voce corrente come letta/non letta",
|
||||
"mark_all_as_read" : "segna tutte le voci come lette",
|
||||
"open_in_new_tab_mark_as_read" : "apri voce in un nuovo tab e segna come letta",
|
||||
"fullscreen" : "commuta la modalità a schermo intero",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,3 +360,14 @@ module.directive('metricGauge', function() {
|
||||
templateUrl : 'templates/_metrics.gauge.html'
|
||||
};
|
||||
});
|
||||
|
||||
module.directive('metricTimer', function() {
|
||||
return {
|
||||
scope : {
|
||||
metric : '=',
|
||||
label : '='
|
||||
},
|
||||
restrict : 'E',
|
||||
templateUrl : 'templates/_metrics.timer.html'
|
||||
};
|
||||
});
|
||||
|
||||
@@ -19,7 +19,7 @@ module.service('LangService', [function() {
|
||||
'nn': 'Norsk (nynorsk)',
|
||||
'pt': 'Português',
|
||||
'pl': 'Polski',
|
||||
'ru': 'русский',
|
||||
'ru': 'Русский',
|
||||
'fi': 'Suomi',
|
||||
'sv': 'Svenska',
|
||||
'zh': '简体中文',
|
||||
@@ -31,4 +31,4 @@ module.service('LangService', [function() {
|
||||
'cs': 'Čeština',
|
||||
'ms': 'Bahasa Malaysian'
|
||||
}
|
||||
}]);
|
||||
}]);
|
||||
|
||||
@@ -4,14 +4,8 @@
|
||||
<dt>Mean</dt>
|
||||
<dd>{{metric.meanRate | number:2}}</dd>
|
||||
|
||||
<dt>1 min</dt>
|
||||
<dd>{{metric.oneMinuteRate | number:2}}</dd>
|
||||
|
||||
<dt>5 min</dt>
|
||||
<dd>{{metric.fiveMinuteRate | number:2}}</dd>
|
||||
|
||||
<dt>15 min</dt>
|
||||
<dd>{{metric.fifteenMinuteRate | number:2}}</dd>
|
||||
<dt>1/5/15 min</dt>
|
||||
<dd>{{metric.oneMinuteRate | number:2}} {{metric.fiveMinuteRate | number:2}} {{metric.fifteenMinuteRate | number:2}}</dd>
|
||||
|
||||
<dt>Total</dt>
|
||||
<dd>{{metric.count}}</dd>
|
||||
|
||||
17
src/main/app/templates/_metrics.timer.html
Normal file
17
src/main/app/templates/_metrics.timer.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<div>
|
||||
<span>{{label}}</span>
|
||||
<dl class="dl-horizontal">
|
||||
<dt>Mean</dt>
|
||||
<dd>{{metric.meanRate | number:2}}</dd>
|
||||
|
||||
<dt>1/5/15 min</dt>
|
||||
<dd>{{metric.oneMinuteRate | number:2}} {{metric.fiveMinuteRate | number:2}} {{metric.fifteenMinuteRate | number:2}}</dd>
|
||||
|
||||
<dt>Total</dt>
|
||||
<dd>{{metric.count}}</dd>
|
||||
|
||||
<dt>min/max/mean (ms)</dt>
|
||||
<dd>{{metric.snapshot.min/1000000 | number:0}} {{metric.snapshot.max/1000000 | number:0}} {{metric.snapshot.mean/1000000 | number:0}}</dd>
|
||||
|
||||
</dl>
|
||||
</div>
|
||||
@@ -6,14 +6,14 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="btn-group">
|
||||
<div class="btn-group" id="toolbar-nav">
|
||||
<a type="button" class="btn btn-default" ng-click="previousEntry()" title="{{ 'toolbar.previous_entry' | translate }}">
|
||||
<i class="icon-chevron-up"></i>
|
||||
</a>
|
||||
<a type="button" class="btn btn-default" ng-click="nextEntry()" title="{{ 'toolbar.next_entry' | translate }}">
|
||||
<i class="icon-chevron-down"></i>
|
||||
</a>
|
||||
<div class="btn-group">
|
||||
<div class="btn-group" id="toolbar-refresh">
|
||||
<a type="button" class="btn btn-default" ng-click="refresh()" title="{{ 'toolbar.refresh' | translate }}">
|
||||
<i class="icon-refresh"></i>
|
||||
</a>
|
||||
@@ -28,7 +28,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="btn-group">
|
||||
<div class="btn-group" id="toolbar-mark-read">
|
||||
<a type="button" class="btn btn-default" ng-click="markAllAsRead()" title="{{ 'toolbar.mark_all_as_read' | translate }}">
|
||||
<i class="icon-ok"></i>
|
||||
</a>
|
||||
@@ -57,7 +57,7 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="actions btn-group">
|
||||
<div class="actions btn-group" id="toolbar-read-mode">
|
||||
<div ng-if="!MobileService.mobile || MobileService.rightMenu">
|
||||
<div class="btn-group read-mode">
|
||||
<button type="button" class="btn btn-default" ng-click="settingsService.settings.readingMode = 'unread'"
|
||||
@@ -66,14 +66,14 @@
|
||||
ng-class="{'active': settingsService.settings.readingMode == 'all'}">{{ 'toolbar.all' | translate }}</button>
|
||||
</div>
|
||||
|
||||
<div class="btn-group">
|
||||
<div class="btn-group" id="toolbar-read-order">
|
||||
<a type="button" class="btn btn-default" ng-click="toggleOrder()" title="{{ 'toolbar.sort_by_asc_desc' | translate }}">
|
||||
<i
|
||||
ng-class="{'icon-arrow-up' : settingsService.settings.readingOrder == 'asc', 'icon-arrow-down': settingsService.settings.readingOrder == 'desc'}"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="btn-group">
|
||||
<div class="btn-group" id="toolbar-read-view-settings">
|
||||
<a type="button" class="btn btn-default" ng-click="settingsService.settings.viewMode = 'title'"
|
||||
ng-class="{'active': settingsService.settings.viewMode == 'title'}" title="{{ 'toolbar.titles_only' | translate }}">
|
||||
<i class="icon-list"></i>
|
||||
@@ -84,7 +84,7 @@
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="btn-group">
|
||||
<div class="btn-group" id="toolbar-settings">
|
||||
<a class="btn btn-default" ng-click="toSettings()" title="{{ 'toolbar.settings' | translate }}">
|
||||
<i class="icon-cog"></i>
|
||||
</a>
|
||||
@@ -133,4 +133,4 @@
|
||||
</div>
|
||||
<span ng-if="!MobileService.mobile" ng-bind-html="ServerService.announcement | trustHtml"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,21 +1,28 @@
|
||||
<div>
|
||||
<metric-meter metric="metrics.meters['com.commafeed.backend.feed.FeedQueues.refill']" label="'Refresh queue refill rate (/sec)'"></metric-meter>
|
||||
<metric-meter metric="metrics.meters['com.commafeed.backend.feed.FeedRefreshTaskGiver.feedRefreshed']" label="'Feed refreshed (/sec)'"></metric-meter>
|
||||
<metric-meter metric="metrics.meters['com.commafeed.backend.feed.FeedRefreshUpdater.feedUpdated']" label="'Feed updated (/sec)'"></metric-meter>
|
||||
<metric-meter metric="metrics.meters['com.commafeed.backend.feed.FeedRefreshUpdater.entryCacheHit']" label="'Entry cache hit (/sec)'"></metric-meter>
|
||||
<metric-meter metric="metrics.meters['com.commafeed.backend.feed.FeedRefreshUpdater.entryCacheMiss']" label="'Entry cache miss (/sec)'"></metric-meter>
|
||||
<div class="col-md-6">
|
||||
<metric-meter metric="metrics.meters['com.commafeed.backend.feed.FeedQueues.refill']" label="'Refresh queue refill rate (/sec)'"></metric-meter>
|
||||
<metric-meter metric="metrics.meters['com.commafeed.backend.feed.FeedRefreshTaskGiver.feedRefreshed']" label="'Feed refreshed (/sec)'"></metric-meter>
|
||||
<metric-meter metric="metrics.meters['com.commafeed.backend.feed.FeedRefreshUpdater.feedUpdated']" label="'Feed updated (/sec)'"></metric-meter>
|
||||
<metric-meter metric="metrics.meters['com.commafeed.backend.feed.FeedRefreshUpdater.entryCacheHit']" label="'Entry cache hit (/sec)'"></metric-meter>
|
||||
<metric-meter metric="metrics.meters['com.commafeed.backend.feed.FeedRefreshUpdater.entryCacheMiss']" label="'Entry cache miss (/sec)'"></metric-meter>
|
||||
|
||||
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedRefreshExecutor.feed-refresh-updater.active']"
|
||||
label="'Feed Updater active'"></metric-gauge>
|
||||
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedRefreshExecutor.feed-refresh-updater.pending']"
|
||||
label="'Feed Updater queued'"></metric-gauge>
|
||||
|
||||
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedRefreshExecutor.feed-refresh-updater.active']"
|
||||
label="'Feed Updater active'"></metric-gauge>
|
||||
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedRefreshExecutor.feed-refresh-updater.pending']"
|
||||
label="'Feed Updater queued'"></metric-gauge>
|
||||
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedRefreshExecutor.feed-refresh-worker.active']"
|
||||
label="'Feed Worker active'"></metric-gauge>
|
||||
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedRefreshExecutor.feed-refresh-worker.pending']"
|
||||
label="'Feed Worker queued'"></metric-gauge>
|
||||
|
||||
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedRefreshExecutor.feed-refresh-worker.active']"
|
||||
label="'Feed Worker active'"></metric-gauge>
|
||||
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedRefreshExecutor.feed-refresh-worker.pending']"
|
||||
label="'Feed Worker queued'"></metric-gauge>
|
||||
|
||||
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedQueues.addQueue']" label="'Task Giver Add Queue'"></metric-gauge>
|
||||
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedQueues.takeQueue']" label="'Task Giver Take Queue'"></metric-gauge>
|
||||
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedQueues.giveBackQueue']" label="'Task Giver Give Back Queue'"></metric-gauge>
|
||||
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedQueues.addQueue']" label="'Task Giver Add Queue'"></metric-gauge>
|
||||
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedQueues.takeQueue']" label="'Task Giver Take Queue'"></metric-gauge>
|
||||
<metric-gauge metric="metrics.gauges['com.commafeed.backend.feed.FeedQueues.giveBackQueue']" label="'Task Giver Give Back Queue'"></metric-gauge>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div ng-repeat="(name, timer) in metrics.timers">
|
||||
<metric-timer metric="timer" label="name"></metric-gauge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -61,8 +61,7 @@
|
||||
<div class="entry-body-content">
|
||||
<div ng-if="!MobileService.mobile" ng-bind-html="entry.content | iframeHttpsRewrite| highlight:keywords | trustHtml"></div>
|
||||
<div ng-if="MobileService.mobile" ng-bind-html="entry.content | iframeHttpsRewrite| highlight:keywords | appendImageTitles | trustHtml"></div>
|
||||
|
||||
<div class="entry-enclosure" ng-if="entry.enclosureType">
|
||||
<div class="entry-enclosure" ng-if="entry.enclosureType && (entry.enclosureUrl && entry.content && entry.content.indexOf(entry.enclosureUrl) == -1)">
|
||||
<video controls ng-if="entry.enclosureType && entry.enclosureType.indexOf('video') == 0">
|
||||
<source ng-src="{{entry.enclosureUrl | trustUrl}}" type="{{entry.enclosureType}}" />
|
||||
</video>
|
||||
|
||||
@@ -1,21 +1,8 @@
|
||||
package com.commafeed;
|
||||
|
||||
import io.dropwizard.Application;
|
||||
import io.dropwizard.assets.AssetsBundle;
|
||||
import io.dropwizard.db.DataSourceFactory;
|
||||
import io.dropwizard.forms.MultiPartBundle;
|
||||
import io.dropwizard.hibernate.HibernateBundle;
|
||||
import io.dropwizard.migrations.MigrationsBundle;
|
||||
import io.dropwizard.server.DefaultServerFactory;
|
||||
import io.dropwizard.servlets.CacheBustingFilter;
|
||||
import io.dropwizard.setup.Bootstrap;
|
||||
import io.dropwizard.setup.Environment;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
@@ -26,7 +13,6 @@ import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.jetty.server.session.SessionHandler;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
||||
@@ -60,13 +46,21 @@ import com.commafeed.frontend.servlet.CustomCssServlet;
|
||||
import com.commafeed.frontend.servlet.LogoutServlet;
|
||||
import com.commafeed.frontend.servlet.NextUnreadServlet;
|
||||
import com.commafeed.frontend.session.SessionHelperFactoryProvider;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Key;
|
||||
import com.google.inject.TypeLiteral;
|
||||
import com.wordnik.swagger.jaxrs.config.BeanConfig;
|
||||
import com.wordnik.swagger.jaxrs.listing.ApiListingResource;
|
||||
|
||||
import io.dropwizard.Application;
|
||||
import io.dropwizard.assets.AssetsBundle;
|
||||
import io.dropwizard.db.DataSourceFactory;
|
||||
import io.dropwizard.forms.MultiPartBundle;
|
||||
import io.dropwizard.hibernate.HibernateBundle;
|
||||
import io.dropwizard.migrations.MigrationsBundle;
|
||||
import io.dropwizard.server.DefaultServerFactory;
|
||||
import io.dropwizard.servlets.CacheBustingFilter;
|
||||
import io.dropwizard.setup.Bootstrap;
|
||||
import io.dropwizard.setup.Environment;
|
||||
|
||||
public class CommaFeedApplication extends Application<CommaFeedConfiguration> {
|
||||
|
||||
@@ -158,21 +152,6 @@ public class CommaFeedApplication extends Application<CommaFeedConfiguration> {
|
||||
environment.lifecycle().manage(injector.getInstance(FeedRefreshWorker.class));
|
||||
environment.lifecycle().manage(injector.getInstance(FeedRefreshUpdater.class));
|
||||
|
||||
// Swagger
|
||||
environment.jersey().register(new ApiListingResource());
|
||||
environment.getObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);
|
||||
|
||||
String modelsPackage = "com.commafeed.frontend.model";
|
||||
String requestsPackage = "com.commafeed.frontend.model.request";
|
||||
String endpointsPackage = "com.commafeed.frontend.resource";
|
||||
List<String> packages = Arrays.asList(modelsPackage, requestsPackage, endpointsPackage);
|
||||
BeanConfig swaggerConfig = new BeanConfig();
|
||||
swaggerConfig.setTitle("CommaFeed");
|
||||
swaggerConfig.setVersion("1");
|
||||
swaggerConfig.setBasePath("/rest");
|
||||
swaggerConfig.setResourcePackage(StringUtils.join(packages, ","));
|
||||
swaggerConfig.setScan(true);
|
||||
|
||||
// cache configuration
|
||||
// prevent caching on REST resources, except for favicons
|
||||
environment.servlets().addFilter("cache-filter", new CacheBustingFilter() {
|
||||
|
||||
@@ -16,7 +16,7 @@ import org.apache.http.entity.HttpEntityWrapper;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
|
||||
class ContentEncodingInterceptor implements HttpResponseInterceptor {
|
||||
|
||||
|
||||
private static final Set<String> ALLOWED_CONTENT_ENCODINGS = new HashSet<>(Arrays.asList("gzip", "x-gzip", "deflate", "identity"));
|
||||
|
||||
@Override
|
||||
@@ -28,17 +28,17 @@ class ContentEncodingInterceptor implements HttpResponseInterceptor {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean containsUnsupportedEncodings(Header contentEncodingHeader) {
|
||||
HeaderElement[] codecs = contentEncodingHeader.getElements();
|
||||
|
||||
|
||||
for (final HeaderElement codec : codecs) {
|
||||
String codecName = codec.getName().toLowerCase(Locale.US);
|
||||
if (!ALLOWED_CONTENT_ENCODINGS.contains(codecName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -47,9 +47,9 @@ class ContentEncodingInterceptor implements HttpResponseInterceptor {
|
||||
@Override
|
||||
public Header getContentEncoding() {
|
||||
return null;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
response.setEntity(wrapped);
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ public class HttpGetter {
|
||||
|
||||
@Inject
|
||||
public HttpGetter(CommaFeedConfiguration config) {
|
||||
this.userAgent = String.format("CommaFeed/%s (https://www.commafeed.com)", config.getVersion());
|
||||
this.userAgent = String.format("CommaFeed/%s (https://github.com/Athou/commafeed)", config.getVersion());
|
||||
}
|
||||
|
||||
public HttpResult getBinary(String url, int timeout) throws ClientProtocolException, IOException, NotModifiedException {
|
||||
|
||||
@@ -13,7 +13,7 @@ import com.commafeed.backend.model.FeedCategory;
|
||||
import com.commafeed.backend.model.QFeedCategory;
|
||||
import com.commafeed.backend.model.QUser;
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.mysema.query.types.Predicate;
|
||||
import com.querydsl.core.types.Predicate;
|
||||
|
||||
@Singleton
|
||||
public class FeedCategoryDAO extends GenericDAO<FeedCategory> {
|
||||
@@ -26,11 +26,11 @@ public class FeedCategoryDAO extends GenericDAO<FeedCategory> {
|
||||
}
|
||||
|
||||
public List<FeedCategory> findAll(User user) {
|
||||
return newQuery().from(category).where(category.user.eq(user)).join(category.user, QUser.user).fetch().list(category);
|
||||
return query().selectFrom(category).where(category.user.eq(user)).join(category.user, QUser.user).fetchJoin().fetch();
|
||||
}
|
||||
|
||||
public FeedCategory findById(User user, Long id) {
|
||||
return newQuery().from(category).where(category.user.eq(user), category.id.eq(id)).uniqueResult(category);
|
||||
return query().selectFrom(category).where(category.user.eq(user), category.id.eq(id)).fetchOne();
|
||||
}
|
||||
|
||||
public FeedCategory findByName(User user, String name, FeedCategory parent) {
|
||||
@@ -40,7 +40,7 @@ public class FeedCategoryDAO extends GenericDAO<FeedCategory> {
|
||||
} else {
|
||||
parentPredicate = category.parent.eq(parent);
|
||||
}
|
||||
return newQuery().from(category).where(category.user.eq(user), category.name.eq(name), parentPredicate).uniqueResult(category);
|
||||
return query().selectFrom(category).where(category.user.eq(user), category.name.eq(name), parentPredicate).fetchOne();
|
||||
}
|
||||
|
||||
public List<FeedCategory> findByParent(User user, FeedCategory parent) {
|
||||
@@ -50,7 +50,7 @@ public class FeedCategoryDAO extends GenericDAO<FeedCategory> {
|
||||
} else {
|
||||
parentPredicate = category.parent.eq(parent);
|
||||
}
|
||||
return newQuery().from(category).where(category.user.eq(user), parentPredicate).list(category);
|
||||
return query().selectFrom(category).where(category.user.eq(user), parentPredicate).fetch();
|
||||
}
|
||||
|
||||
public List<FeedCategory> findAllChildrenCategories(User user, FeedCategory parent) {
|
||||
|
||||
@@ -15,9 +15,9 @@ import com.commafeed.backend.model.QFeed;
|
||||
import com.commafeed.backend.model.QFeedSubscription;
|
||||
import com.commafeed.backend.model.QUser;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.mysema.query.BooleanBuilder;
|
||||
import com.mysema.query.jpa.hibernate.HibernateQuery;
|
||||
import com.mysema.query.jpa.hibernate.HibernateSubQuery;
|
||||
import com.querydsl.jpa.JPAExpressions;
|
||||
import com.querydsl.jpa.JPQLQuery;
|
||||
import com.querydsl.jpa.hibernate.HibernateQuery;
|
||||
|
||||
@Singleton
|
||||
public class FeedDAO extends GenericDAO<Feed> {
|
||||
@@ -30,26 +30,23 @@ public class FeedDAO extends GenericDAO<Feed> {
|
||||
}
|
||||
|
||||
public List<Feed> findNextUpdatable(int count, Date lastLoginThreshold) {
|
||||
BooleanBuilder disabledDatePredicate = new BooleanBuilder();
|
||||
disabledDatePredicate.or(feed.disabledUntil.isNull());
|
||||
disabledDatePredicate.or(feed.disabledUntil.lt(new Date()));
|
||||
HibernateQuery<Feed> query = query().selectFrom(feed);
|
||||
query.where(feed.disabledUntil.isNull().or(feed.disabledUntil.lt(new Date())));
|
||||
|
||||
HibernateQuery query = null;
|
||||
if (lastLoginThreshold != null) {
|
||||
QFeedSubscription subs = QFeedSubscription.feedSubscription;
|
||||
QUser user = QUser.user;
|
||||
query = newQuery().from(subs);
|
||||
query.join(subs.feed, feed).join(subs.user, user).where(disabledDatePredicate, user.lastLogin.gt(lastLoginThreshold));
|
||||
} else {
|
||||
query = newQuery().from(feed);
|
||||
query.where(disabledDatePredicate);
|
||||
|
||||
JPQLQuery<Integer> subQuery = JPAExpressions.selectOne().from(subs);
|
||||
subQuery.join(subs.user, user).where(user.lastLogin.gt(lastLoginThreshold));
|
||||
query.where(subQuery.exists());
|
||||
}
|
||||
|
||||
return query.orderBy(feed.disabledUntil.asc()).limit(count).distinct().list(feed);
|
||||
return query.orderBy(feed.disabledUntil.asc()).limit(count).distinct().fetch();
|
||||
}
|
||||
|
||||
public Feed findByUrl(String normalizedUrl) {
|
||||
List<Feed> feeds = newQuery().from(feed).where(feed.normalizedUrlHash.eq(DigestUtils.sha1Hex(normalizedUrl))).list(feed);
|
||||
List<Feed> feeds = query().selectFrom(feed).where(feed.normalizedUrlHash.eq(DigestUtils.sha1Hex(normalizedUrl))).fetch();
|
||||
Feed feed = Iterables.getFirst(feeds, null);
|
||||
if (feed != null && StringUtils.equals(normalizedUrl, feed.getNormalizedUrl())) {
|
||||
return feed;
|
||||
@@ -58,12 +55,12 @@ public class FeedDAO extends GenericDAO<Feed> {
|
||||
}
|
||||
|
||||
public List<Feed> findByTopic(String topic) {
|
||||
return newQuery().from(feed).where(feed.pushTopicHash.eq(DigestUtils.sha1Hex(topic))).list(feed);
|
||||
return query().selectFrom(feed).where(feed.pushTopicHash.eq(DigestUtils.sha1Hex(topic))).fetch();
|
||||
}
|
||||
|
||||
public List<Feed> findWithoutSubscriptions(int max) {
|
||||
QFeedSubscription sub = QFeedSubscription.feedSubscription;
|
||||
return newQuery().from(feed).where(new HibernateSubQuery().from(sub).where(sub.feed.eq(feed)).notExists()).limit(max).list(feed);
|
||||
// return newQuery().from(feed).leftJoin(feed.subscriptions, sub).where(sub.id.isNull()).limit(max).list(feed);
|
||||
return query().selectFrom(feed).where(JPAExpressions.selectOne().from(sub).where(sub.feed.eq(feed)).notExists()).limit(max)
|
||||
.fetch();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,13 +10,14 @@ import org.hibernate.SessionFactory;
|
||||
import com.commafeed.backend.model.FeedEntryContent;
|
||||
import com.commafeed.backend.model.QFeedEntry;
|
||||
import com.commafeed.backend.model.QFeedEntryContent;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.mysema.query.jpa.hibernate.HibernateSubQuery;
|
||||
import com.querydsl.jpa.JPAExpressions;
|
||||
import com.querydsl.jpa.JPQLQuery;
|
||||
|
||||
@Singleton
|
||||
public class FeedEntryContentDAO extends GenericDAO<FeedEntryContent> {
|
||||
|
||||
private QFeedEntryContent content = QFeedEntryContent.feedEntryContent;
|
||||
private QFeedEntry entry = QFeedEntry.feedEntry;
|
||||
|
||||
@Inject
|
||||
public FeedEntryContentDAO(SessionFactory sessionFactory) {
|
||||
@@ -24,16 +25,14 @@ public class FeedEntryContentDAO extends GenericDAO<FeedEntryContent> {
|
||||
}
|
||||
|
||||
public Long findExisting(String contentHash, String titleHash) {
|
||||
List<Long> list = newQuery().from(content).where(content.contentHash.eq(contentHash), content.titleHash.eq(titleHash)).limit(1)
|
||||
.list(content.id);
|
||||
return Iterables.getFirst(list, null);
|
||||
return query().select(content.id).from(content).where(content.contentHash.eq(contentHash), content.titleHash.eq(titleHash))
|
||||
.fetchFirst();
|
||||
}
|
||||
|
||||
public int deleteWithoutEntries(int max) {
|
||||
QFeedEntry entry = QFeedEntry.feedEntry;
|
||||
|
||||
HibernateSubQuery subQuery = new HibernateSubQuery().from(entry).where(entry.content.id.eq(content.id));
|
||||
List<FeedEntryContent> list = newQuery().from(content).where(subQuery.notExists()).limit(max).list(content);
|
||||
JPQLQuery<Integer> subQuery = JPAExpressions.selectOne().from(entry).where(entry.content.id.eq(content.id));
|
||||
List<FeedEntryContent> list = query().selectFrom(content).where(subQuery.notExists()).limit(max).fetch();
|
||||
|
||||
int deleted = list.size();
|
||||
delete(list);
|
||||
|
||||
@@ -6,18 +6,17 @@ import java.util.stream.Collectors;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import com.commafeed.backend.model.Feed;
|
||||
import com.commafeed.backend.model.FeedEntry;
|
||||
import com.commafeed.backend.model.QFeedEntry;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.mysema.query.Tuple;
|
||||
import com.mysema.query.types.expr.NumberExpression;
|
||||
import com.querydsl.core.Tuple;
|
||||
import com.querydsl.core.types.dsl.NumberExpression;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Singleton
|
||||
public class FeedEntryDAO extends GenericDAO<FeedEntry> {
|
||||
@@ -30,24 +29,25 @@ public class FeedEntryDAO extends GenericDAO<FeedEntry> {
|
||||
}
|
||||
|
||||
public Long findExisting(String guid, Feed feed) {
|
||||
List<Long> list = newQuery().from(entry).where(entry.guidHash.eq(DigestUtils.sha1Hex(guid)), entry.feed.eq(feed)).limit(1)
|
||||
.list(entry.id);
|
||||
return Iterables.getFirst(list, null);
|
||||
return query().select(entry.id).from(entry).where(entry.guidHash.eq(DigestUtils.sha1Hex(guid)), entry.feed.eq(feed)).limit(1)
|
||||
.fetchOne();
|
||||
}
|
||||
|
||||
public List<FeedCapacity> findFeedsExceedingCapacity(long maxCapacity, long max) {
|
||||
NumberExpression<Long> count = entry.id.count();
|
||||
List<Tuple> tuples = newQuery().from(entry).groupBy(entry.feed).having(count.gt(maxCapacity)).limit(max).list(entry.feed.id, count);
|
||||
List<Tuple> tuples = query().select(entry.feed.id, count).from(entry).groupBy(entry.feed).having(count.gt(maxCapacity)).limit(max)
|
||||
.fetch();
|
||||
return tuples.stream().map(t -> new FeedCapacity(t.get(entry.feed.id), t.get(count))).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public int delete(Long feedId, long max) {
|
||||
List<FeedEntry> list = newQuery().from(entry).where(entry.feed.id.eq(feedId)).limit(max).list(entry);
|
||||
|
||||
List<FeedEntry> list = query().selectFrom(entry).where(entry.feed.id.eq(feedId)).limit(max).fetch();
|
||||
return delete(list);
|
||||
}
|
||||
|
||||
public int deleteOldEntries(Long feedId, long max) {
|
||||
List<FeedEntry> list = newQuery().from(entry).where(entry.feed.id.eq(feedId)).orderBy(entry.updated.asc()).limit(max).list(entry);
|
||||
List<FeedEntry> list = query().selectFrom(entry).where(entry.feed.id.eq(feedId)).orderBy(entry.updated.asc()).limit(max).fetch();
|
||||
return delete(list);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,9 +30,9 @@ import com.commafeed.backend.model.UserSettings.ReadingOrder;
|
||||
import com.commafeed.frontend.model.UnreadCount;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Ordering;
|
||||
import com.mysema.query.BooleanBuilder;
|
||||
import com.mysema.query.Tuple;
|
||||
import com.mysema.query.jpa.hibernate.HibernateQuery;
|
||||
import com.querydsl.core.BooleanBuilder;
|
||||
import com.querydsl.core.Tuple;
|
||||
import com.querydsl.jpa.hibernate.HibernateQuery;
|
||||
|
||||
@Singleton
|
||||
public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
||||
@@ -62,13 +62,13 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
||||
builder.append(o2.getEntryUpdated(), o1.getEntryUpdated());
|
||||
builder.append(o2.getId(), o1.getId());
|
||||
return builder.toComparison();
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
private static final Comparator<FeedEntryStatus> STATUS_COMPARATOR_ASC = Ordering.from(STATUS_COMPARATOR_DESC).reverse();
|
||||
|
||||
public FeedEntryStatus getStatus(User user, FeedSubscription sub, FeedEntry entry) {
|
||||
List<FeedEntryStatus> statuses = newQuery().from(status).where(status.entry.eq(entry), status.subscription.eq(sub)).list(status);
|
||||
List<FeedEntryStatus> statuses = query().selectFrom(status).where(status.entry.eq(entry), status.subscription.eq(sub)).fetch();
|
||||
FeedEntryStatus status = Iterables.getFirst(statuses, null);
|
||||
return handleStatus(user, status, sub, entry);
|
||||
}
|
||||
@@ -93,7 +93,7 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
||||
}
|
||||
|
||||
public List<FeedEntryStatus> findStarred(User user, Date newerThan, int offset, int limit, ReadingOrder order, boolean includeContent) {
|
||||
HibernateQuery query = newQuery().from(status).where(status.user.eq(user), status.starred.isTrue());
|
||||
HibernateQuery<FeedEntryStatus> query = query().selectFrom(status).where(status.user.eq(user), status.starred.isTrue());
|
||||
if (newerThan != null) {
|
||||
query.where(status.entryInserted.gt(newerThan));
|
||||
}
|
||||
@@ -110,7 +110,7 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
||||
query.setTimeout(timeout / 1000);
|
||||
}
|
||||
|
||||
List<FeedEntryStatus> statuses = query.list(status);
|
||||
List<FeedEntryStatus> statuses = query.fetch();
|
||||
for (FeedEntryStatus status : statuses) {
|
||||
status = handleStatus(user, status, status.getSubscription(), status.getEntry());
|
||||
fetchTags(user, status);
|
||||
@@ -118,10 +118,10 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
||||
return lazyLoadContent(includeContent, statuses);
|
||||
}
|
||||
|
||||
private HibernateQuery buildQuery(User user, FeedSubscription sub, boolean unreadOnly, List<FeedEntryKeyword> keywords, Date newerThan,
|
||||
int offset, int limit, ReadingOrder order, Date last, String tag) {
|
||||
private HibernateQuery<FeedEntry> buildQuery(User user, FeedSubscription sub, boolean unreadOnly, List<FeedEntryKeyword> keywords,
|
||||
Date newerThan, int offset, int limit, ReadingOrder order, Date last, String tag) {
|
||||
|
||||
HibernateQuery query = newQuery().from(entry).where(entry.feed.eq(sub.getFeed()));
|
||||
HibernateQuery<FeedEntry> query = query().selectFrom(entry).where(entry.feed.eq(sub.getFeed()));
|
||||
|
||||
if (CollectionUtils.isNotEmpty(keywords)) {
|
||||
query.join(entry.content, content);
|
||||
@@ -197,8 +197,8 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
||||
FixedSizeSortedSet<FeedEntryStatus> set = new FixedSizeSortedSet<FeedEntryStatus>(capacity, comparator);
|
||||
for (FeedSubscription sub : subs) {
|
||||
Date last = (order != null && set.isFull()) ? set.last().getEntryUpdated() : null;
|
||||
HibernateQuery query = buildQuery(user, sub, unreadOnly, keywords, newerThan, -1, capacity, order, last, tag);
|
||||
List<Tuple> tuples = query.list(entry.id, entry.updated, status.id);
|
||||
HibernateQuery<FeedEntry> query = buildQuery(user, sub, unreadOnly, keywords, newerThan, -1, capacity, order, last, tag);
|
||||
List<Tuple> tuples = query.select(entry.id, entry.updated, status.id).fetch();
|
||||
for (Tuple tuple : tuples) {
|
||||
Long id = tuple.get(entry.id);
|
||||
Date updated = tuple.get(entry.updated);
|
||||
@@ -245,8 +245,8 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
||||
|
||||
public UnreadCount getUnreadCount(User user, FeedSubscription subscription) {
|
||||
UnreadCount uc = null;
|
||||
HibernateQuery query = buildQuery(user, subscription, true, null, null, -1, -1, null, null, null);
|
||||
List<Tuple> tuples = query.list(entry.count(), entry.updated.max());
|
||||
HibernateQuery<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());
|
||||
Date updated = tuple.get(entry.updated.max());
|
||||
@@ -266,7 +266,7 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
||||
}
|
||||
|
||||
public List<FeedEntryStatus> getOldStatuses(Date olderThan, int limit) {
|
||||
return newQuery().from(status).where(status.entryInserted.lt(olderThan), status.starred.isFalse()).limit(limit).list(status);
|
||||
return query().selectFrom(status).where(status.entryInserted.lt(olderThan), status.starred.isFalse()).limit(limit).fetch();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,10 +23,10 @@ public class FeedEntryTagDAO extends GenericDAO<FeedEntryTag> {
|
||||
}
|
||||
|
||||
public List<String> findByUser(User user) {
|
||||
return newQuery().from(tag).where(tag.user.eq(user)).distinct().list(tag.name);
|
||||
return query().selectDistinct(tag.name).from(tag).where(tag.user.eq(user)).fetch();
|
||||
}
|
||||
|
||||
public List<FeedEntryTag> findByEntry(User user, FeedEntry entry) {
|
||||
return newQuery().from(tag).where(tag.user.eq(user), tag.entry.eq(entry)).list(tag);
|
||||
return query().selectFrom(tag).where(tag.user.eq(user), tag.entry.eq(entry)).fetch();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.mysema.query.jpa.hibernate.HibernateQuery;
|
||||
import com.querydsl.jpa.hibernate.HibernateQuery;
|
||||
|
||||
@Singleton
|
||||
public class FeedSubscriptionDAO extends GenericDAO<FeedSubscription> {
|
||||
@@ -29,34 +29,34 @@ public class FeedSubscriptionDAO extends GenericDAO<FeedSubscription> {
|
||||
}
|
||||
|
||||
public FeedSubscription findById(User user, Long id) {
|
||||
List<FeedSubscription> subs = newQuery().from(sub).where(sub.user.eq(user), sub.id.eq(id)).leftJoin(sub.feed).fetch()
|
||||
.leftJoin(sub.category).fetch().list(sub);
|
||||
List<FeedSubscription> subs = query().selectFrom(sub).where(sub.user.eq(user), sub.id.eq(id)).leftJoin(sub.feed).fetchJoin()
|
||||
.leftJoin(sub.category).fetchJoin().fetch();
|
||||
return initRelations(Iterables.getFirst(subs, null));
|
||||
}
|
||||
|
||||
public List<FeedSubscription> findByFeed(Feed feed) {
|
||||
return newQuery().from(sub).where(sub.feed.eq(feed)).list(sub);
|
||||
return query().selectFrom(sub).where(sub.feed.eq(feed)).fetch();
|
||||
}
|
||||
|
||||
public FeedSubscription findByFeed(User user, Feed feed) {
|
||||
List<FeedSubscription> subs = newQuery().from(sub).where(sub.user.eq(user), sub.feed.eq(feed)).list(sub);
|
||||
List<FeedSubscription> subs = query().selectFrom(sub).where(sub.user.eq(user), sub.feed.eq(feed)).fetch();
|
||||
return initRelations(Iterables.getFirst(subs, null));
|
||||
}
|
||||
|
||||
public List<FeedSubscription> findAll(User user) {
|
||||
List<FeedSubscription> subs = newQuery().from(sub).where(sub.user.eq(user)).leftJoin(sub.feed).fetch().leftJoin(sub.category)
|
||||
.fetch().list(sub);
|
||||
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 query = newQuery().from(sub).where(sub.user.eq(user));
|
||||
HibernateQuery<FeedSubscription> query = query().selectFrom(sub).where(sub.user.eq(user));
|
||||
if (category == null) {
|
||||
query.where(sub.category.isNull());
|
||||
} else {
|
||||
query.where(sub.category.eq(category));
|
||||
}
|
||||
return initRelations(query.list(sub));
|
||||
return initRelations(query.fetch());
|
||||
}
|
||||
|
||||
public List<FeedSubscription> findByCategories(User user, List<FeedCategory> categories) {
|
||||
|
||||
@@ -1,22 +1,25 @@
|
||||
package com.commafeed.backend.dao;
|
||||
|
||||
import io.dropwizard.hibernate.AbstractDAO;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import com.commafeed.backend.model.AbstractModel;
|
||||
import com.mysema.query.jpa.hibernate.HibernateQuery;
|
||||
import com.querydsl.jpa.hibernate.HibernateQueryFactory;
|
||||
|
||||
import io.dropwizard.hibernate.AbstractDAO;
|
||||
|
||||
public abstract class GenericDAO<T extends AbstractModel> extends AbstractDAO<T> {
|
||||
|
||||
private HibernateQueryFactory factory;
|
||||
|
||||
protected GenericDAO(SessionFactory sessionFactory) {
|
||||
super(sessionFactory);
|
||||
this.factory = new HibernateQueryFactory(() -> currentSession());
|
||||
}
|
||||
|
||||
protected HibernateQuery newQuery() {
|
||||
return new HibernateQuery(currentSession());
|
||||
protected HibernateQueryFactory query() {
|
||||
return factory;
|
||||
}
|
||||
|
||||
public void saveOrUpdate(T model) {
|
||||
|
||||
@@ -18,13 +18,13 @@ public class UnitOfWork {
|
||||
}
|
||||
|
||||
public static void run(SessionFactory sessionFactory, SessionRunner sessionRunner) {
|
||||
run(sessionFactory, () -> {
|
||||
call(sessionFactory, () -> {
|
||||
sessionRunner.runInSession();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
public static <T> T run(SessionFactory sessionFactory, SessionRunnerReturningValue<T> sessionRunner) {
|
||||
public static <T> T call(SessionFactory sessionFactory, SessionRunnerReturningValue<T> sessionRunner) {
|
||||
final Session session = sessionFactory.openSession();
|
||||
if (ManagedSessionContext.hasBind(sessionFactory)) {
|
||||
throw new IllegalStateException("Already in a unit of work!");
|
||||
|
||||
@@ -19,18 +19,18 @@ public class UserDAO extends GenericDAO<User> {
|
||||
}
|
||||
|
||||
public User findByName(String name) {
|
||||
return newQuery().from(user).where(user.name.equalsIgnoreCase(name)).uniqueResult(user);
|
||||
return query().selectFrom(user).where(user.name.equalsIgnoreCase(name)).fetchOne();
|
||||
}
|
||||
|
||||
public User findByApiKey(String key) {
|
||||
return newQuery().from(user).where(user.apiKey.equalsIgnoreCase(key)).uniqueResult(user);
|
||||
return query().selectFrom(user).where(user.apiKey.equalsIgnoreCase(key)).fetchOne();
|
||||
}
|
||||
|
||||
public User findByEmail(String email) {
|
||||
return newQuery().from(user).where(user.email.equalsIgnoreCase(email)).uniqueResult(user);
|
||||
return query().selectFrom(user).where(user.email.equalsIgnoreCase(email)).fetchOne();
|
||||
}
|
||||
|
||||
public long count() {
|
||||
return newQuery().from(user).count();
|
||||
return query().selectFrom(user).fetchCount();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,11 +25,11 @@ public class UserRoleDAO extends GenericDAO<UserRole> {
|
||||
}
|
||||
|
||||
public List<UserRole> findAll() {
|
||||
return newQuery().from(role).leftJoin(role.user).fetch().distinct().list(role);
|
||||
return query().selectFrom(role).leftJoin(role.user).fetchJoin().distinct().fetch();
|
||||
}
|
||||
|
||||
public List<UserRole> findAll(User user) {
|
||||
return newQuery().from(role).where(role.user.eq(user)).distinct().list(role);
|
||||
return query().selectFrom(role).where(role.user.eq(user)).distinct().fetch();
|
||||
}
|
||||
|
||||
public Set<Role> findRoles(User user) {
|
||||
|
||||
@@ -20,6 +20,6 @@ public class UserSettingsDAO extends GenericDAO<UserSettings> {
|
||||
}
|
||||
|
||||
public UserSettings findByUser(User user) {
|
||||
return newQuery().from(settings).where(settings.user.eq(user)).uniqueResult(settings);
|
||||
return query().selectFrom(settings).where(settings.user.eq(user)).fetchFirst();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,6 @@ import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.utils.URLEncodedUtils;
|
||||
|
||||
@@ -27,8 +24,11 @@ import com.google.api.services.youtube.model.Channel;
|
||||
import com.google.api.services.youtube.model.ChannelListResponse;
|
||||
import com.google.api.services.youtube.model.Thumbnail;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }) )
|
||||
@Singleton
|
||||
public class YoutubeFaviconFetcher extends AbstractFaviconFetcher {
|
||||
|
||||
@@ -54,8 +54,7 @@ public class YoutubeFaviconFetcher extends AbstractFaviconFetcher {
|
||||
try {
|
||||
List<NameValuePair> params = URLEncodedUtils.parse(url.substring(url.indexOf("?") + 1), StandardCharsets.UTF_8);
|
||||
Optional<NameValuePair> userId = params.stream().filter(nvp -> nvp.getName().equalsIgnoreCase("user")).findFirst();
|
||||
Optional<NameValuePair> channelId = params.stream().filter(nvp -> nvp.getName().equalsIgnoreCase("channel")).findFirst();
|
||||
System.out.println(userId.isPresent());
|
||||
Optional<NameValuePair> channelId = params.stream().filter(nvp -> nvp.getName().equalsIgnoreCase("channel_id")).findFirst();
|
||||
if (!userId.isPresent() && !channelId.isPresent()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ public class FeedQueues {
|
||||
// add feeds that are up to refresh from the database
|
||||
int count = batchSize - contexts.size();
|
||||
if (count > 0) {
|
||||
List<Feed> feeds = UnitOfWork.run(sessionFactory, () -> feedDAO.findNextUpdatable(count, getLastLoginThreshold()));
|
||||
List<Feed> feeds = UnitOfWork.call(sessionFactory, () -> feedDAO.findNextUpdatable(count, getLastLoginThreshold()));
|
||||
for (Feed feed : feeds) {
|
||||
contexts.add(new FeedRefreshContext(feed, false));
|
||||
}
|
||||
|
||||
@@ -5,11 +5,11 @@ import java.util.concurrent.RejectedExecutionHandler;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import com.codahale.metrics.Gauge;
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* Wraps a {@link ThreadPoolExecutor} instance. Blocks when queue is full instead of rejecting the task. Allow priority queueing by using
|
||||
* {@link Task} instead of {@link Runnable}
|
||||
@@ -43,7 +43,7 @@ public class FeedRefreshExecutor {
|
||||
if (t != null) {
|
||||
log.error("thread from pool {} threw a runtime exception", poolName, t);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
pool.setRejectedExecutionHandler(new RejectedExecutionHandler() {
|
||||
@Override
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.commafeed.backend.feed;
|
||||
|
||||
import io.dropwizard.lifecycle.Managed;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
@@ -14,8 +12,6 @@ import java.util.stream.Collectors;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -39,6 +35,9 @@ import com.commafeed.backend.service.FeedUpdateService;
|
||||
import com.commafeed.backend.service.PubSubService;
|
||||
import com.google.common.util.concurrent.Striped;
|
||||
|
||||
import io.dropwizard.lifecycle.Managed;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Singleton
|
||||
public class FeedRefreshUpdater implements Managed {
|
||||
@@ -121,7 +120,7 @@ public class FeedRefreshUpdater implements Managed {
|
||||
if (!lastEntries.contains(cacheKey)) {
|
||||
log.debug("cache miss for {}", entry.getUrl());
|
||||
if (subscriptions == null) {
|
||||
subscriptions = UnitOfWork.run(sessionFactory, () -> feedSubscriptionDAO.findByFeed(feed));
|
||||
subscriptions = UnitOfWork.call(sessionFactory, () -> feedSubscriptionDAO.findByFeed(feed));
|
||||
}
|
||||
ok &= addEntry(feed, entry, subscriptions);
|
||||
entryCacheMiss.mark();
|
||||
@@ -183,7 +182,7 @@ public class FeedRefreshUpdater implements Managed {
|
||||
locked1 = lock1.tryLock(1, TimeUnit.MINUTES);
|
||||
locked2 = lock2.tryLock(1, TimeUnit.MINUTES);
|
||||
if (locked1 && locked2) {
|
||||
boolean inserted = UnitOfWork.run(sessionFactory, () -> feedUpdateService.addEntry(feed, entry, subscriptions));
|
||||
boolean inserted = UnitOfWork.call(sessionFactory, () -> feedUpdateService.addEntry(feed, entry, subscriptions));
|
||||
if (inserted) {
|
||||
entryInserted.mark();
|
||||
}
|
||||
|
||||
@@ -13,8 +13,6 @@ import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -40,6 +38,7 @@ import com.ibm.icu.text.CharsetMatch;
|
||||
import com.steadystate.css.parser.CSSOMParser;
|
||||
|
||||
import edu.uci.ics.crawler4j.url.URLCanonicalizer;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* Utility methods related to feed handling
|
||||
@@ -87,7 +86,7 @@ public class FeedUtils {
|
||||
whitelist.addAttributes("th", "border", "bordercolor", "abbr", "axis", "colspan", "rowspan", "scope", "width");
|
||||
whitelist.addAttributes("ul", "type");
|
||||
|
||||
whitelist.addProtocols("a", "href", "ftp", "http", "https", "mailto");
|
||||
whitelist.addProtocols("a", "href", "ftp", "http", "https", "magnet", "mailto");
|
||||
whitelist.addProtocols("blockquote", "cite", "http", "https");
|
||||
whitelist.addProtocols("img", "src", "http", "https");
|
||||
whitelist.addProtocols("q", "cite", "http", "https");
|
||||
@@ -438,10 +437,7 @@ public class FeedUtils {
|
||||
return removeTrailingSlash(publicUrl) + "/rest/feed/favicon/" + subscription.getId();
|
||||
}
|
||||
|
||||
public static String proxyImages(String content, String publicUrl, boolean proxyImages) {
|
||||
if (!proxyImages) {
|
||||
return content;
|
||||
}
|
||||
public static String proxyImages(String content, String publicUrl) {
|
||||
if (StringUtils.isBlank(content)) {
|
||||
return content;
|
||||
}
|
||||
@@ -451,7 +447,7 @@ public class FeedUtils {
|
||||
for (Element element : elements) {
|
||||
String href = element.attr("src");
|
||||
if (href != null) {
|
||||
String proxy = removeTrailingSlash(publicUrl) + "/rest/server/proxy?u=" + imageProxyEncoder(href);
|
||||
String proxy = proxyImage(href, publicUrl);
|
||||
element.attr("src", proxy);
|
||||
}
|
||||
}
|
||||
@@ -459,6 +455,13 @@ public class FeedUtils {
|
||||
return doc.body().html();
|
||||
}
|
||||
|
||||
public static String proxyImage(String url, String publicUrl) {
|
||||
if (StringUtils.isBlank(url)) {
|
||||
return url;
|
||||
}
|
||||
return removeTrailingSlash(publicUrl) + "/rest/server/proxy?u=" + imageProxyEncoder(url);
|
||||
}
|
||||
|
||||
public static String rot13(String msg) {
|
||||
StringBuilder message = new StringBuilder();
|
||||
|
||||
@@ -491,8 +494,8 @@ public class FeedUtils {
|
||||
Entry entry = it.next();
|
||||
boolean keep = true;
|
||||
for (FeedEntryKeyword keyword : keywords) {
|
||||
String title = Jsoup.parse(entry.getTitle()).text();
|
||||
String content = Jsoup.parse(entry.getContent()).text();
|
||||
String title = entry.getTitle() == null ? null : Jsoup.parse(entry.getTitle()).text();
|
||||
String content = entry.getContent() == null ? null : Jsoup.parse(entry.getContent()).text();
|
||||
boolean condition = !StringUtils.containsIgnoreCase(content, keyword.getKeyword())
|
||||
&& !StringUtils.containsIgnoreCase(title, keyword.getKeyword());
|
||||
if (keyword.getMode() == Mode.EXCLUDE) {
|
||||
|
||||
@@ -29,7 +29,7 @@ public class OPML11Parser extends OPML10Parser {
|
||||
|
||||
return false;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public WireFeed parse(Document document, boolean validate, Locale locale) throws IllegalArgumentException, FeedException {
|
||||
|
||||
@@ -6,9 +6,6 @@ import java.util.List;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import com.commafeed.backend.dao.FeedDAO;
|
||||
@@ -19,12 +16,15 @@ import com.commafeed.backend.dao.FeedEntryStatusDAO;
|
||||
import com.commafeed.backend.dao.UnitOfWork;
|
||||
import com.commafeed.backend.model.Feed;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* Contains utility methods for cleaning the database
|
||||
*
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }) )
|
||||
@Singleton
|
||||
public class DatabaseCleaningService {
|
||||
|
||||
@@ -42,16 +42,16 @@ public class DatabaseCleaningService {
|
||||
int deleted = 0;
|
||||
long entriesTotal = 0;
|
||||
do {
|
||||
List<Feed> feeds = UnitOfWork.run(sessionFactory, () -> feedDAO.findWithoutSubscriptions(1));
|
||||
List<Feed> feeds = UnitOfWork.call(sessionFactory, () -> feedDAO.findWithoutSubscriptions(1));
|
||||
for (Feed feed : feeds) {
|
||||
int entriesDeleted = 0;
|
||||
do {
|
||||
entriesDeleted = UnitOfWork.run(sessionFactory, () -> feedEntryDAO.delete(feed.getId(), BATCH_SIZE));
|
||||
entriesDeleted = UnitOfWork.call(sessionFactory, () -> feedEntryDAO.delete(feed.getId(), BATCH_SIZE));
|
||||
entriesTotal += entriesDeleted;
|
||||
log.info("removed {} entries for feeds without subscriptions", entriesTotal);
|
||||
} while (entriesDeleted > 0);
|
||||
}
|
||||
deleted = UnitOfWork.run(sessionFactory, () -> feedDAO.delete(feeds));
|
||||
deleted = UnitOfWork.call(sessionFactory, () -> feedDAO.delete(feeds));
|
||||
total += deleted;
|
||||
log.info("removed {} feeds without subscriptions", total);
|
||||
} while (deleted != 0);
|
||||
@@ -64,7 +64,7 @@ public class DatabaseCleaningService {
|
||||
long total = 0;
|
||||
int deleted = 0;
|
||||
do {
|
||||
deleted = UnitOfWork.run(sessionFactory, () -> feedEntryContentDAO.deleteWithoutEntries(BATCH_SIZE));
|
||||
deleted = UnitOfWork.call(sessionFactory, () -> feedEntryContentDAO.deleteWithoutEntries(BATCH_SIZE));
|
||||
total += deleted;
|
||||
log.info("removed {} contents without entries", total);
|
||||
} while (deleted != 0);
|
||||
@@ -75,7 +75,7 @@ public class DatabaseCleaningService {
|
||||
public long cleanEntriesForFeedsExceedingCapacity(final int maxFeedCapacity) {
|
||||
long total = 0;
|
||||
while (true) {
|
||||
List<FeedCapacity> feeds = UnitOfWork.run(sessionFactory,
|
||||
List<FeedCapacity> feeds = UnitOfWork.call(sessionFactory,
|
||||
() -> feedEntryDAO.findFeedsExceedingCapacity(maxFeedCapacity, BATCH_SIZE));
|
||||
if (feeds.isEmpty()) {
|
||||
break;
|
||||
@@ -85,7 +85,7 @@ public class DatabaseCleaningService {
|
||||
long remaining = feed.getCapacity() - maxFeedCapacity;
|
||||
do {
|
||||
final long rem = remaining;
|
||||
int deleted = UnitOfWork.run(sessionFactory,
|
||||
int deleted = UnitOfWork.call(sessionFactory,
|
||||
() -> feedEntryDAO.deleteOldEntries(feed.getId(), Math.min(BATCH_SIZE, rem)));
|
||||
total += deleted;
|
||||
remaining -= deleted;
|
||||
@@ -102,7 +102,7 @@ public class DatabaseCleaningService {
|
||||
long total = 0;
|
||||
int deleted = 0;
|
||||
do {
|
||||
deleted = UnitOfWork.run(sessionFactory,
|
||||
deleted = UnitOfWork.call(sessionFactory,
|
||||
() -> feedEntryStatusDAO.delete(feedEntryStatusDAO.getOldStatuses(olderThan, BATCH_SIZE)));
|
||||
total += deleted;
|
||||
log.info("removed {} old read statuses", total);
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.commafeed.backend.service;
|
||||
|
||||
import io.dropwizard.lifecycle.Managed;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.Arrays;
|
||||
|
||||
@@ -9,17 +7,6 @@ import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import liquibase.Liquibase;
|
||||
import liquibase.database.Database;
|
||||
import liquibase.database.DatabaseFactory;
|
||||
import liquibase.database.core.PostgresDatabase;
|
||||
import liquibase.database.jvm.JdbcConnection;
|
||||
import liquibase.resource.ClassLoaderResourceAccessor;
|
||||
import liquibase.resource.ResourceAccessor;
|
||||
import liquibase.structure.DatabaseObject;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl;
|
||||
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
|
||||
@@ -31,8 +18,20 @@ import com.commafeed.backend.dao.UnitOfWork;
|
||||
import com.commafeed.backend.dao.UserDAO;
|
||||
import com.commafeed.backend.model.UserRole.Role;
|
||||
|
||||
import io.dropwizard.lifecycle.Managed;
|
||||
import liquibase.Liquibase;
|
||||
import liquibase.database.Database;
|
||||
import liquibase.database.DatabaseFactory;
|
||||
import liquibase.database.core.PostgresDatabase;
|
||||
import liquibase.database.jvm.JdbcConnection;
|
||||
import liquibase.resource.ClassLoaderResourceAccessor;
|
||||
import liquibase.resource.ResourceAccessor;
|
||||
import liquibase.structure.DatabaseObject;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }) )
|
||||
@Singleton
|
||||
public class StartupService implements Managed {
|
||||
|
||||
@@ -44,7 +43,7 @@ public class StartupService implements Managed {
|
||||
@Override
|
||||
public void start() throws Exception {
|
||||
updateSchema();
|
||||
long count = UnitOfWork.run(sessionFactory, () -> userDAO.count());
|
||||
long count = UnitOfWork.call(sessionFactory, () -> userDAO.count());
|
||||
if (count == 0) {
|
||||
UnitOfWork.run(sessionFactory, () -> initialData());
|
||||
}
|
||||
|
||||
@@ -4,11 +4,10 @@ import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiModel("Entry details")
|
||||
@Data
|
||||
|
||||
@@ -4,11 +4,10 @@ import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiModel("List of entries with some metadata")
|
||||
@Data
|
||||
|
||||
@@ -6,7 +6,7 @@ import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.Data;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.commafeed.backend.feed.FeedUtils;
|
||||
import com.commafeed.backend.model.FeedEntry;
|
||||
@@ -19,8 +19,10 @@ import com.rometools.rome.feed.synd.SyndEnclosure;
|
||||
import com.rometools.rome.feed.synd.SyndEnclosureImpl;
|
||||
import com.rometools.rome.feed.synd.SyndEntry;
|
||||
import com.rometools.rome.feed.synd.SyndEntryImpl;
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiModel("Entry details")
|
||||
@@ -52,10 +54,11 @@ public class Entry implements Serializable {
|
||||
if (content != null) {
|
||||
entry.setRtl(FeedUtils.isRTL(feedEntry));
|
||||
entry.setTitle(content.getTitle());
|
||||
entry.setContent(FeedUtils.proxyImages(content.getContent(), publicUrl, proxyImages));
|
||||
entry.setContent(proxyImages ? FeedUtils.proxyImages(content.getContent(), publicUrl) : content.getContent());
|
||||
entry.setAuthor(content.getAuthor());
|
||||
entry.setEnclosureUrl(content.getEnclosureUrl());
|
||||
entry.setEnclosureType(content.getEnclosureType());
|
||||
entry.setEnclosureUrl(proxyImages && StringUtils.contains(content.getEnclosureType(), "image")
|
||||
? FeedUtils.proxyImage(content.getEnclosureUrl(), publicUrl) : content.getEnclosureUrl());
|
||||
entry.setCategories(content.getCategories());
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,9 @@ package com.commafeed.frontend.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiModel("Feed details")
|
||||
@Data
|
||||
|
||||
@@ -2,10 +2,9 @@ package com.commafeed.frontend.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiModel("Server infos")
|
||||
@Data
|
||||
|
||||
@@ -2,11 +2,10 @@ package com.commafeed.frontend.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiModel("User settings")
|
||||
@Data
|
||||
|
||||
@@ -3,14 +3,14 @@ package com.commafeed.frontend.model;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.commafeed.backend.feed.FeedUtils;
|
||||
import com.commafeed.backend.model.Feed;
|
||||
import com.commafeed.backend.model.FeedCategory;
|
||||
import com.commafeed.backend.model.FeedSubscription;
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiModel("User information")
|
||||
|
||||
@@ -3,10 +3,9 @@ package com.commafeed.frontend.model;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiModel("Unread count")
|
||||
@Data
|
||||
|
||||
@@ -3,11 +3,10 @@ package com.commafeed.frontend.model;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiModel("User information")
|
||||
@Data
|
||||
|
||||
@@ -2,11 +2,10 @@ package com.commafeed.frontend.model.request;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiModel("Add Category Request")
|
||||
@Data
|
||||
|
||||
@@ -2,11 +2,10 @@ package com.commafeed.frontend.model.request;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiModel("Category modification request")
|
||||
@Data
|
||||
|
||||
@@ -2,11 +2,10 @@ package com.commafeed.frontend.model.request;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiModel("Mark Request")
|
||||
@Data
|
||||
|
||||
@@ -2,11 +2,10 @@ package com.commafeed.frontend.model.request;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiModel("Feed information request")
|
||||
@Data
|
||||
|
||||
@@ -3,11 +3,10 @@ package com.commafeed.frontend.model.request;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiModel("Feed merge Request")
|
||||
@Data
|
||||
|
||||
@@ -2,11 +2,10 @@ package com.commafeed.frontend.model.request;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiModel("Feed modification request")
|
||||
@Data
|
||||
|
||||
@@ -2,11 +2,10 @@ package com.commafeed.frontend.model.request;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiModel
|
||||
@Data
|
||||
|
||||
@@ -2,11 +2,10 @@ package com.commafeed.frontend.model.request;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@Data
|
||||
@ApiModel
|
||||
|
||||
@@ -3,11 +3,10 @@ package com.commafeed.frontend.model.request;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiModel("Mark Request")
|
||||
@Data
|
||||
|
||||
@@ -3,11 +3,10 @@ package com.commafeed.frontend.model.request;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiModel("Multiple Mark Request")
|
||||
@Data
|
||||
|
||||
@@ -2,13 +2,12 @@ package com.commafeed.frontend.model.request;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import org.hibernate.validator.constraints.Email;
|
||||
import org.hibernate.validator.constraints.NotEmpty;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@Data
|
||||
|
||||
@@ -2,11 +2,10 @@ package com.commafeed.frontend.model.request;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiModel("Profile modification request")
|
||||
@Data
|
||||
|
||||
@@ -2,14 +2,13 @@ package com.commafeed.frontend.model.request;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import org.hibernate.validator.constraints.Email;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
import org.hibernate.validator.constraints.NotEmpty;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@Data
|
||||
|
||||
@@ -2,11 +2,10 @@ package com.commafeed.frontend.model.request;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiModel("Star Request")
|
||||
@Data
|
||||
|
||||
@@ -2,11 +2,10 @@ package com.commafeed.frontend.model.request;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiModel("Subscription request")
|
||||
@Data
|
||||
|
||||
@@ -3,11 +3,10 @@ package com.commafeed.frontend.model.request;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModel;
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ApiModel("Tag Request")
|
||||
@Data
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.commafeed.frontend.resource;
|
||||
|
||||
import io.dropwizard.hibernate.UnitOfWork;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -18,11 +16,10 @@ import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import com.codahale.metrics.annotation.Timed;
|
||||
import com.commafeed.CommaFeedApplication;
|
||||
import com.commafeed.CommaFeedConfiguration;
|
||||
import com.commafeed.CommaFeedConfiguration.ApplicationSettings;
|
||||
@@ -38,15 +35,18 @@ import com.commafeed.frontend.model.UserModel;
|
||||
import com.commafeed.frontend.model.request.IDRequest;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.wordnik.swagger.annotations.Api;
|
||||
import com.wordnik.swagger.annotations.ApiOperation;
|
||||
import com.wordnik.swagger.annotations.ApiParam;
|
||||
|
||||
import io.dropwizard.hibernate.UnitOfWork;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Path("/admin")
|
||||
@Api(value = "/admin", description = "Operations about application administration")
|
||||
@Api(value = "/admin")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }) )
|
||||
@Singleton
|
||||
public class AdminREST {
|
||||
|
||||
@@ -61,6 +61,7 @@ public class AdminREST {
|
||||
@POST
|
||||
@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) {
|
||||
Preconditions.checkNotNull(userModel);
|
||||
Preconditions.checkNotNull(userModel.getName());
|
||||
@@ -115,6 +116,7 @@ public class AdminREST {
|
||||
@GET
|
||||
@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) {
|
||||
Preconditions.checkNotNull(id);
|
||||
User u = userDAO.findById(id);
|
||||
@@ -131,6 +133,7 @@ public class AdminREST {
|
||||
@GET
|
||||
@UnitOfWork
|
||||
@ApiOperation(value = "Get all users", notes = "Get all users", response = UserModel.class, responseContainer = "List")
|
||||
@Timed
|
||||
public Response getUsers(@SecurityCheck(Role.ADMIN) User user) {
|
||||
Map<Long, UserModel> users = new HashMap<>();
|
||||
for (UserRole role : userRoleDAO.findAll()) {
|
||||
@@ -158,6 +161,7 @@ public class AdminREST {
|
||||
@POST
|
||||
@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) {
|
||||
Preconditions.checkNotNull(req);
|
||||
Preconditions.checkNotNull(req.getId());
|
||||
@@ -177,6 +181,7 @@ public class AdminREST {
|
||||
@GET
|
||||
@UnitOfWork
|
||||
@ApiOperation(value = "Retrieve application settings", notes = "Retrieve application settings", response = ApplicationSettings.class)
|
||||
@Timed
|
||||
public Response getSettings(@SecurityCheck(Role.ADMIN) User user) {
|
||||
return Response.ok(config.getApplicationSettings()).build();
|
||||
}
|
||||
@@ -185,6 +190,7 @@ public class AdminREST {
|
||||
@GET
|
||||
@UnitOfWork
|
||||
@ApiOperation(value = "Retrieve server metrics")
|
||||
@Timed
|
||||
public Response getMetrics(@SecurityCheck(Role.ADMIN) User user) {
|
||||
return Response.ok(metrics).build();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.commafeed.frontend.resource;
|
||||
|
||||
import io.dropwizard.hibernate.UnitOfWork;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -27,13 +25,11 @@ import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.codahale.metrics.annotation.Timed;
|
||||
import com.commafeed.CommaFeedConfiguration;
|
||||
import com.commafeed.backend.cache.CacheService;
|
||||
import com.commafeed.backend.dao.FeedCategoryDAO;
|
||||
@@ -65,16 +61,20 @@ import com.google.common.collect.Lists;
|
||||
import com.rometools.rome.feed.synd.SyndFeed;
|
||||
import com.rometools.rome.feed.synd.SyndFeedImpl;
|
||||
import com.rometools.rome.io.SyndFeedOutput;
|
||||
import com.wordnik.swagger.annotations.Api;
|
||||
import com.wordnik.swagger.annotations.ApiOperation;
|
||||
import com.wordnik.swagger.annotations.ApiParam;
|
||||
|
||||
import io.dropwizard.hibernate.UnitOfWork;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Path("/category")
|
||||
@Api(value = "/category", description = "Operations about user categories")
|
||||
@Api(value = "/category")
|
||||
@Slf4j
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }) )
|
||||
@Singleton
|
||||
public class CategoryREST {
|
||||
|
||||
@@ -93,10 +93,13 @@ public class CategoryREST {
|
||||
@GET
|
||||
@UnitOfWork
|
||||
@ApiOperation(value = "Get category entries", notes = "Get a list of category entries", response = Entries.class)
|
||||
public Response getCategoryEntries(
|
||||
@SecurityCheck User user,
|
||||
@Timed
|
||||
public Response getCategoryEntries(@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", allowableValues = "all,unread", required = true) @DefaultValue("unread") @QueryParam("readType") ReadingMode readType,
|
||||
@ApiParam(
|
||||
value = "all entries or only unread ones",
|
||||
allowableValues = "all,unread",
|
||||
required = true) @DefaultValue("unread") @QueryParam("readType") ReadingMode readType,
|
||||
@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,
|
||||
@@ -104,7 +107,8 @@ public class CategoryREST {
|
||||
@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,
|
||||
@ApiParam(value = "comma-separated list of excluded subscription ids") @QueryParam("excludedSubscriptionIds") String excludedSubscriptionIds,
|
||||
@ApiParam(
|
||||
value = "comma-separated list of excluded subscription ids") @QueryParam("excludedSubscriptionIds") String excludedSubscriptionIds,
|
||||
@ApiParam(value = "keep only entries tagged with this tag") @QueryParam("tag") String tag) {
|
||||
|
||||
Preconditions.checkNotNull(readType);
|
||||
@@ -139,18 +143,16 @@ public class CategoryREST {
|
||||
offset, limit + 1, order, true, onlyIds, tag);
|
||||
|
||||
for (FeedEntryStatus status : list) {
|
||||
entries.getEntries().add(
|
||||
Entry.build(status, config.getApplicationSettings().getPublicUrl(), config.getApplicationSettings()
|
||||
.getImageProxyEnabled()));
|
||||
entries.getEntries().add(Entry.build(status, config.getApplicationSettings().getPublicUrl(),
|
||||
config.getApplicationSettings().getImageProxyEnabled()));
|
||||
}
|
||||
|
||||
} else if (STARRED.equals(id)) {
|
||||
entries.setName("Starred");
|
||||
List<FeedEntryStatus> starred = feedEntryStatusDAO.findStarred(user, newerThanDate, offset, limit + 1, order, !onlyIds);
|
||||
for (FeedEntryStatus status : starred) {
|
||||
entries.getEntries().add(
|
||||
Entry.build(status, config.getApplicationSettings().getPublicUrl(), config.getApplicationSettings()
|
||||
.getImageProxyEnabled()));
|
||||
entries.getEntries().add(Entry.build(status, config.getApplicationSettings().getPublicUrl(),
|
||||
config.getApplicationSettings().getImageProxyEnabled()));
|
||||
}
|
||||
} else {
|
||||
FeedCategory parent = feedCategoryDAO.findById(user, Long.valueOf(id));
|
||||
@@ -162,9 +164,8 @@ public class CategoryREST {
|
||||
offset, limit + 1, order, true, onlyIds, tag);
|
||||
|
||||
for (FeedEntryStatus status : list) {
|
||||
entries.getEntries().add(
|
||||
Entry.build(status, config.getApplicationSettings().getPublicUrl(), config.getApplicationSettings()
|
||||
.getImageProxyEnabled()));
|
||||
entries.getEntries().add(Entry.build(status, config.getApplicationSettings().getPublicUrl(),
|
||||
config.getApplicationSettings().getImageProxyEnabled()));
|
||||
}
|
||||
entries.setName(parent.getName());
|
||||
} else {
|
||||
@@ -189,10 +190,13 @@ public class CategoryREST {
|
||||
@UnitOfWork
|
||||
@ApiOperation(value = "Get category entries as feed", notes = "Get a feed of category entries")
|
||||
@Produces(MediaType.APPLICATION_XML)
|
||||
public Response getCategoryEntriesAsFeed(
|
||||
@SecurityCheck(apiKeyAllowed = true) User user,
|
||||
@Timed
|
||||
public Response getCategoryEntriesAsFeed(@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", allowableValues = "all,unread", required = true) @DefaultValue("all") @QueryParam("readType") ReadingMode readType,
|
||||
@ApiParam(
|
||||
value = "all entries or only unread ones",
|
||||
allowableValues = "all,unread",
|
||||
required = true) @DefaultValue("all") @QueryParam("readType") ReadingMode readType,
|
||||
@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,
|
||||
@@ -200,7 +204,8 @@ public class CategoryREST {
|
||||
@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,
|
||||
@ApiParam(value = "comma-separated list of excluded subscription ids") @QueryParam("excludedSubscriptionIds") String excludedSubscriptionIds,
|
||||
@ApiParam(
|
||||
value = "comma-separated list of excluded subscription ids") @QueryParam("excludedSubscriptionIds") String excludedSubscriptionIds,
|
||||
@ApiParam(value = "keep only entries tagged with this tag") @QueryParam("tag") String tag) {
|
||||
|
||||
Response response = getCategoryEntries(user, id, readType, newerThan, offset, limit, order, keywords, onlyIds,
|
||||
@@ -232,6 +237,7 @@ public class CategoryREST {
|
||||
@POST
|
||||
@UnitOfWork
|
||||
@ApiOperation(value = "Mark category entries", notes = "Mark feed entries of this category as read")
|
||||
@Timed
|
||||
public Response markCategoryEntries(@SecurityCheck User user,
|
||||
@ApiParam(value = "category id, or 'all'", required = true) MarkRequest req) {
|
||||
Preconditions.checkNotNull(req);
|
||||
@@ -273,6 +279,7 @@ public class CategoryREST {
|
||||
@POST
|
||||
@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) {
|
||||
Preconditions.checkNotNull(req);
|
||||
Preconditions.checkNotNull(req.getName());
|
||||
@@ -296,6 +303,7 @@ public class CategoryREST {
|
||||
@Path("/delete")
|
||||
@UnitOfWork
|
||||
@ApiOperation(value = "Delete a category", notes = "Delete an existing feed category")
|
||||
@Timed
|
||||
public Response deleteCategory(@SecurityCheck User user, @ApiParam(required = true) IDRequest req) {
|
||||
|
||||
Preconditions.checkNotNull(req);
|
||||
@@ -328,6 +336,7 @@ public class CategoryREST {
|
||||
@Path("/modify")
|
||||
@UnitOfWork
|
||||
@ApiOperation(value = "Rename a category", notes = "Rename an existing feed category")
|
||||
@Timed
|
||||
public Response modifyCategory(@SecurityCheck User user, @ApiParam(required = true) CategoryModificationRequest req) {
|
||||
Preconditions.checkNotNull(req);
|
||||
Preconditions.checkNotNull(req.getId());
|
||||
@@ -382,6 +391,7 @@ public class CategoryREST {
|
||||
@Path("/collapse")
|
||||
@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) {
|
||||
Preconditions.checkNotNull(req);
|
||||
Preconditions.checkNotNull(req.getId());
|
||||
@@ -400,6 +410,7 @@ public class CategoryREST {
|
||||
@Path("/unreadCount")
|
||||
@UnitOfWork
|
||||
@ApiOperation(value = "Get unread count for feed subscriptions", response = UnreadCount.class, responseContainer = "List")
|
||||
@Timed
|
||||
public Response getUnreadCount(@SecurityCheck User user) {
|
||||
Map<Long, UnreadCount> unreadCount = feedSubscriptionService.getUnreadCount(user);
|
||||
return Response.ok(Lists.newArrayList(unreadCount.values())).build();
|
||||
@@ -409,6 +420,7 @@ public class CategoryREST {
|
||||
@Path("/get")
|
||||
@UnitOfWork
|
||||
@ApiOperation(value = "Get feed categories", notes = "Get all categories and subscriptions of the user", response = Category.class)
|
||||
@Timed
|
||||
public Response getSubscriptions(@SecurityCheck User user) {
|
||||
Category root = cache.getUserRootCategory(user);
|
||||
if (root == null) {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.commafeed.frontend.resource;
|
||||
|
||||
import io.dropwizard.hibernate.UnitOfWork;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@@ -14,8 +12,7 @@ import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import com.codahale.metrics.annotation.Timed;
|
||||
import com.commafeed.backend.dao.FeedEntryTagDAO;
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.commafeed.backend.service.FeedEntryService;
|
||||
@@ -26,15 +23,18 @@ import com.commafeed.frontend.model.request.MultipleMarkRequest;
|
||||
import com.commafeed.frontend.model.request.StarRequest;
|
||||
import com.commafeed.frontend.model.request.TagRequest;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.wordnik.swagger.annotations.Api;
|
||||
import com.wordnik.swagger.annotations.ApiOperation;
|
||||
import com.wordnik.swagger.annotations.ApiParam;
|
||||
|
||||
import io.dropwizard.hibernate.UnitOfWork;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Path("/entry")
|
||||
@Api(value = "/entry", description = "Operations about feed entries")
|
||||
@Api(value = "/entry")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }) )
|
||||
@Singleton
|
||||
public class EntryREST {
|
||||
|
||||
@@ -46,6 +46,7 @@ public class EntryREST {
|
||||
@POST
|
||||
@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) {
|
||||
Preconditions.checkNotNull(req);
|
||||
Preconditions.checkNotNull(req.getId());
|
||||
@@ -58,6 +59,7 @@ public class EntryREST {
|
||||
@POST
|
||||
@UnitOfWork
|
||||
@ApiOperation(value = "Mark multiple feed entries", notes = "Mark feed entries as read/unread")
|
||||
@Timed
|
||||
public Response markFeedEntries(@SecurityCheck User user,
|
||||
@ApiParam(value = "Multiple Mark Request", required = true) MultipleMarkRequest req) {
|
||||
Preconditions.checkNotNull(req);
|
||||
@@ -74,6 +76,7 @@ public class EntryREST {
|
||||
@POST
|
||||
@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) {
|
||||
Preconditions.checkNotNull(req);
|
||||
Preconditions.checkNotNull(req.getId());
|
||||
@@ -88,6 +91,7 @@ public class EntryREST {
|
||||
@GET
|
||||
@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) {
|
||||
List<String> tags = feedEntryTagDAO.findByUser(user);
|
||||
return Response.ok(tags).build();
|
||||
@@ -97,6 +101,7 @@ public class EntryREST {
|
||||
@POST
|
||||
@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) {
|
||||
Preconditions.checkNotNull(req);
|
||||
Preconditions.checkNotNull(req.getEntryId());
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.commafeed.frontend.resource;
|
||||
|
||||
import io.dropwizard.hibernate.UnitOfWork;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.StringWriter;
|
||||
import java.net.URI;
|
||||
@@ -32,14 +30,12 @@ import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.ResponseBuilder;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.glassfish.jersey.media.multipart.FormDataParam;
|
||||
|
||||
import com.codahale.metrics.annotation.Timed;
|
||||
import com.commafeed.CommaFeedApplication;
|
||||
import com.commafeed.CommaFeedConfiguration;
|
||||
import com.commafeed.backend.cache.CacheService;
|
||||
@@ -86,16 +82,20 @@ import com.rometools.rome.feed.synd.SyndFeed;
|
||||
import com.rometools.rome.feed.synd.SyndFeedImpl;
|
||||
import com.rometools.rome.io.SyndFeedOutput;
|
||||
import com.rometools.rome.io.WireFeedOutput;
|
||||
import com.wordnik.swagger.annotations.Api;
|
||||
import com.wordnik.swagger.annotations.ApiOperation;
|
||||
import com.wordnik.swagger.annotations.ApiParam;
|
||||
|
||||
import io.dropwizard.hibernate.UnitOfWork;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Path("/feed")
|
||||
@Api(value = "/feed", description = "Operations about feeds")
|
||||
@Api(value = "/feed")
|
||||
@Slf4j
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }) )
|
||||
@Singleton
|
||||
public class FeedREST {
|
||||
|
||||
@@ -131,10 +131,13 @@ public class FeedREST {
|
||||
@GET
|
||||
@UnitOfWork
|
||||
@ApiOperation(value = "Get feed entries", notes = "Get a list of feed entries", response = Entries.class)
|
||||
public Response getFeedEntries(
|
||||
@SecurityCheck User user,
|
||||
@Timed
|
||||
public Response getFeedEntries(@SecurityCheck User user,
|
||||
@ApiParam(value = "id of the feed", required = true) @QueryParam("id") String id,
|
||||
@ApiParam(value = "all entries or only unread ones", allowableValues = "all,unread", required = true) @DefaultValue("unread") @QueryParam("readType") ReadingMode readType,
|
||||
@ApiParam(
|
||||
value = "all entries or only unread ones",
|
||||
allowableValues = "all,unread",
|
||||
required = true) @DefaultValue("unread") @QueryParam("readType") ReadingMode readType,
|
||||
@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,
|
||||
@@ -172,9 +175,8 @@ public class FeedREST {
|
||||
entryKeywords, newerThanDate, offset, limit + 1, order, true, onlyIds, null);
|
||||
|
||||
for (FeedEntryStatus status : list) {
|
||||
entries.getEntries().add(
|
||||
Entry.build(status, config.getApplicationSettings().getPublicUrl(), config.getApplicationSettings()
|
||||
.getImageProxyEnabled()));
|
||||
entries.getEntries().add(Entry.build(status, config.getApplicationSettings().getPublicUrl(),
|
||||
config.getApplicationSettings().getImageProxyEnabled()));
|
||||
}
|
||||
|
||||
boolean hasMore = entries.getEntries().size() > limit;
|
||||
@@ -197,10 +199,13 @@ public class FeedREST {
|
||||
@UnitOfWork
|
||||
@ApiOperation(value = "Get feed entries as a feed", notes = "Get a feed of feed entries")
|
||||
@Produces(MediaType.APPLICATION_XML)
|
||||
public Response getFeedEntriesAsFeed(
|
||||
@SecurityCheck(apiKeyAllowed = true) User user,
|
||||
@Timed
|
||||
public Response getFeedEntriesAsFeed(@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", allowableValues = "all,unread", required = true) @DefaultValue("all") @QueryParam("readType") ReadingMode readType,
|
||||
@ApiParam(
|
||||
value = "all entries or only unread ones",
|
||||
allowableValues = "all,unread",
|
||||
required = true) @DefaultValue("all") @QueryParam("readType") ReadingMode readType,
|
||||
@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,
|
||||
@@ -254,6 +259,7 @@ public class FeedREST {
|
||||
@Path("/fetch")
|
||||
@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) {
|
||||
Preconditions.checkNotNull(req);
|
||||
Preconditions.checkNotNull(req.getUrl());
|
||||
@@ -272,6 +278,7 @@ public class FeedREST {
|
||||
@GET
|
||||
@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) {
|
||||
feedSubscriptionService.refreshAll(user);
|
||||
return Response.ok().build();
|
||||
@@ -281,6 +288,7 @@ public class FeedREST {
|
||||
@POST
|
||||
@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) {
|
||||
|
||||
Preconditions.checkNotNull(req);
|
||||
@@ -299,6 +307,7 @@ public class FeedREST {
|
||||
@POST
|
||||
@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) {
|
||||
Preconditions.checkNotNull(req);
|
||||
Preconditions.checkNotNull(req.getId());
|
||||
@@ -318,6 +327,7 @@ public class FeedREST {
|
||||
@Path("/get/{id}")
|
||||
@UnitOfWork
|
||||
@ApiOperation(value = "", notes = "")
|
||||
@Timed
|
||||
public Response get(@SecurityCheck User user, @ApiParam(value = "user id", required = true) @PathParam("id") Long id) {
|
||||
|
||||
Preconditions.checkNotNull(id);
|
||||
@@ -333,6 +343,7 @@ public class FeedREST {
|
||||
@Path("/favicon/{id}")
|
||||
@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) {
|
||||
|
||||
Preconditions.checkNotNull(id);
|
||||
@@ -362,6 +373,7 @@ public class FeedREST {
|
||||
@Path("/subscribe")
|
||||
@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) {
|
||||
Preconditions.checkNotNull(req);
|
||||
Preconditions.checkNotNull(req.getTitle());
|
||||
@@ -388,6 +400,7 @@ public class FeedREST {
|
||||
@Path("/subscribe")
|
||||
@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) {
|
||||
|
||||
try {
|
||||
@@ -415,6 +428,7 @@ public class FeedREST {
|
||||
@Path("/unsubscribe")
|
||||
@UnitOfWork
|
||||
@ApiOperation(value = "Unsubscribe from a feed", notes = "Unsubscribe from a feed")
|
||||
@Timed
|
||||
public Response unsubscribe(@SecurityCheck User user, @ApiParam(required = true) IDRequest req) {
|
||||
Preconditions.checkNotNull(req);
|
||||
Preconditions.checkNotNull(req.getId());
|
||||
@@ -431,6 +445,7 @@ public class FeedREST {
|
||||
@Path("/modify")
|
||||
@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) {
|
||||
Preconditions.checkNotNull(req);
|
||||
Preconditions.checkNotNull(req.getId());
|
||||
@@ -442,7 +457,7 @@ public class FeedREST {
|
||||
}
|
||||
|
||||
FeedSubscription subscription = feedSubscriptionDAO.findById(user, req.getId());
|
||||
subscription.setFilter(req.getFilter());
|
||||
subscription.setFilter(StringUtils.lowerCase(req.getFilter()));
|
||||
|
||||
if (StringUtils.isNotBlank(req.getName())) {
|
||||
subscription.setTitle(req.getName());
|
||||
@@ -490,12 +505,13 @@ public class FeedREST {
|
||||
@UnitOfWork
|
||||
@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) {
|
||||
|
||||
String publicUrl = config.getApplicationSettings().getPublicUrl();
|
||||
if (StringUtils.isBlank(publicUrl)) {
|
||||
throw new WebApplicationException(Response.status(Status.INTERNAL_SERVER_ERROR)
|
||||
.entity("Set the public URL in the admin section.").build());
|
||||
throw new WebApplicationException(
|
||||
Response.status(Status.INTERNAL_SERVER_ERROR).entity("Set the public URL in the admin section.").build());
|
||||
}
|
||||
|
||||
if (CommaFeedApplication.USERNAME_DEMO.equals(user.getName())) {
|
||||
@@ -516,6 +532,7 @@ public class FeedREST {
|
||||
@UnitOfWork
|
||||
@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) {
|
||||
Opml opml = opmlExporter.export(user);
|
||||
WireFeedOutput output = new WireFeedOutput();
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.commafeed.frontend.resource;
|
||||
|
||||
import io.dropwizard.hibernate.UnitOfWork;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@@ -19,14 +17,12 @@ import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import com.codahale.metrics.annotation.Timed;
|
||||
import com.commafeed.CommaFeedConfiguration;
|
||||
import com.commafeed.backend.dao.FeedDAO;
|
||||
import com.commafeed.backend.feed.FeedParser;
|
||||
@@ -35,9 +31,13 @@ import com.commafeed.backend.feed.FetchedFeed;
|
||||
import com.commafeed.backend.model.Feed;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import io.dropwizard.hibernate.UnitOfWork;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Path("/push")
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }) )
|
||||
@Singleton
|
||||
public class PubSubHubbubCallbackREST {
|
||||
|
||||
@@ -54,6 +54,7 @@ public class PubSubHubbubCallbackREST {
|
||||
@GET
|
||||
@UnitOfWork
|
||||
@Produces(MediaType.TEXT_PLAIN)
|
||||
@Timed
|
||||
public Response verify(@QueryParam("hub.mode") String mode, @QueryParam("hub.topic") String topic,
|
||||
@QueryParam("hub.challenge") String challenge, @QueryParam("hub.lease_seconds") String leaseSeconds,
|
||||
@QueryParam("hub.verify_token") String verifyToken) {
|
||||
@@ -85,6 +86,7 @@ public class PubSubHubbubCallbackREST {
|
||||
@POST
|
||||
@UnitOfWork
|
||||
@Consumes({ MediaType.APPLICATION_ATOM_XML, "application/rss+xml" })
|
||||
@Timed
|
||||
public Response callback() {
|
||||
|
||||
if (!config.getApplicationSettings().getPubsubhubbub()) {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.commafeed.frontend.resource;
|
||||
|
||||
import io.dropwizard.hibernate.UnitOfWork;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.ws.rs.Consumes;
|
||||
@@ -13,10 +11,9 @@ import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.codahale.metrics.annotation.Timed;
|
||||
import com.commafeed.CommaFeedConfiguration;
|
||||
import com.commafeed.backend.HttpGetter;
|
||||
import com.commafeed.backend.HttpGetter.HttpResult;
|
||||
@@ -24,14 +21,17 @@ import com.commafeed.backend.feed.FeedUtils;
|
||||
import com.commafeed.backend.model.User;
|
||||
import com.commafeed.frontend.auth.SecurityCheck;
|
||||
import com.commafeed.frontend.model.ServerInfo;
|
||||
import com.wordnik.swagger.annotations.Api;
|
||||
import com.wordnik.swagger.annotations.ApiOperation;
|
||||
|
||||
import io.dropwizard.hibernate.UnitOfWork;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Path("/server")
|
||||
@Api(value = "/server", description = "Operations about server infos")
|
||||
@Api(value = "/server")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }) )
|
||||
@Singleton
|
||||
public class ServerREST {
|
||||
|
||||
@@ -42,6 +42,7 @@ public class ServerREST {
|
||||
@GET
|
||||
@UnitOfWork
|
||||
@ApiOperation(value = "Get server infos", notes = "Get server infos", response = ServerInfo.class)
|
||||
@Timed
|
||||
public Response get() {
|
||||
ServerInfo infos = new ServerInfo();
|
||||
infos.setAnnouncement(config.getApplicationSettings().getAnnouncement());
|
||||
@@ -58,6 +59,7 @@ public class ServerREST {
|
||||
@UnitOfWork
|
||||
@ApiOperation(value = "proxy image")
|
||||
@Produces("image/png")
|
||||
@Timed
|
||||
public Response get(@SecurityCheck User user, @QueryParam("u") String url) {
|
||||
if (!config.getApplicationSettings().getImageProxyEnabled()) {
|
||||
return Response.status(Status.FORBIDDEN).build();
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
package com.commafeed.frontend.resource;
|
||||
|
||||
import io.dropwizard.hibernate.UnitOfWork;
|
||||
import io.dropwizard.jersey.validation.ValidationErrorMessage;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.Valid;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
@@ -24,15 +19,13 @@ import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
|
||||
import com.codahale.metrics.annotation.Timed;
|
||||
import com.commafeed.CommaFeedApplication;
|
||||
import com.commafeed.CommaFeedConfiguration;
|
||||
import com.commafeed.backend.dao.UserDAO;
|
||||
@@ -59,16 +52,21 @@ import com.commafeed.frontend.model.request.RegistrationRequest;
|
||||
import com.commafeed.frontend.session.SessionHelper;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.wordnik.swagger.annotations.Api;
|
||||
import com.wordnik.swagger.annotations.ApiOperation;
|
||||
import com.wordnik.swagger.annotations.ApiParam;
|
||||
|
||||
import io.dropwizard.hibernate.UnitOfWork;
|
||||
import io.dropwizard.jersey.validation.ValidationErrorMessage;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Path("/user")
|
||||
@Api(value = "/user", description = "Operations about the user")
|
||||
@Api(value = "/user")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }) )
|
||||
@Singleton
|
||||
public class UserREST {
|
||||
|
||||
@@ -84,6 +82,7 @@ public class UserREST {
|
||||
@GET
|
||||
@UnitOfWork
|
||||
@ApiOperation(value = "Retrieve user settings", notes = "Retrieve user settings", response = Settings.class)
|
||||
@Timed
|
||||
public Response getSettings(@SecurityCheck User user) {
|
||||
Settings s = new Settings();
|
||||
UserSettings settings = userSettingsDAO.findByUser(user);
|
||||
@@ -138,6 +137,7 @@ public class UserREST {
|
||||
@POST
|
||||
@UnitOfWork
|
||||
@ApiOperation(value = "Save user settings", notes = "Save user settings")
|
||||
@Timed
|
||||
public Response saveSettings(@SecurityCheck User user, @ApiParam(required = true) Settings settings) {
|
||||
Preconditions.checkNotNull(settings);
|
||||
|
||||
@@ -176,6 +176,7 @@ public class UserREST {
|
||||
@GET
|
||||
@UnitOfWork
|
||||
@ApiOperation(value = "Retrieve user's profile", response = UserModel.class)
|
||||
@Timed
|
||||
public Response get(@SecurityCheck User user) {
|
||||
UserModel userModel = new UserModel();
|
||||
userModel.setId(user.getId());
|
||||
@@ -195,6 +196,7 @@ public class UserREST {
|
||||
@POST
|
||||
@UnitOfWork
|
||||
@ApiOperation(value = "Save user's profile")
|
||||
@Timed
|
||||
public Response save(@SecurityCheck User user, @ApiParam(required = true) ProfileModificationRequest request) {
|
||||
Preconditions.checkArgument(StringUtils.isBlank(request.getPassword()) || request.getPassword().length() >= 6);
|
||||
if (StringUtils.isNotBlank(request.getEmail())) {
|
||||
@@ -223,6 +225,7 @@ public class UserREST {
|
||||
@POST
|
||||
@UnitOfWork
|
||||
@ApiOperation(value = "Register a new account")
|
||||
@Timed
|
||||
public Response register(@Valid @ApiParam(required = true) RegistrationRequest req, @Context SessionHelper sessionHelper) {
|
||||
try {
|
||||
User registeredUser = userService.register(req.getName(), req.getPassword(), req.getEmail(), Arrays.asList(Role.USER));
|
||||
@@ -230,12 +233,8 @@ public class UserREST {
|
||||
sessionHelper.setLoggedInUser(registeredUser);
|
||||
return Response.ok().build();
|
||||
} catch (final IllegalArgumentException e) {
|
||||
return Response.status(422).entity(new ValidationErrorMessage(Collections.<ConstraintViolation<?>> emptySet()) {
|
||||
@Override
|
||||
public ImmutableList<String> getErrors() {
|
||||
return ImmutableList.of(e.getMessage());
|
||||
}
|
||||
}).type(MediaType.TEXT_PLAIN).build();
|
||||
return Response.status(422).entity(new ValidationErrorMessage(ImmutableList.of(e.getMessage()))).type(MediaType.TEXT_PLAIN)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,6 +242,7 @@ public class UserREST {
|
||||
@POST
|
||||
@UnitOfWork
|
||||
@ApiOperation(value = "Login and create a session")
|
||||
@Timed
|
||||
public Response login(@ApiParam(required = true) LoginRequest req, @Context SessionHelper sessionHelper) {
|
||||
Optional<User> user = userService.login(req.getName(), req.getPassword());
|
||||
if (user.isPresent()) {
|
||||
@@ -257,6 +257,7 @@ public class UserREST {
|
||||
@POST
|
||||
@UnitOfWork
|
||||
@ApiOperation(value = "send a password reset email")
|
||||
@Timed
|
||||
public Response sendPasswordReset(@Valid PasswordResetRequest req) {
|
||||
User user = userDAO.findByEmail(req.getEmail());
|
||||
if (user == null) {
|
||||
@@ -278,9 +279,9 @@ public class UserREST {
|
||||
private String buildEmailContent(User user) throws Exception {
|
||||
String publicUrl = FeedUtils.removeTrailingSlash(config.getApplicationSettings().getPublicUrl());
|
||||
publicUrl += "/rest/user/passwordResetCallback";
|
||||
return String
|
||||
.format("You asked for password recovery for account '%s', <a href='%s'>follow this link</a> to change your password. Ignore this if you didn't request a password recovery.",
|
||||
user.getName(), callbackUrl(user, publicUrl));
|
||||
return String.format(
|
||||
"You asked for password recovery for account '%s', <a href='%s'>follow this link</a> to change your password. Ignore this if you didn't request a password recovery.",
|
||||
user.getName(), callbackUrl(user, publicUrl));
|
||||
}
|
||||
|
||||
private String callbackUrl(User user, String publicUrl) throws Exception {
|
||||
@@ -292,6 +293,7 @@ public class UserREST {
|
||||
@GET
|
||||
@UnitOfWork
|
||||
@Produces(MediaType.TEXT_HTML)
|
||||
@Timed
|
||||
public Response passwordRecoveryCallback(@QueryParam("email") String email, @QueryParam("token") String token) {
|
||||
Preconditions.checkNotNull(email);
|
||||
Preconditions.checkNotNull(token);
|
||||
@@ -327,6 +329,7 @@ public class UserREST {
|
||||
@POST
|
||||
@UnitOfWork
|
||||
@ApiOperation(value = "Delete the user account")
|
||||
@Timed
|
||||
public Response delete(@SecurityCheck User user) {
|
||||
if (CommaFeedApplication.USERNAME_ADMIN.equals(user.getName()) || CommaFeedApplication.USERNAME_DEMO.equals(user.getName())) {
|
||||
return Response.status(Status.FORBIDDEN).build();
|
||||
|
||||
@@ -10,8 +10,6 @@ import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import com.commafeed.backend.dao.UnitOfWork;
|
||||
@@ -20,8 +18,10 @@ import com.commafeed.backend.model.User;
|
||||
import com.commafeed.backend.model.UserSettings;
|
||||
import com.commafeed.frontend.session.SessionHelper;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }) )
|
||||
@Singleton
|
||||
public class CustomCssServlet extends HttpServlet {
|
||||
|
||||
@@ -37,7 +37,7 @@ public class CustomCssServlet extends HttpServlet {
|
||||
return;
|
||||
}
|
||||
|
||||
UserSettings settings = UnitOfWork.run(sessionFactory, () -> userSettingsDAO.findByUser(user.get()));
|
||||
UserSettings settings = UnitOfWork.call(sessionFactory, () -> userSettingsDAO.findByUser(user.get()));
|
||||
if (settings == null || settings.getCustomCss() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -11,8 +11,6 @@ import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
@@ -31,8 +29,10 @@ import com.commafeed.frontend.resource.CategoryREST;
|
||||
import com.commafeed.frontend.session.SessionHelper;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }))
|
||||
@RequiredArgsConstructor(onConstructor = @__({ @Inject }) )
|
||||
@Singleton
|
||||
public class NextUnreadServlet extends HttpServlet {
|
||||
|
||||
@@ -63,31 +63,29 @@ public class NextUnreadServlet extends HttpServlet {
|
||||
|
||||
final ReadingOrder order = StringUtils.equals(orderParam, "asc") ? ReadingOrder.asc : ReadingOrder.desc;
|
||||
|
||||
FeedEntryStatus status = UnitOfWork.run(
|
||||
sessionFactory,
|
||||
() -> {
|
||||
FeedEntryStatus s = null;
|
||||
if (StringUtils.isBlank(categoryId) || CategoryREST.ALL.equals(categoryId)) {
|
||||
List<FeedSubscription> subs = feedSubscriptionDAO.findAll(user.get());
|
||||
List<FeedEntryStatus> statuses = feedEntryStatusDAO.findBySubscriptions(user.get(), subs, true, null, null, 0, 1,
|
||||
order, true, false, null);
|
||||
s = Iterables.getFirst(statuses, null);
|
||||
} else {
|
||||
FeedCategory category = feedCategoryDAO.findById(user.get(), Long.valueOf(categoryId));
|
||||
if (category != null) {
|
||||
List<FeedCategory> children = feedCategoryDAO.findAllChildrenCategories(user.get(), category);
|
||||
List<FeedSubscription> subscriptions = feedSubscriptionDAO.findByCategories(user.get(), children);
|
||||
List<FeedEntryStatus> statuses = feedEntryStatusDAO.findBySubscriptions(user.get(), subscriptions, true, null,
|
||||
null, 0, 1, order, true, false, null);
|
||||
s = Iterables.getFirst(statuses, null);
|
||||
}
|
||||
}
|
||||
if (s != null) {
|
||||
s.setRead(true);
|
||||
feedEntryStatusDAO.saveOrUpdate(s);
|
||||
}
|
||||
return s;
|
||||
});
|
||||
FeedEntryStatus status = UnitOfWork.call(sessionFactory, () -> {
|
||||
FeedEntryStatus s = null;
|
||||
if (StringUtils.isBlank(categoryId) || CategoryREST.ALL.equals(categoryId)) {
|
||||
List<FeedSubscription> subs = feedSubscriptionDAO.findAll(user.get());
|
||||
List<FeedEntryStatus> statuses = feedEntryStatusDAO.findBySubscriptions(user.get(), subs, true, null, null, 0, 1, order,
|
||||
true, false, null);
|
||||
s = Iterables.getFirst(statuses, null);
|
||||
} else {
|
||||
FeedCategory category = feedCategoryDAO.findById(user.get(), Long.valueOf(categoryId));
|
||||
if (category != null) {
|
||||
List<FeedCategory> children = feedCategoryDAO.findAllChildrenCategories(user.get(), category);
|
||||
List<FeedSubscription> subscriptions = feedSubscriptionDAO.findByCategories(user.get(), children);
|
||||
List<FeedEntryStatus> statuses = feedEntryStatusDAO.findBySubscriptions(user.get(), subscriptions, true, null, null, 0,
|
||||
1, order, true, false, null);
|
||||
s = Iterables.getFirst(statuses, null);
|
||||
}
|
||||
}
|
||||
if (s != null) {
|
||||
s.setRead(true);
|
||||
feedEntryStatusDAO.saveOrUpdate(s);
|
||||
}
|
||||
return s;
|
||||
});
|
||||
|
||||
if (status == null) {
|
||||
resp.sendRedirect(resp.encodeRedirectURL(config.getApplicationSettings().getPublicUrl()));
|
||||
|
||||
Reference in New Issue
Block a user