mirror of https://github.com/bvn13/VoidForum.git
initial commit with existing sources
parent
38cfe9dfca
commit
10502673ad
|
@ -1,22 +1,25 @@
|
|||
# Compiled class file
|
||||
*.class
|
||||
.gradle
|
||||
/build/
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Log file
|
||||
*.log
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
|
||||
# BlueJ files
|
||||
*.ctxt
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
### NetBeans ###
|
||||
nbproject/private/
|
||||
build/
|
||||
nbbuild/
|
||||
dist/
|
||||
nbdist/
|
||||
.nb-gradle/
|
|
@ -0,0 +1,132 @@
|
|||
buildscript {
|
||||
ext {
|
||||
springBootVersion = '1.5.10.BUILD-SNAPSHOT'
|
||||
redisEmbeddedVersion = "0.6"
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
maven { url "https://repo.spring.io/snapshot" }
|
||||
maven { url "https://repo.spring.io/milestone" }
|
||||
}
|
||||
dependencies {
|
||||
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.10.BUILD-SNAPSHOT")
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'idea'
|
||||
apply plugin: 'org.springframework.boot'
|
||||
|
||||
group = 'ru.bvn13'
|
||||
version = '0.0.1-SNAPSHOT'
|
||||
|
||||
sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
maven { url "https://repo.spring.io/snapshot" }
|
||||
maven { url "https://repo.spring.io/milestone" }
|
||||
|
||||
maven { url 'https://repo.spring.io/libs-release' }
|
||||
maven { url "https://repo.springsource.org/repo" }
|
||||
}
|
||||
|
||||
|
||||
bootRun {
|
||||
systemProperties = System.properties
|
||||
}
|
||||
|
||||
configurations {
|
||||
compile.exclude module: "spring-boot-starter-tomcat"
|
||||
all*.exclude module: 'spring-boot-starter-logging'
|
||||
}
|
||||
|
||||
|
||||
dependencies {
|
||||
|
||||
// --- spring boot ---
|
||||
//compile('org.springframework.boot:spring-boot-starter-cache')
|
||||
compile('org.springframework.boot:spring-boot-starter-data-jpa:1.5.10.BUILD-SNAPSHOT')
|
||||
compile('org.springframework.boot:spring-boot-starter-security:1.5.10.BUILD-SNAPSHOT')
|
||||
compile('org.springframework.session:spring-session:1.3.1.RELEASE')
|
||||
compile('org.springframework.boot:spring-boot-starter-validation:1.5.10.BUILD-SNAPSHOT')
|
||||
compile('org.springframework.boot:spring-boot-starter-web:1.5.10.BUILD-SNAPSHOT')
|
||||
compile('org.springframework.boot:spring-boot-starter-jetty:1.5.10.BUILD-SNAPSHOT')
|
||||
compile('org.springframework.boot:spring-boot-starter-thymeleaf:1.5.10.BUILD-SNAPSHOT')
|
||||
compile('com.domingosuarez.boot:spring-boot-starter-jade4j:0.3.2')
|
||||
compile "org.springframework.boot:spring-boot-starter-data-redis:1.5.10.BUILD-SNAPSHOT",
|
||||
"com.github.kstyrc:embedded-redis:$redisEmbeddedVersion"
|
||||
compile(group: 'org.springframework.boot', name: 'spring-boot-starter') {
|
||||
exclude(module: 'spring-boot-starter-logging')
|
||||
}
|
||||
compile('org.springframework.boot:spring-boot-starter-log4j:1.3.7.RELEASE')
|
||||
|
||||
// --- spring ---
|
||||
compile('org.springframework:spring-context:4.3.13.RELEASE')
|
||||
compile('org.springframework:spring-webmvc:4.3.13.RELEASE')
|
||||
compile('org.springframework.security:spring-security-config:4.2.3.RELEASE')
|
||||
compile('org.springframework.security:spring-security-web:4.2.3.RELEASE')
|
||||
|
||||
// --- spring data ---
|
||||
compile('org.springframework.data:spring-data-jpa:1.11.9.RELEASE')
|
||||
|
||||
// --- persistence ---
|
||||
compile('com.zaxxer:HikariCP:2.5.1')
|
||||
compile('org.springframework:spring-orm:4.3.13.RELEASE')
|
||||
compile('org.hibernate:hibernate-entitymanager:5.0.12.Final')
|
||||
compile('javax.el:javax.el-api:+')
|
||||
compile('org.hsqldb:hsqldb:2.3.5')
|
||||
|
||||
// --- view ---
|
||||
compile('de.neuland-bfi:spring-jade4j:1.2.7')
|
||||
|
||||
//markdown processor
|
||||
compile 'com.vladsch.flexmark:flexmark-all:0.28.8'
|
||||
|
||||
// --- cache ---
|
||||
compile('org.springframework.data:spring-data-redis:1.8.9.RELEASE')
|
||||
compile('redis.clients:jedis:2.9.0')
|
||||
|
||||
// --- PostgreSQL ---
|
||||
runtime('org.postgresql:postgresql')
|
||||
|
||||
// --- Validation ---
|
||||
compile 'org.hibernate:hibernate-validator:6.0.5.Final'
|
||||
//compile 'org.hibernate.validator:hibernate-validator:6.0.5.Final'
|
||||
//compile 'org.hibernate.validator:hibernate-validator-annotation-processor:6.0.5.Final'
|
||||
compile 'javax.validation:validation-api:2.0.0.Final'
|
||||
|
||||
// Logging
|
||||
compile('ch.qos.logback:logback-classic')
|
||||
compile('org.slf4j:slf4j-api')
|
||||
compile('org.apache.commons:commons-lang3')
|
||||
|
||||
// @Inject
|
||||
compile('javax.inject:javax.inject:+')
|
||||
|
||||
// JSON
|
||||
compile('com.fasterxml.jackson.core:jackson-databind')
|
||||
compile('com.fasterxml.jackson.core:jackson-annotations')
|
||||
|
||||
// Utilities
|
||||
compile('com.google.guava:guava:23.0')
|
||||
compile('org.modelmapper:modelmapper:1.1.1')
|
||||
compile('org.projectlombok:lombok:1.16.18')
|
||||
|
||||
|
||||
// static resources, ref. http://www.webjars.org/
|
||||
compile('org.webjars:jquery:3.2.1')
|
||||
compile('org.webjars:bootstrap:3.3.7-1')
|
||||
compile('org.webjars:font-awesome:4.7.0')
|
||||
compile('org.webjars:ace:1.2.8')
|
||||
|
||||
|
||||
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
testCompile('org.springframework.boot:spring-boot-starter-test')
|
||||
testCompile('org.springframework.security:spring-security-test')
|
||||
}
|
||||
|
Binary file not shown.
|
@ -0,0 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-3.5.1-bin.zip
|
|
@ -0,0 +1,172 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
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
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
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
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save ( ) {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
|
@ -0,0 +1,84 @@
|
|||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
|
@ -0,0 +1,54 @@
|
|||
package ru.bvn13.voidforum;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import redis.embedded.Redis;
|
||||
import redis.embedded.RedisServer;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
/**
|
||||
* @author bvn13 <mail4bvn@gmail.com>
|
||||
*/
|
||||
|
||||
@SpringBootApplication
|
||||
public class Application {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(Application.class);
|
||||
|
||||
@Autowired
|
||||
@Qualifier("RedisServer")
|
||||
private Redis redisServer;
|
||||
|
||||
|
||||
@PostConstruct
|
||||
public void start() {
|
||||
logger.info("starting redis...");
|
||||
if (!redisServer.isActive()) {
|
||||
redisServer.start();
|
||||
}
|
||||
if (redisServer.isActive()) {
|
||||
logger.info("redis listen ports: {}", redisServer.ports().stream().map(Object::toString).collect(joining(",")));
|
||||
}
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void stop() {
|
||||
|
||||
logger.info("shutting down redis...");
|
||||
redisServer.stop();
|
||||
logger.info("bye!");
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package ru.bvn13.voidforum;
|
||||
|
||||
/**
|
||||
* @author: bvn13 <mail4bvn@gmail.com>
|
||||
*/
|
||||
public final class Constants {
|
||||
|
||||
public static final String ENV_PRODUCTION = "production";
|
||||
|
||||
public static final String ENV_DEVELOPMENT = "development";
|
||||
|
||||
public static final String DEFAULT_ADMIN_NICKNAME = "admin";
|
||||
|
||||
public static final String DEFAULT_ADMIN_EMAIL = "admin@admin.com";
|
||||
|
||||
public static final String DEFAULT_ADMIN_PASSWORD = "admin";
|
||||
|
||||
public static final String ABOUT_PAGE_PERMALINK = "about";
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
package ru.bvn13.voidforum;
|
||||
|
||||
import com.zaxxer.hikari.HikariConfig;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.jpa.HibernateEntityManagerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.orm.jpa.vendor.HibernateJpaSessionFactoryBean;
|
||||
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* @author bvn13 <mail4bvn@gmail.com>
|
||||
*/
|
||||
|
||||
@Configuration
|
||||
@EnableTransactionManagement
|
||||
@EnableJpaRepositories(basePackageClasses = Application.class)
|
||||
class JpaConfig implements TransactionManagementConfigurer {
|
||||
|
||||
@Value("${spring.dataSource.driverClassName}")
|
||||
private String driver;
|
||||
@Value("${spring.dataSource.url}")
|
||||
private String url;
|
||||
@Value("${spring.dataSource.username}")
|
||||
private String username;
|
||||
@Value("${spring.dataSource.password}")
|
||||
private String password;
|
||||
@Value("${spring.hibernate.dialect}")
|
||||
private String dialect;
|
||||
@Value("${spring.hibernate.hbm2ddl.auto}")
|
||||
private String hbm2ddlAuto;
|
||||
@Value("${spring.hibernate.show_sql}")
|
||||
private Boolean showSql;
|
||||
|
||||
@Bean
|
||||
public DataSource configureDataSource() {
|
||||
HikariConfig config = new HikariConfig();
|
||||
config.setDriverClassName(driver);
|
||||
config.setJdbcUrl(url);
|
||||
config.setUsername(username);
|
||||
config.setPassword(password);
|
||||
|
||||
config.addDataSourceProperty("useUnicode", "true");
|
||||
config.addDataSourceProperty("characterEncoding", "utf8");
|
||||
config.addDataSourceProperty("cachePrepStmts", "true");
|
||||
config.addDataSourceProperty("prepStmtCacheSize", "250");
|
||||
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
|
||||
config.addDataSourceProperty("useServerPrepStmts", "true");
|
||||
|
||||
return new HikariDataSource(config);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
|
||||
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
|
||||
entityManagerFactoryBean.setDataSource(configureDataSource());
|
||||
entityManagerFactoryBean.setPackagesToScan("ru.bvn13.voidforum");
|
||||
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
|
||||
|
||||
Properties jpaProperties = new Properties();
|
||||
jpaProperties.put(org.hibernate.cfg.Environment.DIALECT, dialect);
|
||||
jpaProperties.put(org.hibernate.cfg.Environment.HBM2DDL_AUTO, hbm2ddlAuto);
|
||||
jpaProperties.put(org.hibernate.cfg.Environment.SHOW_SQL, showSql);
|
||||
entityManagerFactoryBean.setJpaProperties(jpaProperties);
|
||||
|
||||
return entityManagerFactoryBean;
|
||||
}
|
||||
|
||||
@Bean(name = "transactionManager")
|
||||
public PlatformTransactionManager annotationDrivenTransactionManager() {
|
||||
return new JpaTransactionManager();
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@Autowired
|
||||
private EntityManagerFactory entityManagerFactory;
|
||||
|
||||
@Bean
|
||||
public SessionFactory getSessionFactory() {
|
||||
if (entityManagerFactory.unwrap(SessionFactory.class) == null) {
|
||||
throw new NullPointerException("factory is not a hibernate factory");
|
||||
}
|
||||
return entityManagerFactory.unwrap(SessionFactory.class);
|
||||
}*/
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package ru.bvn13.voidforum;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import redis.embedded.Redis;
|
||||
import redis.embedded.RedisServer;
|
||||
import redis.embedded.exceptions.EmbeddedRedisException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
public class RedisConfig {
|
||||
|
||||
public static class RedisDummy implements Redis {
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() throws EmbeddedRedisException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws EmbeddedRedisException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Integer> ports() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Value("${spring.redis.port}")
|
||||
private int port;
|
||||
|
||||
@Value("${spring.redis.embedded}")
|
||||
private Boolean useEmbeddedRedis;
|
||||
|
||||
|
||||
|
||||
|
||||
@Bean(name = "RedisServer")
|
||||
public Redis redisServer() {
|
||||
if (!this.useEmbeddedRedis) {
|
||||
return new RedisDummy();
|
||||
}
|
||||
RedisServer.builder().reset();
|
||||
|
||||
return RedisServer.builder()
|
||||
.port(this.port)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package ru.bvn13.voidforum;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.crypto.password.StandardPasswordEncoder;
|
||||
import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices;
|
||||
import ru.bvn13.voidforum.services.PrivilegeService;
|
||||
import ru.bvn13.voidforum.services.UserService;
|
||||
|
||||
/**
|
||||
* @author bvn13 <mail4bvn@gmail.com>
|
||||
*/
|
||||
|
||||
@Configuration
|
||||
public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Bean
|
||||
public UserService userService() {
|
||||
return new UserService();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TokenBasedRememberMeServices rememberMeServices() {
|
||||
return new TokenBasedRememberMeServices("remember-me-key", userService());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new StandardPasswordEncoder();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.eraseCredentials(true)
|
||||
.userDetailsService(userService())
|
||||
.passwordEncoder(passwordEncoder());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.antMatchers("/admin/**").hasAnyAuthority(PrivilegeService.PRIVILEGE_ADMIN, PrivilegeService.PRIVILEGE_OWNER)
|
||||
.antMatchers("/account/**").hasAnyAuthority(PrivilegeService.PRIVILEGE_WRITE, PrivilegeService.PRIVILEGE_ADMIN, PrivilegeService.PRIVILEGE_OWNER)
|
||||
.anyRequest().permitAll()
|
||||
.and()
|
||||
.formLogin()
|
||||
.loginPage("/signin")
|
||||
.permitAll()
|
||||
.failureUrl("/signin?error=1")
|
||||
.loginProcessingUrl("/authenticate")
|
||||
.and()
|
||||
.logout()
|
||||
.logoutUrl("/logout")
|
||||
.permitAll()
|
||||
.logoutSuccessUrl("/signin?logout")
|
||||
.and()
|
||||
.rememberMe()
|
||||
.rememberMeServices(rememberMeServices())
|
||||
.key("remember-me-key");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package ru.bvn13.voidforum;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.security.web.csrf.CsrfToken;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
||||
import ru.bvn13.voidforum.support.web.ViewHelperVF;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import static ru.bvn13.voidforum.Constants.*;
|
||||
|
||||
/**
|
||||
* @author bvn13 <mail4bvn@gmail.com>.
|
||||
*/
|
||||
@Configuration
|
||||
public class WebConfig extends WebMvcConfigurerAdapter {
|
||||
@Autowired
|
||||
private ViewHelperVF viewHelper;
|
||||
|
||||
@Autowired
|
||||
private Environment env;
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(viewObjectAddingInterceptor());
|
||||
super.addInterceptors(registry);
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void registerJadeViewHelpers(){
|
||||
viewHelper.setApplicationEnv(this.getApplicationEnv());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HandlerInterceptor viewObjectAddingInterceptor() {
|
||||
return new HandlerInterceptorAdapter() {
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
viewHelper.setStartTime(System.currentTimeMillis());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView view) {
|
||||
CsrfToken token = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
|
||||
if (token != null) {
|
||||
view.addObject(token.getParameterName(), token);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public String getApplicationEnv(){
|
||||
return this.env.acceptsProfiles(ENV_PRODUCTION) ? ENV_PRODUCTION : ENV_DEVELOPMENT;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package ru.bvn13.voidforum.controllers;
|
||||
|
||||
import ru.bvn13.voidforum.Constants;
|
||||
import ru.bvn13.voidforum.error.NotFoundException;
|
||||
import ru.bvn13.voidforum.models.Post;
|
||||
import ru.bvn13.voidforum.services.AppSetting;
|
||||
import ru.bvn13.voidforum.services.PostService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import ru.bvn13.voidforum.services.PrivilegeService;
|
||||
import ru.bvn13.voidforum.services.UserService;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.GET;
|
||||
|
||||
@Controller
|
||||
public class HomeController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
|
||||
|
||||
@Autowired
|
||||
private PostService postService;
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Autowired
|
||||
private AppSetting appSetting;
|
||||
|
||||
@RequestMapping(value = "", method = GET)
|
||||
public String index(@RequestParam(defaultValue = "1") int page, Model model, HttpServletRequest request) {
|
||||
//request.isUserInRole("READ_PRIVILEGE");
|
||||
page = page < 1 ? 0 : page - 1;
|
||||
Page<Post> posts = null;
|
||||
if (userService.currentUserHasPrivilege(PrivilegeService.PRIVILEGE_WRITE)) {
|
||||
if (userService.currentUserHasPrivilege(PrivilegeService.PRIVILEGE_ADMIN)) {
|
||||
posts = postService.getAllPublishedPostsByPage(page, appSetting.getPageSize());
|
||||
} else {
|
||||
posts = postService.getAllPublishedNotDeletedPostsByPage(page, appSetting.getPageSize());
|
||||
}
|
||||
} else {
|
||||
posts = postService.getAllPublishedNotCensoredNotDeletedPostsByPage(page, appSetting.getPageSize());
|
||||
}
|
||||
|
||||
model.addAttribute("totalPages", posts.getTotalPages());
|
||||
model.addAttribute("posts", posts);
|
||||
model.addAttribute("page", page + 1);
|
||||
|
||||
return "home/index";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "about", method = GET)
|
||||
public String about(Model model) {
|
||||
|
||||
/*Post post = null;
|
||||
try {
|
||||
post = postService.getPublishedPostByPermalink(Constants.ABOUT_PAGE_PERMALINK);
|
||||
} catch (NotFoundException nfe) {
|
||||
logger.debug("Get post with permalink " + Constants.ABOUT_PAGE_PERMALINK);
|
||||
post = postService.createAboutPage();
|
||||
}
|
||||
|
||||
if (post == null) {
|
||||
throw new NotFoundException("Post with permalink " + Constants.ABOUT_PAGE_PERMALINK + " is not found");
|
||||
}
|
||||
*/
|
||||
|
||||
Post post = null;
|
||||
try {
|
||||
post = postService.getPublishedPostByPermalink(Constants.ABOUT_PAGE_PERMALINK);
|
||||
} catch (NotFoundException nfe) {
|
||||
logger.debug("Get post with permalink " + Constants.ABOUT_PAGE_PERMALINK);
|
||||
throw new NotFoundException("Post with permalink " + Constants.ABOUT_PAGE_PERMALINK + " is not found");
|
||||
}
|
||||
|
||||
model.addAttribute("about", post);
|
||||
return "home/about";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package ru.bvn13.voidforum.controllers;
|
||||
|
||||
import ru.bvn13.voidforum.forms.CommentForm;
|
||||
import ru.bvn13.voidforum.models.Post;
|
||||
import ru.bvn13.voidforum.models.SeoPostData;
|
||||
import ru.bvn13.voidforum.services.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.*;
|
||||
|
||||
|
||||
/**
|
||||
* bvn13 <mail4bvn@gmail.com>
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("posts")
|
||||
public class PostController {
|
||||
|
||||
Logger logger = LoggerFactory.getLogger(PostController.class);
|
||||
|
||||
@Autowired
|
||||
private PostService postService;
|
||||
|
||||
@Autowired
|
||||
private VisitService visitService;
|
||||
|
||||
@Autowired
|
||||
private LikeService likeService;
|
||||
|
||||
@Autowired
|
||||
private CommentService commentService;
|
||||
|
||||
@Autowired
|
||||
private RequestProcessorService requestProcessorService;
|
||||
|
||||
|
||||
@RequestMapping(value = "archive", method = GET)
|
||||
public String archive(Model model){
|
||||
model.addAttribute("posts", postService.getArchivePosts());
|
||||
|
||||
return "posts/archive";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "{permalink}", method = GET)
|
||||
public String show(@PathVariable String permalink, Model model, HttpServletRequest request){
|
||||
Post post = this.postService.findPostByPermalink(permalink);
|
||||
|
||||
logger.debug(String.format("ACCESS %s from IP: %s", permalink, this.requestProcessorService.getRealIp(request)));
|
||||
|
||||
this.visitService.saveVisit(post, this.requestProcessorService.getRealIp(request), this.requestProcessorService.getUserAgent(request));
|
||||
post.setVisitsCount(this.visitService.getUniqueVisitsCount(post));
|
||||
post.setSympathyCount(this.likeService.getTotalLikesByPost(post));
|
||||
|
||||
SeoPostData seoData = null;
|
||||
if (post.getSeoData() == null) {
|
||||
seoData = new SeoPostData();
|
||||
seoData.setPost(post);
|
||||
} else {
|
||||
seoData = post.getSeoData();
|
||||
}
|
||||
|
||||
model.addAttribute("post", post);
|
||||
model.addAttribute("tags", this.postService.getPostTags(post));
|
||||
model.addAttribute("seoKeywords", this.postService.getSeoKeywordsAsString(post));
|
||||
model.addAttribute("seoDescription", post.getSeoDescription());
|
||||
model.addAttribute("seoData", seoData);
|
||||
|
||||
model.addAttribute("comments", commentService.getCommentsForPost(post));
|
||||
model.addAttribute("commentForm", new CommentForm());
|
||||
model.addAttribute("commentFormats", commentService.getAvailableCommentFormats());
|
||||
|
||||
return "posts/show";
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package ru.bvn13.voidforum.controllers;
|
||||
|
||||
import ru.bvn13.voidforum.models.StoredFile;
|
||||
import ru.bvn13.voidforum.services.FileStorageService;
|
||||
import ru.bvn13.voidforum.services.UserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM;
|
||||
import static org.springframework.util.MimeTypeUtils.APPLICATION_OCTET_STREAM_VALUE;
|
||||
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/files")
|
||||
public class StoredFileController {
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Autowired
|
||||
private FileStorageService storageService;
|
||||
|
||||
@GetMapping(value = "/{fileName:.+}", produces = APPLICATION_OCTET_STREAM_VALUE)
|
||||
@ExceptionHandler(value = FileNotFoundException.class)
|
||||
public @ResponseBody
|
||||
HttpEntity<byte[]> getFileById(@PathVariable String fileName, final HttpServletResponse response) throws IOException {
|
||||
|
||||
StoredFile file = this.storageService.getFileByName(fileName);
|
||||
if (file == null) {
|
||||
response.sendError(404, String.format("File %s not found", fileName));
|
||||
return null;
|
||||
}
|
||||
byte[] content;
|
||||
try {
|
||||
content = this.storageService.getFileContent(file.getPath());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
if (this.userService.isCurrentUserAdmin()) {
|
||||
response.sendError(404, String.format("File %s (%s) not found", file.getName(), file.getPath()));
|
||||
} else {
|
||||
response.sendError(404, String.format("File %s not found", file.getName()));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
HttpHeaders header = new HttpHeaders();
|
||||
header.setContentType(APPLICATION_OCTET_STREAM);
|
||||
header.set("Content-Disposition", "inline; filename=" + file.getName());
|
||||
header.setContentLength(file.getSize());
|
||||
|
||||
return new HttpEntity<byte[]>(content, header);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
package ru.bvn13.voidforum.controllers;
|
||||
|
||||
import ru.bvn13.voidforum.forms.LikeForm;
|
||||
import ru.bvn13.voidforum.models.Post;
|
||||
import ru.bvn13.voidforum.services.*;
|
||||
import ru.bvn13.voidforum.support.web.ViewHelperVF;
|
||||
import lombok.Data;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Controller
|
||||
@RequestMapping(value = "/sympathy")
|
||||
public class SympathyController {
|
||||
|
||||
@Autowired
|
||||
private AppSetting appSetting;
|
||||
|
||||
@Autowired
|
||||
private PostService postService;
|
||||
|
||||
@Autowired
|
||||
private LikeService likeService;
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Autowired
|
||||
private RequestProcessorService requestProcessorService;
|
||||
|
||||
|
||||
@Data
|
||||
public static class SympathyRequestData {
|
||||
@NotNull
|
||||
private String postId;
|
||||
}
|
||||
|
||||
|
||||
@PostMapping(value = "/like")
|
||||
public @ResponseBody
|
||||
LikeForm likeIt(@RequestBody SympathyRequestData data, HttpServletRequest request) {
|
||||
Post post = this.postService.findPostByPermalink(data.getPostId());
|
||||
this.likeService.likePost(post, this.requestProcessorService.getRealIp(request));
|
||||
ViewHelperVF viewHelper = new ViewHelperVF(this.appSetting);
|
||||
LikeForm result = new LikeForm();
|
||||
result.setSympathy(viewHelper.formatNumberByThousands(this.likeService.getTotalLikesByPost(post)));
|
||||
return result;
|
||||
}
|
||||
|
||||
@PostMapping(value = "/dislike")
|
||||
public @ResponseBody
|
||||
LikeForm dislikeIt(@RequestBody SympathyRequestData data, HttpServletRequest request) {
|
||||
Post post = this.postService.findPostByPermalink(data.getPostId());
|
||||
this.likeService.dislikePost(post, this.requestProcessorService.getRealIp(request));
|
||||
ViewHelperVF viewHelper = new ViewHelperVF(this.appSetting);
|
||||
LikeForm result = new LikeForm();
|
||||
result.setSympathy(viewHelper.formatNumberByThousands(this.likeService.getTotalLikesByPost(post)));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package ru.bvn13.voidforum.controllers;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import ru.bvn13.voidforum.error.NotFoundException;
|
||||
import ru.bvn13.voidforum.models.Post;
|
||||
import ru.bvn13.voidforum.models.Tag;
|
||||
import ru.bvn13.voidforum.services.AppSetting;
|
||||
import ru.bvn13.voidforum.services.PostService;
|
||||
import ru.bvn13.voidforum.services.TagService;
|
||||
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.GET;
|
||||
|
||||
/**
|
||||
* bvn13 <mail4bvn@gmail.com>.
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("tags")
|
||||
public class TagController {
|
||||
@Autowired
|
||||
private TagService tagService;
|
||||
|
||||
@Autowired
|
||||
private PostService postService;
|
||||
|
||||
@Autowired
|
||||
private AppSetting appSetting;
|
||||
|
||||
@RequestMapping(value = "", method = GET)
|
||||
public String index(Model model){
|
||||
model.addAttribute("tags", postService.countPostsByTags());
|
||||
return "tags/index";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "{tagName}", method = GET)
|
||||
public String showTag(@PathVariable String tagName, @RequestParam(defaultValue = "1") int page, Model model) {
|
||||
Tag tag = tagService.getTag(tagName);
|
||||
|
||||
if (tag == null) {
|
||||
throw new NotFoundException("Tag " + tagName + " is not found.");
|
||||
}
|
||||
|
||||
page = page < 1 ? 0 : page - 1;
|
||||
Page<Post> posts = postService.findPostsByTag(tagName, page, appSetting.getPageSize());
|
||||
|
||||
model.addAttribute("tag", tag);
|
||||
model.addAttribute("posts", posts);
|
||||
model.addAttribute("page", page + 1);
|
||||
model.addAttribute("totalPages", posts.getTotalPages());
|
||||
|
||||
return "tags/show";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package ru.bvn13.voidforum.controllers;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
/**
|
||||
* Created by bvn13 on 09.12.2017.
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("tests")
|
||||
public class TestController {
|
||||
|
||||
@GetMapping(value = "/1")
|
||||
public String test1(Model model) {
|
||||
|
||||
|
||||
return "tests/1";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
package ru.bvn13.voidforum.controllers;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
import ru.bvn13.voidforum.error.EmailExistsException;
|
||||
import ru.bvn13.voidforum.error.NicknameExistsException;
|
||||
import ru.bvn13.voidforum.forms.RegistrationForm;
|
||||
import ru.bvn13.voidforum.models.User;
|
||||
import ru.bvn13.voidforum.services.UserService;
|
||||
import ru.bvn13.voidforum.utils.DTOUtil;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.validation.Valid;
|
||||
import java.security.Principal;
|
||||
|
||||
/**
|
||||
* bvn13 <mail4bvn@gmail.com>
|
||||
*/
|
||||
@Controller(value = "/")
|
||||
public class UserController {
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
|
||||
@RequestMapping(value = "signin", method = RequestMethod.GET)
|
||||
public String signin(Principal principal, RedirectAttributes ra) {
|
||||
return principal == null ? "users/signin" : "redirect:/";
|
||||
}
|
||||
|
||||
|
||||
@GetMapping(value = "register")
|
||||
public String registrationForm(Model model) {
|
||||
model.addAttribute("form", new RegistrationForm());
|
||||
return "users/register";
|
||||
}
|
||||
|
||||
|
||||
@PostMapping(value = "register")
|
||||
public String register(@Valid RegistrationForm registrationForm, Errors errors, Model model, RedirectAttributes ra) {
|
||||
if (!registrationForm.getPassword().equals(registrationForm.getPasswordCheck())) {
|
||||
ra.addFlashAttribute("error", "Verify your password!");
|
||||
return "redirect:/register";
|
||||
}
|
||||
|
||||
if (registrationForm.getUsername().isEmpty()
|
||||
|| registrationForm.getNickname().isEmpty()
|
||||
|| registrationForm.getPassword().isEmpty()
|
||||
|| registrationForm.getPasswordCheck().isEmpty()) {
|
||||
ra.addFlashAttribute("error", "Not all necessary fields are specified");
|
||||
return "redirect:/register";
|
||||
}
|
||||
|
||||
User user = new User();
|
||||
user.setEmail(registrationForm.getUsername());
|
||||
user.setNickname(registrationForm.getNickname());
|
||||
user.setPassword(registrationForm.getPassword());
|
||||
//DTOUtil.mapTo(registrationForm, user);
|
||||
|
||||
try {
|
||||
userService.registerNewUserAccount(user);
|
||||
} catch (EmailExistsException e) {
|
||||
e.printStackTrace();
|
||||
ra.addFlashAttribute("error", "There is an account with specified email and nickname");
|
||||
return "redirect:/register";
|
||||
} catch (NicknameExistsException e) {
|
||||
e.printStackTrace();
|
||||
ra.addFlashAttribute("error", "There is an account with specified email and nickname");
|
||||
return "redirect:/register";
|
||||
}
|
||||
|
||||
return "redirect:/signin";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package ru.bvn13.voidforum.controllers.account;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
/**
|
||||
* Created by bvn13 on 08.12.2017.
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping(value = "/account")
|
||||
public class AccountController {
|
||||
|
||||
@GetMapping(value = "")
|
||||
public String getAccountIndex(Model model) {
|
||||
|
||||
return "account/home/index";
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package ru.bvn13.voidforum.controllers.account;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.POST;
|
||||
|
||||
/**
|
||||
* Created by bvn13 on 08.12.2017.
|
||||
*/
|
||||
@Controller("accountCommentController")
|
||||
@RequestMapping("/account/comments")
|
||||
public class CommentController {
|
||||
|
||||
|
||||
@RequestMapping(value = "", method = POST)
|
||||
public String addComment(Model model) {
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,193 @@
|
|||
package ru.bvn13.voidforum.controllers.account;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.FieldError;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import ru.bvn13.voidforum.forms.PostForm;
|
||||
import ru.bvn13.voidforum.models.Post;
|
||||
import ru.bvn13.voidforum.models.User;
|
||||
import ru.bvn13.voidforum.models.support.*;
|
||||
import ru.bvn13.voidforum.repositories.PostRepository;
|
||||
import ru.bvn13.voidforum.repositories.UserRepository;
|
||||
import ru.bvn13.voidforum.services.PostService;
|
||||
import ru.bvn13.voidforum.services.PrivilegeService;
|
||||
import ru.bvn13.voidforum.services.UserService;
|
||||
import ru.bvn13.voidforum.utils.DTOUtil;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.security.Principal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.DELETE;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.POST;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.PUT;
|
||||
|
||||
/**
|
||||
* Created by bvn13 on 07.12.2017.
|
||||
*/
|
||||
@Controller("accountPostController")
|
||||
@RequestMapping(value = "/account/posts")
|
||||
public class PostController {
|
||||
|
||||
@Autowired
|
||||
private PostRepository postRepository;
|
||||
|
||||
@Autowired
|
||||
private PostService postService;
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
private static final int PAGE_SIZE = 20;
|
||||
|
||||
@GetMapping(name = "")
|
||||
public String getOwnedPosts(@RequestParam(defaultValue = "0") int page, Model model) {
|
||||
|
||||
Assert.notNull(userService.currentUser(), "");
|
||||
|
||||
Page<Post> posts = postRepository.findAllByUser(userService.currentUser(), new PageRequest(page, PAGE_SIZE, Sort.Direction.DESC, "id"));
|
||||
|
||||
model.addAttribute("totalPages", posts.getTotalPages());
|
||||
model.addAttribute("page", page);
|
||||
model.addAttribute("posts", posts);
|
||||
|
||||
return "account/posts/index";
|
||||
}
|
||||
|
||||
private String makeFormPostCreation(Model model) {
|
||||
PostForm postForm = DTOUtil.map(new Post(), PostForm.class);
|
||||
postForm.init();
|
||||
return this.makeFormPostCreation(model, postForm);
|
||||
}
|
||||
|
||||
private String makeFormPostCreation(Model model, PostForm postForm) {
|
||||
|
||||
User user = userService.currentUser();
|
||||
List<PostFormat> availableFormats = userService.getAvailablePostFormats(user);
|
||||
|
||||
model.addAttribute("postForm", postForm);
|
||||
model.addAttribute("postFormats", availableFormats);
|
||||
model.addAttribute("postStatus", PostStatus.values());
|
||||
model.addAttribute("seoOgLocales", OgLocale.values());
|
||||
model.addAttribute("seoOgTypes", OgType.values());
|
||||
|
||||
return "account/posts/new";
|
||||
}
|
||||
|
||||
private String makeFormPostEdition(Long postId, Model model) {
|
||||
return this.makeFormPostEdition(postId, model, null);
|
||||
}
|
||||
|
||||
private String makeFormPostEdition(Long postId, Model model, PostForm postForm) {
|
||||
Post post = postRepository.findOne(postId);
|
||||
|
||||
if (postForm == null) {
|
||||
postForm = DTOUtil.map(post, PostForm.class);
|
||||
}
|
||||
|
||||
postForm.init();
|
||||
DTOUtil.mapTo(post, postForm);
|
||||
postForm.initFromPost(post, postService.getTagNames(post.getTags()));
|
||||
|
||||
User user = userService.currentUser();
|
||||
List<PostFormat> availableFormats = userService.getAvailablePostFormats(user);
|
||||
|
||||
model.addAttribute("post", post);
|
||||
model.addAttribute("postForm", postForm);
|
||||
model.addAttribute("postFormats", availableFormats);
|
||||
model.addAttribute("postStatus", PostStatus.values());
|
||||
model.addAttribute("seoOgLocales", OgLocale.values());
|
||||
model.addAttribute("seoOgTypes", OgType.values());
|
||||
|
||||
return "account/posts/edit";
|
||||
}
|
||||
|
||||
private void checkAccess(Long postId) {
|
||||
if (!postService.getPost(postId).getUser().getId().equals(userService.currentUser().getId())) {
|
||||
throw new AccessDeniedException("You are not allowed to be here");
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping(value = "{postId:[0-9]+}/edit")
|
||||
public String editPost(@PathVariable Long postId, Model model) {
|
||||
this.checkAccess(postId);
|
||||
return this.makeFormPostEdition(postId, model);
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping(value = "new")
|
||||
public String newPost(Model model){
|
||||
return this.makeFormPostCreation(model);
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping(value = "{postId:[0-9]+}/delete", method = {DELETE, POST})
|
||||
public String deletePost(@PathVariable Long postId){
|
||||
this.checkAccess(postId);
|
||||
postService.deletePost(postRepository.findOne(postId));
|
||||
return "redirect:/account/posts";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "", method = POST)
|
||||
public String create(Principal principal, @Valid PostForm postForm, Errors errors, Model model){
|
||||
if (errors.hasErrors()) {
|
||||
Map<String, WebError> webErrors = new HashMap<>();
|
||||
errors.getAllErrors().forEach(e -> {
|
||||
String field = ((FieldError)e).getField();
|
||||
webErrors.put(field, new WebError(field, e.getDefaultMessage()));
|
||||
});
|
||||
model.addAttribute("errors", webErrors);
|
||||
return this.makeFormPostCreation(model, postForm);
|
||||
} else {
|
||||
Post post = DTOUtil.map(postForm, Post.class);
|
||||
post.setUser(userRepository.findByEmail(principal.getName()));
|
||||
post.setTags(postService.parseTagNames(postForm.getPostTags()));
|
||||
postForm.fillOgFieldsInPost(post);
|
||||
|
||||
postService.createPost(post);
|
||||
|
||||
return "redirect:/account/posts";
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping(value = "{postId:[0-9]+}", method = {PUT, POST})
|
||||
public String update(@PathVariable Long postId, @Valid PostForm postForm, Errors errors, Model model){
|
||||
this.checkAccess(postId);
|
||||
if (errors.hasErrors()){
|
||||
Map<String, WebError> webErrors = new HashMap<>();
|
||||
errors.getAllErrors().forEach(e -> {
|
||||
String field = ((FieldError)e).getField();
|
||||
webErrors.put(field, new WebError(field, e.getDefaultMessage()));
|
||||
});
|
||||
model.addAttribute("errors", webErrors);
|
||||
return this.makeFormPostEdition(postId, model, postForm);
|
||||
} else {
|
||||
Post post = postRepository.findOne(postId);
|
||||
DTOUtil.mapTo(postForm, post);
|
||||
post.setTags(postService.parseTagNames(postForm.getPostTags()));
|
||||
postForm.fillOgFieldsInPost(post);
|
||||
|
||||
postService.updatePost(post);
|
||||
|
||||
return "redirect:/account/posts";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
package ru.bvn13.voidforum.controllers.account;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
import ru.bvn13.voidforum.error.NotFoundException;
|
||||
import ru.bvn13.voidforum.forms.StoredFileForm;
|
||||
import ru.bvn13.voidforum.models.StoredFile;
|
||||
import ru.bvn13.voidforum.repositories.StoredFileRepository;
|
||||
import ru.bvn13.voidforum.services.FileStorageService;
|
||||
import ru.bvn13.voidforum.services.UserService;
|
||||
import ru.bvn13.voidforum.utils.DTOUtil;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.DELETE;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.POST;
|
||||
|
||||
@Controller("accountUploadController")
|
||||
@RequestMapping("account/files")
|
||||
public class StoredFileController {
|
||||
|
||||
private static final int PAGE_SIZE = 20;
|
||||
|
||||
@Autowired
|
||||
private FileStorageService storageService;
|
||||
|
||||
@Autowired
|
||||
private StoredFileRepository storedFileRepository;
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@GetMapping("")
|
||||
public String index(@RequestParam(defaultValue = "0") int page, Model model) {
|
||||
Page<StoredFile> files = storedFileRepository.findAllByUserOrderByIdDesc(userService.currentUser(), new PageRequest(page, PAGE_SIZE, Sort.Direction.DESC, "id"));
|
||||
|
||||
model.addAttribute("totalPages", files.getTotalPages());
|
||||
model.addAttribute("page", page);
|
||||
model.addAttribute("files", files);
|
||||
|
||||
return "account/files/index";
|
||||
}
|
||||
|
||||
@PostMapping("/upload") //new annotation since 4.3
|
||||
public String upload(@RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes) {
|
||||
if (file.isEmpty()) {
|
||||
redirectAttributes.addFlashAttribute("uploadStatus", "Please select a file to upload");
|
||||
return "redirect:/account/files/status";
|
||||
}
|
||||
|
||||
String message = "";
|
||||
|
||||
try {
|
||||
|
||||
// Get the file and save it somewhere
|
||||
byte[] bytes = file.getBytes();
|
||||
|
||||
this.storageService.storeFile(userService.currentUser(), file.getOriginalFilename(), bytes);
|
||||
|
||||
message = "You successfully uploaded '" + file.getOriginalFilename() + "'";
|
||||
redirectAttributes.addFlashAttribute("uploadStatus", message);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
message = "Internal server error occured";
|
||||
redirectAttributes.addFlashAttribute("uploadStatus", message);
|
||||
}
|
||||
|
||||
return "redirect:/account/files/status";
|
||||
}
|
||||
|
||||
@GetMapping("/status")
|
||||
public String uploadStatus() {
|
||||
return "account/files/status";
|
||||
}
|
||||
|
||||
|
||||
|
||||
@GetMapping(value = "/{fileId:[\\d]+}/edit")
|
||||
public String editFileById(@PathVariable Long fileId, Model model) {
|
||||
Assert.notNull(fileId);
|
||||
StoredFile file = this.storageService.getFileById(fileId);
|
||||
if (file == null) {
|
||||
//response.sendError(404, String.format("File %s not found", fileId));
|
||||
throw new NotFoundException(String.format("File with id %s not found", fileId));
|
||||
}
|
||||
|
||||
StoredFileForm fileForm = DTOUtil.map(file, StoredFileForm.class);
|
||||
|
||||
model.addAttribute("file", file);
|
||||
model.addAttribute("fileForm", fileForm);
|
||||
|
||||
return "account/files/edit";
|
||||
}
|
||||
|
||||
|
||||
@PostMapping(value = "/{fileId:[\\d]+}")
|
||||
public String saveFile(@PathVariable Long fileId, @Valid StoredFileForm fileForm, Errors errors) {
|
||||
Assert.notNull(fileId);
|
||||
|
||||
if (errors.hasErrors()) {
|
||||
return String.format("account/files/%d/edit", fileId);
|
||||
}
|
||||
|
||||
StoredFile storedFile = this.storedFileRepository.findById(fileId);
|
||||
DTOUtil.mapTo(fileForm, storedFile);
|
||||
storedFile.setUser(this.userService.currentUser());
|
||||
storedFile.setUpdatedAt(new Date());
|
||||
this.storedFileRepository.save(storedFile);
|
||||
|
||||
return "redirect:/account/files";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "{fileId:[0-9]+}/delete", method = {DELETE, POST})
|
||||
public String deletePost(@PathVariable Long fileId){
|
||||
try {
|
||||
this.storageService.deleteFileById(fileId);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "redirect:/account/files";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package ru.bvn13.voidforum.controllers.account;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
import ru.bvn13.voidforum.forms.UserForm;
|
||||
import ru.bvn13.voidforum.models.User;
|
||||
import ru.bvn13.voidforum.repositories.UserRepository;
|
||||
import ru.bvn13.voidforum.services.UserService;
|
||||
import ru.bvn13.voidforum.support.web.MessageHelper;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.POST;
|
||||
|
||||
/**
|
||||
* bvn13 <mail4bvn@gmail.com>.
|
||||
*/
|
||||
@Controller("accountUserController")
|
||||
@RequestMapping("account/profile")
|
||||
public class UserController {
|
||||
|
||||
private UserService userService;
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
public UserController(UserService userService, UserRepository userRepository){
|
||||
this.userService = userService;
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
@RequestMapping()
|
||||
public String profile(Model model){
|
||||
model.addAttribute("user", userService.currentUser());
|
||||
|
||||
return "account/users/profile";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "{userId:[0-9]+}", method = POST)
|
||||
public String update(@PathVariable Long userId, @Valid UserForm userForm, Errors errors, RedirectAttributes ra){
|
||||
User user = userRepository.findOne(userId);
|
||||
Assert.notNull(user);
|
||||
|
||||
if (!userService.currentUser().getId().equals(userId)) {
|
||||
throw new AccessDeniedException("You are not allowed here");
|
||||
}
|
||||
|
||||
if (errors.hasErrors()){
|
||||
// do something
|
||||
|
||||
return "account/users/profile";
|
||||
}
|
||||
|
||||
if (!userForm.getNewPassword().isEmpty()){
|
||||
|
||||
if (!userService.changePassword(user, userForm.getPassword(), userForm.getNewPassword()))
|
||||
MessageHelper.addErrorAttribute(ra, "Change password failed.");
|
||||
else
|
||||
MessageHelper.addSuccessAttribute(ra, "Change password successfully.");
|
||||
|
||||
}
|
||||
|
||||
return "redirect:/account/profile";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package ru.bvn13.voidforum.controllers.admin;
|
||||
|
||||
import ru.bvn13.voidforum.forms.SettingsForm;
|
||||
import ru.bvn13.voidforum.services.AppSetting;
|
||||
import ru.bvn13.voidforum.support.web.MessageHelper;
|
||||
import ru.bvn13.voidforum.utils.DTOUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
/**
|
||||
* bvn13 <mail4bvn@gmail.com>
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("admin")
|
||||
public class AdminController {
|
||||
|
||||
private AppSetting appSetting;
|
||||
|
||||
@Autowired
|
||||
public AdminController( AppSetting appSetting){
|
||||
this.appSetting = appSetting;
|
||||
}
|
||||
|
||||
@RequestMapping("")
|
||||
public String index(){
|
||||
return "admin/home/index";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "settings")
|
||||
public String settings(Model model){
|
||||
SettingsForm settingsForm = DTOUtil.map(appSetting, SettingsForm.class);
|
||||
|
||||
model.addAttribute("settings", settingsForm);
|
||||
return "admin/home/settings";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "settings", method = RequestMethod.POST)
|
||||
public String updateSettings(@Valid SettingsForm settingsForm, Errors errors, Model model, RedirectAttributes ra){
|
||||
if (errors.hasErrors()){
|
||||
return "admin/settings";
|
||||
} else {
|
||||
appSetting.setSiteName(settingsForm.getSiteName());
|
||||
appSetting.setSiteSlogan(settingsForm.getSiteSlogan());
|
||||
appSetting.setPageSize(settingsForm.getPageSize());
|
||||
appSetting.setStoragePath(settingsForm.getStoragePath());
|
||||
appSetting.setMainUri(settingsForm.getMainUri());
|
||||
|
||||
MessageHelper.addSuccessAttribute(ra, "Update settings successfully.");
|
||||
|
||||
return "redirect:settings";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
package ru.bvn13.voidforum.controllers.admin;
|
||||
|
||||
import ru.bvn13.voidforum.forms.PostForm;
|
||||
import ru.bvn13.voidforum.models.Post;
|
||||
import ru.bvn13.voidforum.models.User;
|
||||
import ru.bvn13.voidforum.models.support.*;
|
||||
import ru.bvn13.voidforum.repositories.PostRepository;
|
||||
import ru.bvn13.voidforum.repositories.UserRepository;
|
||||
import ru.bvn13.voidforum.services.PostService;
|
||||
import ru.bvn13.voidforum.services.PrivilegeService;
|
||||
import ru.bvn13.voidforum.services.UserService;
|
||||
import ru.bvn13.voidforum.utils.DTOUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.FieldError;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.security.Principal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.*;
|
||||
|
||||
/**
|
||||
* bvn13 <mail4bvn@gmail.com>
|
||||
*/
|
||||
@Controller("adminPostController")
|
||||
@RequestMapping("admin/posts")
|
||||
public class PostController {
|
||||
|
||||
@Autowired
|
||||
private PostRepository postRepository;
|
||||
|
||||
@Autowired
|
||||
private PostService postService;
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
|
||||
private static final int PAGE_SIZE = 20;
|
||||
|
||||
@RequestMapping(value = "")
|
||||
public String index(@RequestParam(defaultValue = "0") int page, Model model) {
|
||||
Page<Post> posts = postRepository.findAll(new PageRequest(page, PAGE_SIZE, Sort.Direction.DESC, "id"));
|
||||
|
||||
model.addAttribute("totalPages", posts.getTotalPages());
|
||||
model.addAttribute("page", page);
|
||||
model.addAttribute("posts", posts);
|
||||
|
||||
return "admin/posts/index";
|
||||
}
|
||||
|
||||
private String makeFormPostCreation(Model model) {
|
||||
PostForm postForm = DTOUtil.map(new Post(), PostForm.class);
|
||||
postForm.init();
|
||||
return this.makeFormPostCreation(model, postForm);
|
||||
}
|
||||
|
||||
private String makeFormPostCreation(Model model, PostForm postForm) {
|
||||
|
||||
User user = userService.currentUser();
|
||||
List<PostFormat> availableFormats = userService.getAvailablePostFormats(user);
|
||||
|
||||
model.addAttribute("postForm", postForm);
|
||||
model.addAttribute("postFormats", availableFormats);
|
||||
model.addAttribute("postStatus", PostStatus.values());
|
||||
model.addAttribute("seoOgLocales", OgLocale.values());
|
||||
model.addAttribute("seoOgTypes", OgType.values());
|
||||
|
||||
return "admin/posts/new";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "new")
|
||||
public String newPost(Model model){
|
||||
return this.makeFormPostCreation(model);
|
||||
}
|
||||
|
||||
private String makeFormPostEdition(Long postId, Model model) {
|
||||
return this.makeFormPostEdition(postId, model, null);
|
||||
}
|
||||
|
||||
private String makeFormPostEdition(Long postId, Model model, PostForm postForm) {
|
||||
Post post = postRepository.findOne(postId);
|
||||
|
||||
if (postForm == null) {
|
||||
postForm = DTOUtil.map(post, PostForm.class);
|
||||
}
|
||||
|
||||
postForm.init();
|
||||
DTOUtil.mapTo(post, postForm);
|
||||
postForm.initFromPost(post, postService.getTagNames(post.getTags()));
|
||||
|
||||
User user = userService.currentUser();
|
||||
List<PostFormat> availableFormats = userService.getAvailablePostFormats(user);
|
||||
|
||||
model.addAttribute("post", post);
|
||||
model.addAttribute("postForm", postForm);
|
||||
model.addAttribute("postFormats", availableFormats);
|
||||
model.addAttribute("postStatus", PostStatus.values());
|
||||
model.addAttribute("seoOgLocales", OgLocale.values());
|
||||
model.addAttribute("seoOgTypes", OgType.values());
|
||||
|
||||
return "admin/posts/edit";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "{postId:[0-9]+}/edit")
|
||||
public String editPost(@PathVariable Long postId, Model model){
|
||||
return this.makeFormPostEdition(postId, model);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "{postId:[0-9]+}/delete", method = {DELETE, POST})
|
||||
public String deletePost(@PathVariable Long postId){
|
||||
postService.deletePost(postRepository.findOne(postId));
|
||||
return "redirect:/admin/posts";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "{postId:[0-9]+}/censore", method = {PUT, POST})
|
||||
public String censorePost(@PathVariable Long postId){
|
||||
postService.censorePost(postRepository.findOne(postId));
|
||||
return "redirect:/admin/posts";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "", method = POST)
|
||||
public String create(Principal principal, @Valid PostForm postForm, Errors errors, Model model){
|
||||
if (errors.hasErrors()) {
|
||||
Map<String, WebError> webErrors = new HashMap<>();
|
||||
errors.getAllErrors().forEach(e -> {
|
||||
String field = ((FieldError)e).getField();
|
||||
webErrors.put(field, new WebError(field, e.getDefaultMessage()));
|
||||
});
|
||||
model.addAttribute("errors", webErrors);
|
||||
return this.makeFormPostCreation(model, postForm);
|
||||
} else {
|
||||
Post post = DTOUtil.map(postForm, Post.class);
|
||||
post.setUser(userRepository.findByEmail(principal.getName()));
|
||||
post.setTags(postService.parseTagNames(postForm.getPostTags()));
|
||||
postForm.fillOgFieldsInPost(post);
|
||||
|
||||
postService.createPost(post);
|
||||
|
||||
return "redirect:/admin/posts";
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping(value = "{postId:[0-9]+}", method = {PUT, POST})
|
||||
public String update(@PathVariable Long postId, @Valid PostForm postForm, Errors errors, Model model){
|
||||
if (errors.hasErrors()){
|
||||
Map<String, WebError> webErrors = new HashMap<>();
|
||||
errors.getAllErrors().forEach(e -> {
|
||||
String field = ((FieldError)e).getField();
|
||||
webErrors.put(field, new WebError(field, e.getDefaultMessage()));
|
||||
});
|
||||
model.addAttribute("errors", webErrors);
|
||||
return this.makeFormPostEdition(postId, model, postForm);
|
||||
} else {
|
||||
Post post = postRepository.findOne(postId);
|
||||
DTOUtil.mapTo(postForm, post);
|
||||
post.setTags(postService.parseTagNames(postForm.getPostTags()));
|
||||
postForm.fillOgFieldsInPost(post);
|
||||
|
||||
postService.updatePost(post);
|
||||
|
||||
return "redirect:/admin/posts";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package ru.bvn13.voidforum.controllers.admin;
|
||||
|
||||
import ru.bvn13.voidforum.forms.SeoRobotAgentForm;
|
||||
import ru.bvn13.voidforum.models.SeoRobotAgent;
|
||||
import ru.bvn13.voidforum.repositories.SeoRobotAgentRepository;
|
||||
import ru.bvn13.voidforum.utils.DTOUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
@Controller
|
||||
@RequestMapping(value = "/admin/robotsAgents")
|
||||
public class SeoRobotAgentController {
|
||||
|
||||
@Autowired
|
||||
private SeoRobotAgentRepository seoRobotAgentRepository;
|
||||
|
||||
@GetMapping()
|
||||
public String getSeoRobotsAgents(Model model) {
|
||||
model.addAttribute("records", this.seoRobotAgentRepository.findAll());
|
||||
model.addAttribute("form", new SeoRobotAgentForm());
|
||||
return "admin/robotsAgents/index";
|
||||
}
|
||||
|
||||
|
||||
@GetMapping(value = "/{recordId:[\\d]+}/edit")
|
||||
public String editSeoRobotAgent(@PathVariable Long recordId, Model model) {
|
||||
|
||||
SeoRobotAgent ua = this.seoRobotAgentRepository.findOne(recordId);
|
||||
|
||||
Assert.notNull(ua);
|
||||
|
||||
model.addAttribute("form", DTOUtil.map(ua, SeoRobotAgentForm.class));
|
||||
|
||||
return "admin/robotsAgents/edit";
|
||||
}
|
||||
|
||||
@PostMapping(value = "/{recordId:[\\d]+}/edit")
|
||||
public String saveSeoRobotAgent(@PathVariable Long recordId, @Valid SeoRobotAgentForm form, Errors errors) {
|
||||
SeoRobotAgent ua = null;
|
||||
if (recordId.equals(0L)) {
|
||||
ua = new SeoRobotAgent();
|
||||
} else {
|
||||
ua = this.seoRobotAgentRepository.findOne(recordId);
|
||||
}
|
||||
Assert.notNull(ua);
|
||||
|
||||
DTOUtil.mapTo(form, ua);
|
||||
|
||||
this.seoRobotAgentRepository.save(ua);
|
||||
|
||||
return "redirect:/admin/robotsAgents";
|
||||
}
|
||||
|
||||
|
||||
@PostMapping(value = "/{recordId:[\\d]+}/delete")
|
||||
public String deleteSeoRobotAgent(@PathVariable Long recordId) {
|
||||
this.seoRobotAgentRepository.delete(recordId);
|
||||
return "redirect:/admin/robotsAgents";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
package ru.bvn13.voidforum.controllers.admin;
|
||||
|
||||
import ru.bvn13.voidforum.error.NotFoundException;
|
||||
import ru.bvn13.voidforum.forms.StoredFileForm;
|
||||
import ru.bvn13.voidforum.models.StoredFile;
|
||||
import ru.bvn13.voidforum.repositories.StoredFileRepository;
|
||||
import ru.bvn13.voidforum.services.FileStorageService;
|
||||
import ru.bvn13.voidforum.services.UserService;
|
||||
import ru.bvn13.voidforum.utils.DTOUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.DELETE;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.POST;
|
||||
|
||||
@Controller("adminUploadController")
|
||||
@RequestMapping("admin/files")
|
||||
public class StoredFileController {
|
||||
|
||||
private static final int PAGE_SIZE = 20;
|
||||
|
||||
@Autowired
|
||||
private FileStorageService storageService;
|
||||
|
||||
@Autowired
|
||||
private StoredFileRepository storedFileRepository;
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@GetMapping("")
|
||||
public String index(@RequestParam(defaultValue = "0") int page, Model model) {
|
||||
Page<StoredFile> files = storedFileRepository.findAll(new PageRequest(page, PAGE_SIZE, Sort.Direction.DESC, "id"));
|
||||
|
||||
model.addAttribute("totalPages", files.getTotalPages());
|
||||
model.addAttribute("page", page);
|
||||
model.addAttribute("files", files);
|
||||
|
||||
return "admin/files/index";
|
||||
}
|
||||
|
||||
@PostMapping("/upload") //new annotation since 4.3
|
||||
public String upload(@RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes) {
|
||||
if (file.isEmpty()) {
|
||||
redirectAttributes.addFlashAttribute("uploadStatus", "Please select a file to upload");
|
||||
return "redirect:/admin/files/status";
|
||||
}
|
||||
|
||||
String message = "";
|
||||
|
||||
try {
|
||||
|
||||
// Get the file and save it somewhere
|
||||
byte[] bytes = file.getBytes();
|
||||
|
||||
this.storageService.storeFile(userService.currentUser(), file.getOriginalFilename(), bytes);
|
||||
|
||||
message = "You successfully uploaded '" + file.getOriginalFilename() + "'";
|
||||
redirectAttributes.addFlashAttribute("uploadStatus", message);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
message = "Internal server error occured";
|
||||
redirectAttributes.addFlashAttribute("uploadStatus", message);
|
||||
}
|
||||
|
||||
return "redirect:/admin/files/status";
|
||||
}
|
||||
|
||||
@GetMapping("/status")
|
||||
public String uploadStatus() {
|
||||
return "admin/files/status";
|
||||
}
|
||||
|
||||
|
||||
|
||||
@GetMapping(value = "/{fileId:[\\d]+}/edit")
|
||||
public String editFileById(@PathVariable Long fileId, Model model) {
|
||||
Assert.notNull(fileId);
|
||||
StoredFile file = this.storageService.getFileById(fileId);
|
||||
if (file == null) {
|
||||
//response.sendError(404, String.format("File %s not found", fileId));
|
||||
throw new NotFoundException(String.format("File with id %s not found", fileId));
|
||||
}
|
||||
|
||||
StoredFileForm fileForm = DTOUtil.map(file, StoredFileForm.class);
|
||||
|
||||
model.addAttribute("file", file);
|
||||
model.addAttribute("fileForm", fileForm);
|
||||
|
||||
return "admin/files/edit";
|
||||
}
|
||||
|
||||
|
||||
@PostMapping(value = "/{fileId:[\\d]+}")
|
||||
public String saveFile(@PathVariable Long fileId, @Valid StoredFileForm fileForm, Errors errors) {
|
||||
Assert.notNull(fileId);
|
||||
|
||||
if (errors.hasErrors()) {
|
||||
return String.format("admin/files/%d/edit", fileId);
|
||||
}
|
||||
|
||||
StoredFile storedFile = this.storedFileRepository.findById(fileId);
|
||||
DTOUtil.mapTo(fileForm, storedFile);
|
||||
storedFile.setUser(this.userService.currentUser());
|
||||
storedFile.setUpdatedAt(new Date());
|
||||
this.storedFileRepository.save(storedFile);
|
||||
|
||||
return "redirect:/admin/files";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "{fileId:[0-9]+}/delete", method = {DELETE, POST})
|
||||
public String deletePost(@PathVariable Long fileId){
|
||||
try {
|
||||
this.storageService.deleteFileById(fileId);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "redirect:/admin/files";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package ru.bvn13.voidforum.controllers.admin;
|
||||
|
||||
import ru.bvn13.voidforum.forms.UserForm;
|
||||
import ru.bvn13.voidforum.models.User;
|
||||
import ru.bvn13.voidforum.repositories.UserRepository;
|
||||
import ru.bvn13.voidforum.services.UserService;
|
||||
import ru.bvn13.voidforum.support.web.MessageHelper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.POST;
|
||||
|
||||
/**
|
||||
* bvn13 <mail4bvn@gmail.com>.
|
||||
*/
|
||||
@Controller("adminUserController")
|
||||
@RequestMapping("admin/users")
|
||||
public class UserController {
|
||||
|
||||
private UserService userService;
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
public UserController(UserService userService, UserRepository userRepository){
|
||||
this.userService = userService;
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
@RequestMapping("profile")
|
||||
public String profile(Model model){
|
||||
model.addAttribute("user", userService.currentUser());
|
||||
|
||||
return "admin/users/profile";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "{userId:[0-9]+}", method = POST)
|
||||
public String update(@PathVariable Long userId, @Valid UserForm userForm, Errors errors, RedirectAttributes ra){
|
||||
User user = userRepository.findOne(userId);
|
||||
Assert.notNull(user);
|
||||
|
||||
if (errors.hasErrors()){
|
||||
// do something
|
||||
|
||||
return "admin/users/profile";
|
||||
}
|
||||
|
||||
if (!userForm.getNewPassword().isEmpty()){
|
||||
|
||||
if (!userService.changePassword(user, userForm.getPassword(), userForm.getNewPassword()))
|
||||
MessageHelper.addErrorAttribute(ra, "Change password failed.");
|
||||
else
|
||||
MessageHelper.addSuccessAttribute(ra, "Change password successfully.");
|
||||
|
||||
}
|
||||
|
||||
return "redirect:profile";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package ru.bvn13.voidforum.controllers.seo;
|
||||
|
||||
import ru.bvn13.voidforum.models.Post;
|
||||
import ru.bvn13.voidforum.services.PostService;
|
||||
import ru.bvn13.voidforum.services.SeoService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Controller
|
||||
@RequestMapping(value = {"/seo", ""})
|
||||
public class SitemapController {
|
||||
|
||||
@Autowired
|
||||
private PostService postService;
|
||||
|
||||
@Autowired
|
||||
private SeoService seoService;
|
||||
|
||||
@GetMapping(value = "/sitemap", produces = MediaType.APPLICATION_XML_VALUE)
|
||||
public @ResponseBody
|
||||
String getSiteMap() {
|
||||
List<Post> posts = this.postService.getAllPublishedPosts();
|
||||
return this.seoService.createSitemap(posts);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package ru.bvn13.voidforum.error;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
public class EmailExistsException extends Exception {
|
||||
@Getter
|
||||
private String message;
|
||||
|
||||
public EmailExistsException(){}
|
||||
|
||||
public EmailExistsException(String message){
|
||||
this.message = message;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package ru.bvn13.voidforum.error;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* General error handler for the application.
|
||||
*/
|
||||
@ControllerAdvice
|
||||
class ExceptionHandlerController {
|
||||
private static final Logger logger = LoggerFactory.getLogger(ExceptionHandlerController.class);
|
||||
|
||||
@ResponseStatus(HttpStatus.NOT_FOUND)
|
||||
@ExceptionHandler(NotFoundException.class)
|
||||
public ModelAndView notFound(HttpServletRequest request, NotFoundException exception){
|
||||
String uri = request.getRequestURI();
|
||||
logger.error("Request page: " + uri + " raised NotFoundException : " + exception);
|
||||
|
||||
ModelAndView model = new ModelAndView("error/general");
|
||||
model.addObject("status", HttpStatus.NOT_FOUND.value());
|
||||
model.addObject("error", HttpStatus.NOT_FOUND.getReasonPhrase());
|
||||
model.addObject("path", uri);
|
||||
model.addObject("customMessage", exception.getMessage());
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle all exceptions
|
||||
*/
|
||||
// @ResponseStatus(HttpStatus.SERVICE_UNAVAILABLE)
|
||||
@ExceptionHandler(Exception.class)
|
||||
public ModelAndView exception(HttpServletRequest request, Exception exception) {
|
||||
String uri = request.getRequestURI();
|
||||
logger.error("Request page: " + uri + " raised exception : " + exception);
|
||||
|
||||
ModelAndView model = new ModelAndView("error/general");
|
||||
model.addObject("error", Throwables.getRootCause(exception).getMessage());
|
||||
model.addObject("status", Throwables.getRootCause(exception).getCause());
|
||||
model.addObject("path", uri);
|
||||
model.addObject("customMessage", exception.getMessage());
|
||||
|
||||
return model;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package ru.bvn13.voidforum.error;
|
||||
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
public class NicknameExistsException extends Exception {
|
||||
@Getter
|
||||
private String message;
|
||||
|
||||
public NicknameExistsException(){}
|
||||
|
||||
public NicknameExistsException(String message){
|
||||
this.message = message;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package ru.bvn13.voidforum.error;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
/**
|
||||
* @author Raysmond<i@raysmond.com>
|
||||
*/
|
||||
@ResponseStatus(value = HttpStatus.NOT_FOUND)
|
||||
public final class NotFoundException extends RuntimeException {
|
||||
private String message;
|
||||
|
||||
public NotFoundException(){
|
||||
|
||||
}
|
||||
|
||||
public NotFoundException(String message){
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage(){
|
||||
return message;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package ru.bvn13.voidforum.forms;
|
||||
|
||||
import lombok.Data;
|
||||
import ru.bvn13.voidforum.models.Comment;
|
||||
import ru.bvn13.voidforum.models.Post;
|
||||
import ru.bvn13.voidforum.models.User;
|
||||
import ru.bvn13.voidforum.models.support.CommentFormat;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* Created by bvn13 on 08.12.2017.
|
||||
*/
|
||||
@Data
|
||||
public class CommentForm {
|
||||
|
||||
@NotNull
|
||||
private Integer postId;
|
||||
|
||||
private Integer parentCommentId;
|
||||
|
||||
@NotEmpty
|
||||
private String content;
|
||||
|
||||
@NotNull
|
||||
private CommentFormat commentFormat;
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package ru.bvn13.voidforum.forms;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Data
|
||||
public class LikeForm {
|
||||
|
||||
@NotNull
|
||||
private String sympathy = "0";
|
||||
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
package ru.bvn13.voidforum.forms;
|
||||
|
||||
import lombok.Data;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import ru.bvn13.voidforum.models.Post;
|
||||
import ru.bvn13.voidforum.models.SeoPostData;
|
||||
import ru.bvn13.voidforum.models.support.OgLocale;
|
||||
import ru.bvn13.voidforum.models.support.OgType;
|
||||
import ru.bvn13.voidforum.models.support.PostFormat;
|
||||
import ru.bvn13.voidforum.models.support.PostStatus;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* bvn13 <mail4bvn@gmail.com>
|
||||
*/
|
||||
@Data
|
||||
public class PostForm {
|
||||
@NotEmpty
|
||||
private String title;
|
||||
|
||||
@NotEmpty
|
||||
private String content;
|
||||
|
||||
@NotNull
|
||||
private PostFormat postFormat;
|
||||
|
||||
@NotNull
|
||||
private PostStatus postStatus;
|
||||
|
||||
@NotNull
|
||||
private String permalink;
|
||||
|
||||
@NotNull
|
||||
private String postTags;
|
||||
|
||||
@NotNull
|
||||
private String seoKeywords;
|
||||
|
||||
@NotNull
|
||||
private String seoDescription;
|
||||
|
||||
|
||||
// @NotNull
|
||||
// private String seoOgTitle;
|
||||
|
||||
@NotNull
|
||||
private OgType seoOgType;
|
||||
|
||||
@NotNull
|
||||
private String seoOgImage;
|
||||
|
||||
@NotNull
|
||||
private String seoOgVideo;
|
||||
|
||||
@NotNull
|
||||
private OgLocale seoOgLocale;
|
||||
|
||||
@NotNull
|
||||
private Boolean deletedMark;
|
||||
|
||||
@NotNull
|
||||
private Boolean censored;
|
||||
|
||||
public void init() {
|
||||
this.setTitle("");
|
||||
this.setPermalink("");
|
||||
this.setContent("");
|
||||
this.setPostTags("");
|
||||
this.setPostStatus(PostStatus.DRAFT);
|
||||
this.setPostFormat(PostFormat.MARKDOWN);
|
||||
this.setSeoKeywords("");
|
||||
this.setSeoOgImage("");
|
||||
this.setSeoOgLocale(OgLocale.ru_RU);
|
||||
//this.setSeoOgTitle("");
|
||||
this.setSeoOgType(OgType.WEBSITE);
|
||||
this.setSeoOgVideo("");
|
||||
this.setDeletedMark(false);
|
||||
this.setCensored(false);
|
||||
}
|
||||
|
||||
public void initFromPost(Post post) {
|
||||
if (post.getSeoData() != null) {
|
||||
this.setSeoOgImage(post.getSeoData().getOgImage());
|
||||
this.setSeoOgVideo(post.getSeoData().getOgVideo());
|
||||
this.setSeoOgLocale(post.getSeoData().getOgLocale());
|
||||
this.setSeoOgType(post.getSeoData().getOgType());
|
||||
} else {
|
||||
this.setSeoOgImage("");
|
||||
this.setSeoOgLocale(OgLocale.ru_RU);
|
||||
//this.setSeoOgTitle("");
|
||||
this.setSeoOgType(OgType.WEBSITE);
|
||||
this.setSeoOgVideo("");
|
||||
}
|
||||
}
|
||||
|
||||
public void initFromPost(Post post, String postTags) {
|
||||
this.initFromPost(post);
|
||||
this.setPostTags(postTags);
|
||||
}
|
||||
|
||||
public void fillOgFieldsInPost(Post post) {
|
||||
SeoPostData data = null;
|
||||
if (post.getSeoData() == null) {
|
||||
data = new SeoPostData();
|
||||
} else {
|
||||
data = post.getSeoData();
|
||||
}
|
||||
data.setOgImage(this.seoOgImage);
|
||||
data.setOgLocale(this.seoOgLocale);
|
||||
data.setOgTitle(this.title);
|
||||
data.setOgType(this.seoOgType);
|
||||
data.setOgVideo(this.seoOgVideo);
|
||||
post.setSeoData(data);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package ru.bvn13.voidforum.forms;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* bvn13 <mail4bvn@gmail.com>.
|
||||
*/
|
||||
@Data
|
||||
public class RegistrationForm {
|
||||
|
||||
@Email(message = "Email should be valid")
|
||||
@NotBlank(message = "Specify your email")
|
||||
private String username;
|
||||
|
||||
@NotBlank(message = "Specify your nickname")
|
||||
private String nickname;
|
||||
|
||||
@NotBlank(message = "Specify your password")
|
||||
private String password;
|
||||
|
||||
@NotBlank(message = "Verify your password")
|
||||
private String passwordCheck;
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package ru.bvn13.voidforum.forms;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Data
|
||||
public class SeoRobotAgentForm {
|
||||
|
||||
@NotNull
|
||||
private Long id = 0L;
|
||||
|
||||
@NotNull
|
||||
private String userAgent = "";
|
||||
|
||||
@NotNull
|
||||
private Boolean isRegexp = false;
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package ru.bvn13.voidforum.forms;
|
||||
|
||||
import lombok.Data;
|
||||
import org.hibernate.validator.constraints.NotEmpty;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* bvn13 <mail4bvn@gmail.com>
|
||||
*/
|
||||
@Data
|
||||
public class SettingsForm {
|
||||
|
||||
@NotEmpty
|
||||
@NotNull
|
||||
private String siteName;
|
||||
|
||||
@NotNull
|
||||
private String siteSlogan;
|
||||
|
||||
@NotNull
|
||||
private Integer pageSize;
|
||||
|
||||
@NotNull
|
||||
private String storagePath;
|
||||
|
||||
@NotNull
|
||||
private String mainUri;
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package ru.bvn13.voidforum.forms;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Data
|
||||
public class StoredFileForm {
|
||||
|
||||
@NotNull
|
||||
private String title;
|
||||
|
||||
@NotNull
|
||||
private String name;
|
||||
|
||||
@NotNull
|
||||
private String path;
|
||||
|
||||
@NotNull
|
||||
private Long size;
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package ru.bvn13.voidforum.forms;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Email;
|
||||
|
||||
/**
|
||||
* bvn13 <mail4bvn@gmail.com>.
|
||||
*/
|
||||
@Data
|
||||
public class UserForm {
|
||||
|
||||
@NotBlank(message = "Enter your password")
|
||||
private String password;
|
||||
|
||||
@NotBlank(message = "Specify your new password")
|
||||
private String newPassword;
|
||||
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package ru.bvn13.voidforum.models;
|
||||
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* An abstract base model class for entities
|
||||
*
|
||||
* @author bvn13 <mail4bvn@gmail.com>
|
||||
*/
|
||||
@MappedSuperclass
|
||||
public abstract class BaseModel implements Comparable<BaseModel>, Serializable {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "id")
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Date createdAt;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Date updatedAt;
|
||||
|
||||
@PrePersist
|
||||
public void prePersist(){
|
||||
createdAt = updatedAt = new Date();
|
||||
}
|
||||
|
||||
@PreUpdate
|
||||
public void preUpdate(){
|
||||
updatedAt = new Date();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(BaseModel o) {
|
||||
return this.getId().compareTo(o.getId());
|
||||
}
|
||||
|
||||
public boolean equals(Object other) {
|
||||
if (other == null || other.getClass() != this.getClass())
|
||||
return false;
|
||||
|
||||
return this.getId().equals(((BaseModel) other).getId());
|
||||
}
|
||||
|
||||
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder().append(getId()).toHashCode();
|
||||
}
|
||||
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long _id) {
|
||||
id = _id;
|
||||
}
|
||||
|
||||
public Date getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public void setCreatedAt(Date createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
public Date getUpdatedAt() {
|
||||
return updatedAt;
|
||||
}
|
||||
|
||||
public void setUpdatedAt(Date updatedAt) {
|
||||
this.updatedAt = updatedAt;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package ru.bvn13.voidforum.models;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hibernate.annotations.Type;
|
||||
import ru.bvn13.voidforum.models.support.CommentFormat;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
@Entity
|
||||
@Table(name = "comments")
|
||||
@Getter
|
||||
@Setter
|
||||
public class Comment extends BaseModel {
|
||||
|
||||
@ManyToOne
|
||||
private User user;
|
||||
|
||||
@ManyToOne
|
||||
private Post post;
|
||||
|
||||
@ManyToOne
|
||||
private Comment parentComment;
|
||||
|
||||
|
||||
@OneToMany(fetch = FetchType.LAZY, mappedBy = "parentComment", cascade = CascadeType.REMOVE)
|
||||
private Collection<Comment> children = new ArrayList<>();
|
||||
|
||||
|
||||
@Type(type="text")
|
||||
@Getter
|
||||
@Setter
|
||||
private String content;
|
||||
|
||||
@Type(type = "text")
|
||||
private String renderedContent;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Enumerated(EnumType.STRING)
|
||||
private CommentFormat commentFormat = CommentFormat.MARKDOWN;
|
||||
|
||||
@Column(nullable = false, columnDefinition = "boolean DEFAULT false")
|
||||
private Boolean deletedMark;
|
||||
|
||||
@Column(nullable = false, columnDefinition = "integer DEFAULT 0")
|
||||
private Integer depth;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package ru.bvn13.voidforum.models;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "posts_likes")
|
||||
@Getter
|
||||
@Setter
|
||||
public class Like extends BaseModel {
|
||||
|
||||
@ManyToOne
|
||||
private User user;
|
||||
|
||||
@ManyToOne
|
||||
private Post post;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Integer sympathy;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String clientIp;
|
||||
|
||||
@Column(nullable = false, columnDefinition = "boolean default false")
|
||||
private Boolean isAdmin;
|
||||
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
package ru.bvn13.voidforum.models;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hibernate.annotations.Type;
|
||||
import org.springframework.util.StringUtils;
|
||||
import ru.bvn13.voidforum.models.support.PostFormat;
|
||||
import ru.bvn13.voidforum.models.support.PostStatus;
|
||||
import ru.bvn13.voidforum.models.support.PostType;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* bvn13 <mail4bvn@gmail.com>
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "posts")
|
||||
@Getter
|
||||
@Setter
|
||||
public class Post extends BaseModel {
|
||||
private static final SimpleDateFormat SLUG_DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd");
|
||||
|
||||
@ManyToOne
|
||||
private User user;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String title;
|
||||
|
||||
@Type(type="text")
|
||||
private String content;
|
||||
|
||||
@Type(type = "text")
|
||||
private String renderedContent;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Enumerated(EnumType.STRING)
|
||||
private PostStatus postStatus = PostStatus.PUBLISHED;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Enumerated(EnumType.STRING)
|
||||
private PostFormat postFormat = PostFormat.MARKDOWN;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Enumerated(EnumType.STRING)
|
||||
private PostType postType = PostType.POST;
|
||||
|
||||
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||
@JoinTable(name = "posts_tags",
|
||||
joinColumns = {@JoinColumn(name = "post_id", nullable = false, updatable = false)},
|
||||
inverseJoinColumns = {@JoinColumn(name = "tag_id", nullable = false, updatable = false)}
|
||||
)
|
||||
private Set<Tag> tags = new HashSet<>();
|
||||
|
||||
@Column(nullable = false, columnDefinition = "character varying DEFAULT ''")
|
||||
private String seoKeywords = "";
|
||||
|
||||
@Column(nullable = false, columnDefinition = "character varying DEFAULT ''")
|
||||
private String seoDescription = "";
|
||||
|
||||
@OneToOne
|
||||
private SeoPostData seoData;
|
||||
|
||||
@Type(type="text")
|
||||
private String permalink;
|
||||
|
||||
public void setPermalink(String permalink){
|
||||
String token = permalink.toLowerCase().replace("\n", " ").replaceAll("[^a-z\\d\\s]", " ");
|
||||
this.permalink = StringUtils.arrayToDelimitedString(StringUtils.tokenizeToStringArray(token, " "), "-");
|
||||
}
|
||||
|
||||
private Long visitsCount = 0L;
|
||||
public Long getVisitsCount() {
|
||||
if (this.visitsCount == null) return 0L;
|
||||
else return this.visitsCount;
|
||||
}
|
||||
|
||||
private Integer sympathyCount = 0;
|
||||
public Integer getSympathyCount() {
|
||||
if (this.sympathyCount == null) return 0;
|
||||
else return this.sympathyCount;
|
||||
}
|
||||
|
||||
@OneToMany(fetch = FetchType.LAZY, mappedBy = "post", cascade = CascadeType.REMOVE)
|
||||
private Collection<Comment> comments = new ArrayList<>();
|
||||
|
||||
@JsonInclude
|
||||
@Transient
|
||||
private Comment lastComment;
|
||||
|
||||
@Column(nullable = false, columnDefinition = "boolean DEFAULT false")
|
||||
private Boolean deletedMark;
|
||||
|
||||
@Column(nullable = false, columnDefinition = "boolean DEFAULT false")
|
||||
private Boolean censored;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package ru.bvn13.voidforum.models;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.Collection;
|
||||
|
||||
@Entity
|
||||
@Table(name = "privileges")
|
||||
@Getter
|
||||
@Setter
|
||||
public class Privilege extends BaseModel {
|
||||
|
||||
private String name;
|
||||
|
||||
@ManyToMany(fetch = FetchType.LAZY, mappedBy = "privileges")
|
||||
private Collection<Role> roles;
|
||||
|
||||
public Privilege() {}
|
||||
|
||||
public Privilege(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package ru.bvn13.voidforum.models;
|
||||
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.Collection;
|
||||
|
||||
@Entity
|
||||
@Table(name = "roles")
|
||||
@Getter
|
||||
@Setter
|
||||
public class Role extends BaseModel {
|
||||
|
||||
private String name;
|
||||
|
||||
@ManyToMany(fetch = FetchType.LAZY, mappedBy = "roles")
|
||||
private Collection<User> users;
|
||||
|
||||
@ManyToMany(fetch = FetchType.LAZY)
|
||||
@JoinTable(name = "roles_privileges",
|
||||
joinColumns = {@JoinColumn(name = "role_id", referencedColumnName = "id")},
|
||||
inverseJoinColumns = {@JoinColumn(name = "privilege_id", referencedColumnName = "id")}
|
||||
)
|
||||
private Collection<Privilege> privileges;
|
||||
|
||||
public Role() {}
|
||||
|
||||
public Role(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package ru.bvn13.voidforum.models;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import ru.bvn13.voidforum.models.support.OgLocale;
|
||||
import ru.bvn13.voidforum.models.support.OgType;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "seo_posts_data")
|
||||
@Getter
|
||||
@Setter
|
||||
public class SeoPostData extends BaseModel {
|
||||
|
||||
@OneToOne(fetch = FetchType.LAZY, mappedBy = "seoData", cascade = CascadeType.ALL)
|
||||
private Post post;
|
||||
|
||||
@Column
|
||||
private String ogTitle = "";
|
||||
|
||||
@Column
|
||||
@Enumerated(EnumType.STRING)
|
||||
private OgType ogType = OgType.ARTICLE;
|
||||
|
||||
@Column
|
||||
private String ogImage = "";
|
||||
|
||||
@Column
|
||||
private String ogVideo = "";
|
||||
|
||||
@Column
|
||||
@Enumerated(EnumType.STRING)
|
||||
private OgLocale ogLocale = OgLocale.en_EN;
|
||||
|
||||
/*@Column
|
||||
private String ogUrl;
|
||||
|
||||
@Column
|
||||
private String ogDescription;*/
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package ru.bvn13.voidforum.models;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "seo_robots_agents")
|
||||
@Getter
|
||||
@Setter
|
||||
public class SeoRobotAgent extends BaseModel {
|
||||
|
||||
@Column(nullable = false)
|
||||
private String userAgent;
|
||||
|
||||
@Column(nullable = false, columnDefinition = "boolean default false")
|
||||
private Boolean isRegexp;
|
||||
|
||||
public SeoRobotAgent() {
|
||||
|
||||
}
|
||||
|
||||
public SeoRobotAgent(String userAgent) {
|
||||
this.userAgent = userAgent;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package ru.bvn13.voidforum.models;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Lob;
|
||||
import javax.persistence.Table;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* A generic setting model
|
||||
*
|
||||
* bvn13 <mail4bvn@gmail.com>
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "settings")
|
||||
@Getter
|
||||
@Setter
|
||||
public class Setting extends BaseModel{
|
||||
|
||||
@Column(name = "_key", unique = true, nullable = false)
|
||||
private String key;
|
||||
|
||||
@Lob
|
||||
@Column(name = "_value")
|
||||
private Serializable value;
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package ru.bvn13.voidforum.models;
|
||||
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "stored_files")
|
||||
@Getter
|
||||
@Setter
|
||||
public class StoredFile extends BaseModel {
|
||||
|
||||
@ManyToOne
|
||||
private User user;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String title;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String path;
|
||||
|
||||
@Column(columnDefinition = "bigint default 0")
|
||||
private Long size;
|
||||
|
||||
public String getSizeFormatted() {
|
||||
double bytes = this.getSize();
|
||||
double kilobytes = (bytes / 1024);
|
||||
double megabytes = (kilobytes / 1024);
|
||||
double gigabytes = (megabytes / 1024);
|
||||
double terabytes = (gigabytes / 1024);
|
||||
double petabytes = (terabytes / 1024);
|
||||
double exabytes = (petabytes / 1024);
|
||||
double zettabytes = (exabytes / 1024);
|
||||
double yottabytes = (zettabytes / 1024);
|
||||
if (Math.floor(yottabytes) > 0d) {
|
||||
return String.format("%.3f Yb", yottabytes);
|
||||
} else if (Math.floor(zettabytes) > 0d) {
|
||||
return String.format("%.3f Zb", zettabytes);
|
||||
} else if (Math.floor(exabytes) > 0d) {
|
||||
return String.format("%.3f Eb", exabytes);
|
||||
} else if (Math.floor(petabytes) > 0d) {
|
||||
return String.format("%.3f Pb", petabytes);
|
||||
} else if (Math.floor(terabytes) > 0d) {
|
||||
return String.format("%.3f Tb", terabytes);
|
||||
} else if (Math.floor(gigabytes) > 0d) {
|
||||
return String.format("%.3f Gb", gigabytes);
|
||||
} else if (Math.floor(megabytes) > 0d) {
|
||||
return String.format("%.3f Mb", megabytes);
|
||||
} else if (Math.floor(kilobytes) > 0d) {
|
||||
return String.format("%.3f Kb", kilobytes);
|
||||
} else {
|
||||
return String.format("%d bytes", (int)bytes);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package ru.bvn13.voidforum.models;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* bvn13 <mail4bvn@gmail.com>.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "tags")
|
||||
@Getter
|
||||
@Setter
|
||||
public class Tag extends BaseModel {
|
||||
|
||||
@Column(nullable = false, unique = true)
|
||||
private String name;
|
||||
|
||||
@ManyToMany(fetch = FetchType.LAZY, mappedBy = "tags")
|
||||
private List<Post> posts = new ArrayList<>();
|
||||
|
||||
public Tag(){
|
||||
|
||||
}
|
||||
|
||||
public Tag(String name){
|
||||
this.setName(name);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package ru.bvn13.voidforum.models;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import ru.bvn13.voidforum.services.RoleService;
|
||||
import ru.bvn13.voidforum.services.UserService;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* bvn13 <mail4bvn@gmail.com>
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "users")
|
||||
@Getter
|
||||
@Setter
|
||||
public class User extends BaseModel {
|
||||
|
||||
@Column(unique = true)
|
||||
private String email;
|
||||
|
||||
@Column(unique = true)
|
||||
private String nickname;
|
||||
|
||||
@JsonIgnore
|
||||
private String password;
|
||||
|
||||
private Boolean disabled;
|
||||
|
||||
@ManyToMany(fetch = FetchType.LAZY)
|
||||
@JoinTable(name = "users_roles",
|
||||
joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")},
|
||||
inverseJoinColumns = {@JoinColumn(name = "role_id", referencedColumnName = "id")}
|
||||
)
|
||||
private Collection<Role> roles;
|
||||
|
||||
@OneToMany(fetch = FetchType.LAZY, mappedBy = "user", cascade = CascadeType.REMOVE)
|
||||
private Collection<Post> posts = new ArrayList<>();
|
||||
|
||||
@OneToMany(fetch = FetchType.LAZY, mappedBy = "user", cascade = CascadeType.REMOVE)
|
||||
private Collection<StoredFile> storedFiles = new ArrayList<>();
|
||||
|
||||
@OneToMany(fetch = FetchType.LAZY, mappedBy = "user", cascade = CascadeType.REMOVE)
|
||||
private Collection<Comment> comments = new ArrayList<>();
|
||||
|
||||
public User() {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
public Boolean isAdmin() {
|
||||
return UserService.hasRole(this, RoleService.ROLE_ADMIN) || UserService.hasRole(this, RoleService.ROLE_OWNER);
|
||||
}
|
||||
|
||||
public Boolean isOwner() {
|
||||
return UserService.hasRole(this, RoleService.ROLE_OWNER);
|
||||
}
|
||||
*/
|
||||
|
||||
public User(String email, String nickname, String password, String role) {
|
||||
this.email = email;
|
||||
this.nickname = nickname;
|
||||
this.password = password;
|
||||
this.roles.add(new Role(role));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package ru.bvn13.voidforum.models;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "visits")
|
||||
@Getter
|
||||
@Setter
|
||||
public class Visit extends BaseModel {
|
||||
|
||||
@ManyToOne
|
||||
private User user;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String clientIp;
|
||||
|
||||
@ManyToOne
|
||||
private Post post;
|
||||
|
||||
@Column(nullable = false, columnDefinition = "boolean default false")
|
||||
private Boolean isAdmin;
|
||||
|
||||
@Column
|
||||
private String userAgent;
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package ru.bvn13.voidforum.models.support;
|
||||
|
||||
public enum CommentFormat {
|
||||
|
||||
HTML("Html"),
|
||||
MARKDOWN("Markdown");
|
||||
|
||||
private String name;
|
||||
|
||||
CommentFormat(String name){
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName(){
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package ru.bvn13.voidforum.models.support;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
public class HttpContentTypeSerializer {
|
||||
|
||||
private static final Hashtable<String, String> variants = new Hashtable<String, String>();
|
||||
|
||||
private static final String defaultVariant = "application/octet-stream";
|
||||
|
||||
static {
|
||||
variants.put("aac", "audio/aac");
|
||||
variants.put("abw", "application/x-abiword");
|
||||
variants.put("", "");
|
||||
variants.put("", "");
|
||||
variants.put("", "");
|
||||
variants.put("", "");
|
||||
variants.put("", "");
|
||||
variants.put("", "");
|
||||
}
|
||||
|
||||
public static String getContentType(String fileName) {
|
||||
|
||||
if (fileName.isEmpty()) {
|
||||
return defaultVariant;
|
||||
}
|
||||
|
||||
String fileArray[]=fileName.split("\\.");
|
||||
|
||||
String extension = fileArray[fileArray.length-1];
|
||||
|
||||
if (variants.containsKey(extension)) {
|
||||
return variants.get(extension);
|
||||
}
|
||||
|
||||
return defaultVariant;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package ru.bvn13.voidforum.models.support;
|
||||
|
||||
public enum OgLocale {
|
||||
|
||||
en_EN("en_EN"),
|
||||
ru_RU("ru_RU");
|
||||
|
||||
private String name;
|
||||
|
||||
OgLocale(String name){
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getId(){
|
||||
return name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package ru.bvn13.voidforum.models.support;
|
||||
|
||||
public enum OgType {
|
||||
|
||||
WEBSITE("website"),
|
||||
ARTICLE("article");
|
||||
|
||||
private String name;
|
||||
|
||||
OgType(String name){
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName(){
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package ru.bvn13.voidforum.models.support;
|
||||
|
||||
/**
|
||||
* bvn13 <mail4bvn@gmail.com>
|
||||
*/
|
||||
public enum PostFormat {
|
||||
HTML("Html"),
|
||||
MARKDOWN("Markdown");
|
||||
|
||||
private String name;
|
||||
|
||||
PostFormat(String name){
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName(){
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package ru.bvn13.voidforum.models.support;
|
||||
|
||||
/**
|
||||
* bvn13 <mail4bvn@gmail.com>
|
||||
*/
|
||||
public enum PostStatus {
|
||||
DRAFT("Draft"),
|
||||
PUBLISHED("Published");
|
||||
|
||||
private String name;
|
||||
|
||||
PostStatus(String name){
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getId(){
|
||||
return name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package ru.bvn13.voidforum.models.support;
|
||||
|
||||
/**
|
||||
* bvn13 <mail4bvn@gmail.com>
|
||||
*/
|
||||
public enum PostType {
|
||||
PAGE("Page"),
|
||||
POST("Post");
|
||||
|
||||
private String name;
|
||||
|
||||
PostType(String name){
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getId(){
|
||||
return name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package ru.bvn13.voidforum.models.support;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class WebError implements Serializable {
|
||||
|
||||
private String field;
|
||||
|
||||
private String errorMessage;
|
||||
|
||||
public WebError(String field, String errorMessage) {
|
||||
this.field = field;
|
||||
this.errorMessage = errorMessage;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package ru.bvn13.voidforum.repositories;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import ru.bvn13.voidforum.models.Comment;
|
||||
import ru.bvn13.voidforum.models.Post;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface CommentRepository extends JpaRepository<Comment, Long> {
|
||||
List<Comment> findAllByPostOrderById(Post post);
|
||||
List<Comment> findAllByPostAndParentCommentOrderById(Post post, Comment parentComment);
|
||||
|
||||
List<Comment> findAllByPostAndDeletedMarkOrderById(Post post, Boolean deletedMark);
|
||||
List<Comment> findAllByPostAndParentCommentAndDeletedMarkOrderById(Post post, Comment parentComment, Boolean deletedMark);
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package ru.bvn13.voidforum.repositories;
|
||||
|
||||
import ru.bvn13.voidforum.models.Like;
|
||||
import ru.bvn13.voidforum.models.Post;
|
||||
import ru.bvn13.voidforum.models.User;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface LikeRepository extends JpaRepository<Like, Long> {
|
||||
|
||||
@Query("SELECT SUM(l.sympathy) FROM Like AS l WHERE l.user = :user AND l.post = :post GROUP BY l.user, l.post")
|
||||
Integer getTotalLikesByUserAndPost(@Param("user") User user, @Param("post") Post post);
|
||||
|
||||
@Query("SELECT SUM(l.sympathy) FROM Like AS l WHERE l.post = :post GROUP BY l.post")
|
||||
Integer getTotalLikesByPost(@Param("post") Post post);
|
||||
|
||||
@Query("SELECT SUM(l.sympathy) FROM Like AS l WHERE l.clientIp = :clientIp AND l.post = :post GROUP BY l.clientIp, l.post")
|
||||
Integer getTotalLikesByClientIpAndPost(@Param("clientIp") String clientIp, @Param("post") Post post);
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package ru.bvn13.voidforum.repositories;
|
||||
|
||||
import ru.bvn13.voidforum.models.Post;
|
||||
import ru.bvn13.voidforum.models.User;
|
||||
import ru.bvn13.voidforum.models.support.PostStatus;
|
||||
import ru.bvn13.voidforum.models.support.PostType;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* bvn13 <mail4bvn@gmail.com>
|
||||
*/
|
||||
@Repository
|
||||
@Transactional
|
||||
public interface PostRepository extends JpaRepository<Post, Long> {
|
||||
Post findByPermalinkAndPostStatus(String permalink, PostStatus postStatus);
|
||||
|
||||
Post findByIdAndPostStatus(Long postId, PostStatus postStatus);
|
||||
|
||||
Page<Post> findAllByPostType(PostType postType, Pageable pageRequest);
|
||||
|
||||
Page<Post> findAllByPostTypeAndPostStatus(PostType postType, PostStatus postStatus, Pageable pageRequest);
|
||||
|
||||
Page<Post> findAllByPostTypeAndPostStatusAndDeletedMarkAndCensored(PostType postType, PostStatus postStatus, Boolean deletedMark, Boolean censored, Pageable pageRequest);
|
||||
|
||||
List<Post> findAllByPostTypeAndPostStatus(PostType postType, PostStatus postStatus);
|
||||
|
||||
@Query("SELECT p FROM Post p INNER JOIN p.tags t WHERE t.name = :tag")
|
||||
Page<Post> findByTag(@Param("tag") String tag, Pageable pageable);
|
||||
|
||||
@Query("SELECT t.name, count(p) as tag_count from Post p " +
|
||||
"INNER JOIN p.tags t " +
|
||||
"WHERE p.postStatus = :status " +
|
||||
"GROUP BY t.id " +
|
||||
"ORDER BY tag_count DESC")
|
||||
List<Object[]> countPostsByTags(@Param("status") PostStatus status);
|
||||
|
||||
Page<Post> findAllByPostTypeAndPostStatusAndDeletedMark(PostType postType, PostStatus postStatus, Boolean deletedMark, Pageable pageRequest);
|
||||
|
||||
Page<Post> findAllByUser(User user, Pageable pageRequest);
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package ru.bvn13.voidforum.repositories;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import ru.bvn13.voidforum.models.Privilege;
|
||||
import ru.bvn13.voidforum.models.Role;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public interface PrivilegeRepository extends JpaRepository<Privilege, Long> {
|
||||
Privilege findByName(String name);
|
||||
@Query("SELECT p FROM Privilege AS p " +
|
||||
"INNER JOIN p.roles AS r " +
|
||||
"WHERE r = :role")
|
||||
List<Privilege> findAllByRole(@Param("role") Role role);
|
||||
/*@Query("SELECT p FROM Privilege AS p " +
|
||||
"INNER JOIN p.roles AS r " +
|
||||
"WHERE r IN :roles")
|
||||
List<Privilege> findAllByRolesList(@Param("roles") Collection<Role> roles);*/
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package ru.bvn13.voidforum.repositories;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import ru.bvn13.voidforum.models.Role;
|
||||
import ru.bvn13.voidforum.models.User;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface RoleRepository extends JpaRepository<Role, Long> {
|
||||
Role findByName(String role_name);
|
||||
@Query("SELECT r FROM Role AS r " +
|
||||
"INNER JOIN r.users AS u " +
|
||||
"WHERE u = :user")
|
||||
List<Role> findAllByUser(@Param("user") User user);
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package ru.bvn13.voidforum.repositories;
|
||||
|
||||
import ru.bvn13.voidforum.models.SeoPostData;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface SeoPostDataRepository extends JpaRepository<SeoPostData, Long> {
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package ru.bvn13.voidforum.repositories;
|
||||
|
||||
import ru.bvn13.voidforum.models.SeoRobotAgent;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface SeoRobotAgentRepository extends JpaRepository<SeoRobotAgent, Long> {
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package ru.bvn13.voidforum.repositories;
|
||||
|
||||
import ru.bvn13.voidforum.models.Setting;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* bvn13 <mail4bvn@gmail.com>
|
||||
*/
|
||||
@Repository
|
||||
@Transactional
|
||||
public interface SettingRepository extends JpaRepository<Setting, Long> {
|
||||
Setting findByKey(String key);
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package ru.bvn13.voidforum.repositories;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import ru.bvn13.voidforum.models.StoredFile;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import ru.bvn13.voidforum.models.User;
|
||||
|
||||
@Repository
|
||||
public interface StoredFileRepository extends JpaRepository<StoredFile, Long> {
|
||||
StoredFile findById(Long id);
|
||||
StoredFile findByName(String name);
|
||||
Page<StoredFile> findAllByUserOrderByIdDesc(User user, Pageable pageRequest);
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package ru.bvn13.voidforum.repositories;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import ru.bvn13.voidforum.models.Tag;
|
||||
|
||||
/**
|
||||
* bvn13 <mail4bvn@gmail.com>.
|
||||
*/
|
||||
public interface TagRepository extends JpaRepository<Tag, Long> {
|
||||
Tag findByName(String name);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package ru.bvn13.voidforum.repositories;
|
||||
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import ru.bvn13.voidforum.models.Role;
|
||||
import ru.bvn13.voidforum.models.User;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* bvn13 <mail4bvn@gmail.com>
|
||||
*/
|
||||
@Repository
|
||||
@Transactional
|
||||
public interface UserRepository extends JpaRepository<User, Long> {
|
||||
User findByEmail(String email);
|
||||
User findByNickname(String nickname);
|
||||
@Query("SELECT u FROM User AS u " +
|
||||
"INNER JOIN u.roles AS r " +
|
||||
"WHERE r.name = :roleName")
|
||||
List<User> findAllByOneRoleByNameOrderById(@Param("roleName") String rname);
|
||||
@Query("SELECT u FROM User AS u " +
|
||||
"INNER JOIN u.roles AS r " +
|
||||
"WHERE r = :role")
|
||||
List<User> findAllByOneRoleOrderById(@Param("role") Role role);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package ru.bvn13.voidforum.repositories;
|
||||
|
||||
import ru.bvn13.voidforum.models.Post;
|
||||
import ru.bvn13.voidforum.models.Visit;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface VisitRepository extends JpaRepository<Visit, Long> {
|
||||
|
||||
@Query( "SELECT COUNT(DISTINCT v.clientIp) " +
|
||||
"FROM Visit AS v " +
|
||||
//"LEFT JOIN v.robotsAgents AS ra " +
|
||||
//"ON v.userAgent LIKE concat('%', ra.userAgent, '%') "+
|
||||
"WHERE v.post = :post AND v.isAdmin = FALSE " //+
|
||||
//"AND ra.id IS NULL "
|
||||
)
|
||||
Long getUniquePostVisitsCount(@Param("post") Post post);
|
||||
|
||||
@Query( "SELECT v.clientIp, NULLIF(v.userAgent, '') " +
|
||||
"FROM Visit AS v " +
|
||||
"WHERE v.post = :post AND v.isAdmin = FALSE " +
|
||||
"GROUP BY v.clientIp, NULLIF(v.userAgent, '') "
|
||||
)
|
||||
List<Object> getVisitsByPostAndIsAdminIsFalse(@Param("post") Post post);
|
||||
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package ru.bvn13.voidforum.services;
|
||||
|
||||
import com.domingosuarez.boot.autoconfigure.jade4j.JadeHelper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* bvn13 <mail4bvn@gmail.com>
|
||||
*/
|
||||
@JadeHelper("App")
|
||||
@Service
|
||||
public class AppSetting {
|
||||
|
||||
private SettingService settingService;
|
||||
|
||||
private String siteName = "void Forum();";
|
||||
private String siteSlogan = "An interesting place to discover";
|
||||
private Integer pageSize = 5;
|
||||
private String storagePath = "/tmp";
|
||||
private String mainUri = "http://localhost/";
|
||||
|
||||
public static final String SITE_NAME = "site_name";
|
||||
public static final String SITE_SLOGAN = "site_slogan";
|
||||
public static final String PAGE_SIZE = "page_size";
|
||||
public static final String STORAGE_PATH = "storage_path";
|
||||
public static final String MAIN_URI = "main_uri";
|
||||
|
||||
@Autowired
|
||||
public AppSetting(SettingService settingService){
|
||||
this.settingService = settingService;
|
||||
}
|
||||
|
||||
public String getSiteName(){
|
||||
return (String) settingService.get(SITE_NAME, siteName);
|
||||
}
|
||||
|
||||
public void setSiteName(String siteName) {
|
||||
this.siteName = siteName;
|
||||
settingService.put(SITE_NAME, siteName);
|
||||
}
|
||||
|
||||
public Integer getPageSize() {
|
||||
return (Integer) settingService.get(PAGE_SIZE, pageSize);
|
||||
}
|
||||
|
||||
public void setPageSize(Integer pageSize) {
|
||||
this.pageSize = pageSize;
|
||||
settingService.put(PAGE_SIZE, pageSize);
|
||||
}
|
||||
|
||||
public String getSiteSlogan() {
|
||||
return (String) settingService.get(SITE_SLOGAN, siteSlogan);
|
||||
}
|
||||
|
||||
public void setSiteSlogan(String siteSlogan) {
|
||||
this.siteSlogan = siteSlogan;
|
||||
settingService.put(SITE_SLOGAN, siteSlogan);
|
||||
}
|
||||
|
||||
public String getStoragePath() {
|
||||
return (String) settingService.get(STORAGE_PATH, storagePath);
|
||||
}
|
||||
|
||||
public void setStoragePath(String storagePath) {
|
||||
this.storagePath = storagePath;
|
||||
settingService.put(STORAGE_PATH, storagePath);
|
||||
}
|
||||
|
||||
public String getMainUri() {
|
||||
return (String) settingService.get(MAIN_URI, mainUri);
|
||||
}
|
||||
|
||||
public void setMainUri(String mainUri) {
|
||||
this.mainUri = mainUri;
|
||||
settingService.put(MAIN_URI, mainUri);
|
||||
}
|
||||
|
||||
public List<String> getOgLocales() {
|
||||
ArrayList<String> ogLocales = new ArrayList<>();
|
||||
ogLocales.add("en_EN");
|
||||
ogLocales.add("ru_RU");
|
||||
return ogLocales;
|
||||
}
|
||||
|
||||
public List<String> getOgTypes() {
|
||||
ArrayList<String> ogTypes = new ArrayList<>();
|
||||
ogTypes.add("article");
|
||||
return ogTypes;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package ru.bvn13.voidforum.services;
|
||||
|
||||
import ru.bvn13.voidforum.models.Setting;
|
||||
import ru.bvn13.voidforum.repositories.SettingRepository;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* bvn13 <mail4bvn@gmail.com>
|
||||
*/
|
||||
@Service
|
||||
public class CacheSettingService implements SettingService {
|
||||
|
||||
private SettingRepository settingRepository;
|
||||
|
||||
private static final String CACHE_NAME = "cache.settings";
|
||||
|
||||
@Autowired
|
||||
public CacheSettingService(SettingRepository settingRepository) {
|
||||
this.settingRepository = settingRepository;
|
||||
}
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SettingService.class);
|
||||
|
||||
@Override
|
||||
public Serializable get(String key) {
|
||||
Setting setting = settingRepository.findByKey(key);
|
||||
Serializable value = null;
|
||||
try {
|
||||
value = setting == null ? null : setting.getValue();
|
||||
} catch (Exception ex) {
|
||||
logger.info("Cannot deserialize setting value with key = " + key);
|
||||
}
|
||||
|
||||
logger.info("Get setting " + key + " from database. Value = " + value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = CACHE_NAME, key = "#key")
|
||||
public Serializable get(String key, Serializable defaultValue) {
|
||||
Serializable value = get(key);
|
||||
return value == null ? defaultValue : value;
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheEvict(value = CACHE_NAME, key = "#key")
|
||||
public void put(String key, Serializable value) {
|
||||
logger.info("Update setting " + key + " to database. Value = " + value);
|
||||
|
||||
Setting setting = settingRepository.findByKey(key);
|
||||
if (setting == null) {
|
||||
setting = new Setting();
|
||||
setting.setKey(key);
|
||||
}
|
||||
try {
|
||||
setting.setValue(value);
|
||||
settingRepository.save(setting);
|
||||
} catch (Exception ex) {
|
||||
|
||||
logger.info("Cannot save setting value with type: " + value.getClass() + ". key = " + key);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
package ru.bvn13.voidforum.services;
|
||||
|
||||
import com.domingosuarez.boot.autoconfigure.jade4j.JadeHelper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ru.bvn13.voidforum.models.Comment;
|
||||
import ru.bvn13.voidforum.models.Post;
|
||||
import ru.bvn13.voidforum.models.User;
|
||||
import ru.bvn13.voidforum.models.support.CommentFormat;
|
||||
import ru.bvn13.voidforum.repositories.CommentRepository;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* Created by bvn13 on 09.12.2017.
|
||||
*/
|
||||
@JadeHelper("commentService")
|
||||
//@Service
|
||||
public class CommentService {
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Autowired
|
||||
private CommentRepository commentRepository;
|
||||
|
||||
|
||||
private static Comparator<Comment> commentComparator = new Comparator<Comment>() {
|
||||
@Override
|
||||
public int compare(Comment o1, Comment o2) {
|
||||
return o1.getId().compareTo(o2.getId());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public List<Comment> getCommentsForPost(Post post) {
|
||||
List<Comment> availableComments = null;
|
||||
//User user = userService.currentUser();
|
||||
//if (userService.hasPrivilege(user, PrivilegeService.PRIVILEGE_WRITE)) {
|
||||
availableComments = commentRepository.findAllByPostOrderById(post);
|
||||
//} else {
|
||||
// availableComments = commentRepository.findAllByPostAndDeletedMarkOrderById(post, false);
|
||||
//}
|
||||
return availableComments;
|
||||
}
|
||||
|
||||
public List<Comment> filterListByParentComment(List<Comment> comments, Comment parent) {
|
||||
List<Comment> children = new ArrayList<>();
|
||||
comments.forEach(c -> {
|
||||
if (c.getParentComment().getId().equals(parent.getId())) {
|
||||
children.add(c);
|
||||
}
|
||||
});
|
||||
Collections.sort(children, CommentService.commentComparator);
|
||||
return children;
|
||||
}
|
||||
|
||||
public Integer childrenCount(List<Comment> comments, Comment parent) {
|
||||
AtomicReference<Integer> count = new AtomicReference<>();
|
||||
comments.forEach(c -> {
|
||||
if (c.getParentComment().getId().equals(parent.getId())) {
|
||||
Integer old = count.get();
|
||||
count.set(old+1);
|
||||
}
|
||||
});
|
||||
return count.get();
|
||||
}
|
||||
|
||||
public List<CommentFormat> getAvailableCommentFormats() {
|
||||
List<CommentFormat> formats = new ArrayList<>();
|
||||
User user = userService.currentUser();
|
||||
for (CommentFormat f : CommentFormat.values()) {
|
||||
if (f.equals(CommentFormat.HTML)) {
|
||||
if (userService.hasPrivilege(user, PrivilegeService.PRIVILEGE_WRITE_HTML)) {
|
||||
formats.add(f);
|
||||
}
|
||||
} else {
|
||||
formats.add(f);
|
||||
}
|
||||
}
|
||||
return formats;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
package ru.bvn13.voidforum.services;
|
||||
|
||||
|
||||
import ru.bvn13.voidforum.error.NotFoundException;
|
||||
import ru.bvn13.voidforum.models.StoredFile;
|
||||
import ru.bvn13.voidforum.models.User;
|
||||
import ru.bvn13.voidforum.models.support.HttpContentTypeSerializer;
|
||||
import ru.bvn13.voidforum.repositories.StoredFileRepository;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
@Service
|
||||
public class FileStorageService {
|
||||
|
||||
public static final Logger logger = LoggerFactory.getLogger(FileStorageService.class);
|
||||
|
||||
private AppSetting appSetting;
|
||||
|
||||
private StoredFileRepository repository;
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Autowired
|
||||
public FileStorageService(StoredFileRepository repository, AppSetting appSetting) {
|
||||
this.repository = repository;
|
||||
this.appSetting = appSetting;
|
||||
logger.debug("== UPLOAD PATH == > "+appSetting.getStoragePath());
|
||||
}
|
||||
|
||||
public StoredFile getFileById(Long id) {
|
||||
return repository.findById(id);
|
||||
}
|
||||
|
||||
public StoredFile getFileByName(String fileName) {
|
||||
StoredFile file = null;
|
||||
|
||||
file = repository.findByName(fileName);
|
||||
if (file == null) {
|
||||
if (fileName.matches("\\d+")) {
|
||||
file = this.getFileById(Long.valueOf(fileName));
|
||||
}
|
||||
}
|
||||
|
||||
if (file == null) {
|
||||
throw new NotFoundException("File " + fileName + " is not found");
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
public void storeFile(User user, String filename, byte[] content) throws IOException {
|
||||
File storage = new File(appSetting.getStoragePath());
|
||||
if (!storage.exists()) {
|
||||
storage.mkdirs();
|
||||
}
|
||||
String separator = "";
|
||||
if (!appSetting.getStoragePath().endsWith("/")) {
|
||||
separator = "/";
|
||||
}
|
||||
String userFolder = appSetting.getStoragePath() + separator + user.getId() + "/";
|
||||
File userStorage = new File(userFolder);
|
||||
if (!userStorage.exists()) {
|
||||
userStorage.mkdirs();
|
||||
}
|
||||
|
||||
String fullname = userFolder + filename;
|
||||
Path path = Paths.get(fullname);
|
||||
Files.write(path, content);
|
||||
|
||||
File file = new File(fullname);
|
||||
|
||||
StoredFile storedFile = new StoredFile();
|
||||
storedFile.setPath(path.toAbsolutePath().toString());
|
||||
storedFile.setUser(this.userService.currentUser());
|
||||
storedFile.setTitle(filename);
|
||||
storedFile.setName(filename);
|
||||
storedFile.setSize(file.length());
|
||||
|
||||
this.repository.saveAndFlush(storedFile);
|
||||
}
|
||||
|
||||
public byte[] getFileContentById(Long fileId) throws IOException {
|
||||
StoredFile storedFile = this.repository.findById(fileId);
|
||||
Path path = Paths.get(storedFile.getPath());
|
||||
return Files.readAllBytes(path);
|
||||
}
|
||||
|
||||
public byte[] getFileContent(String fullname) throws IOException {
|
||||
Path path = Paths.get(fullname);
|
||||
return Files.readAllBytes(path);
|
||||
}
|
||||
|
||||
public void deleteFileById(Long fileId) throws IOException {
|
||||
StoredFile storedFile = this.repository.findById(fileId);
|
||||
Path path = Paths.get(storedFile.getPath());
|
||||
// first delete info, second delete file
|
||||
// because file might be deleted already
|
||||
this.repository.delete(storedFile);
|
||||
Files.delete(path);
|
||||
}
|
||||
|
||||
public String getContentType(String fileName) {
|
||||
return HttpContentTypeSerializer.getContentType(fileName);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package ru.bvn13.voidforum.services;
|
||||
|
||||
import ru.bvn13.voidforum.models.Like;
|
||||
import ru.bvn13.voidforum.models.Post;
|
||||
import ru.bvn13.voidforum.models.User;
|
||||
import ru.bvn13.voidforum.repositories.LikeRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class LikeService {
|
||||
|
||||
@Autowired
|
||||
private LikeRepository likeRepository;
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
|
||||
public Integer getTotalLikesByPost(Post post) {
|
||||
return this.likeRepository.getTotalLikesByPost(post);
|
||||
}
|
||||
|
||||
public Integer getTotalLikesByUserAndPost(User user, Post post) {
|
||||
return this.likeRepository.getTotalLikesByUserAndPost(user, post);
|
||||
}
|
||||
|
||||
public void likePost(Post post, String clientIp) {
|
||||
User user = this.userService.currentUser();
|
||||
Integer currentSympathy = 0;
|
||||
|
||||
if (user != null) {
|
||||
currentSympathy = this.likeRepository.getTotalLikesByUserAndPost(user, post);
|
||||
} else {
|
||||
currentSympathy = this.likeRepository.getTotalLikesByClientIpAndPost(clientIp, post);
|
||||
}
|
||||
if (currentSympathy == null) currentSympathy = 0;
|
||||
|
||||
Integer sympathyDelta = -currentSympathy + 1;
|
||||
this.saveSympathy(post, user, clientIp, sympathyDelta);
|
||||
}
|
||||
|
||||
public void dislikePost(Post post, String clientIp) {
|
||||
User user = this.userService.currentUser();
|
||||
Integer currentSympathy = 0;
|
||||
|
||||
if (user != null) {
|
||||
currentSympathy = this.likeRepository.getTotalLikesByUserAndPost(user, post);
|
||||
} else {
|
||||
currentSympathy = this.likeRepository.getTotalLikesByClientIpAndPost(clientIp, post);
|
||||
}
|
||||
if (currentSympathy == null) currentSympathy = 0;
|
||||
|
||||
Integer sympathyDelta = -currentSympathy - 1;
|
||||
this.saveSympathy(post, user, clientIp, sympathyDelta);
|
||||
}
|
||||
|
||||
private void saveSympathy(Post post, User user, String clientIp, Integer sympathy) {
|
||||
Like like = new Like();
|
||||
like.setClientIp(clientIp);
|
||||
like.setPost(post);
|
||||
like.setUser(user);
|
||||
like.setIsAdmin(user != null ? userService.hasPrivilege(user, PrivilegeService.PRIVILEGE_ADMIN) : false);
|
||||
like.setSympathy(sympathy);
|
||||
this.likeRepository.save(like);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,359 @@
|
|||
package ru.bvn13.voidforum.services;
|
||||
|
||||
import ru.bvn13.voidforum.Constants;
|
||||
import ru.bvn13.voidforum.error.NotFoundException;
|
||||
import ru.bvn13.voidforum.models.Post;
|
||||
import ru.bvn13.voidforum.models.SeoPostData;
|
||||
import ru.bvn13.voidforum.models.Tag;
|
||||
import ru.bvn13.voidforum.models.support.PostFormat;
|
||||
import ru.bvn13.voidforum.models.support.PostStatus;
|
||||
import ru.bvn13.voidforum.models.support.PostType;
|
||||
import ru.bvn13.voidforum.repositories.PostRepository;
|
||||
import ru.bvn13.voidforum.repositories.SeoPostDataRepository;
|
||||
import ru.bvn13.voidforum.support.web.MarkdownService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.cache.annotation.Caching;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* bvn13 <mail4bvn@gmail.com>.
|
||||
*/
|
||||
@Service
|
||||
public class PostService {
|
||||
@Autowired
|
||||
private PostRepository postRepository;
|
||||
|
||||
@Autowired
|
||||
private TagService tagService;
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Autowired
|
||||
private MarkdownService markdownService;
|
||||
|
||||
@Autowired
|
||||
private LikeService likeService;
|
||||
|
||||
@Autowired
|
||||
private VisitService visitService;
|
||||
|
||||
@Autowired
|
||||
private SeoPostDataRepository seoPostDataRepository;
|
||||
|
||||
|
||||
public static final String CACHE_NAME = "cache.post";
|
||||
public static final String CACHE_NAME_ARCHIVE = CACHE_NAME + ".archive";
|
||||
public static final String CACHE_NAME_PAGE = CACHE_NAME + ".page";
|
||||
public static final String CACHE_NAME_TAGS = CACHE_NAME + ".tag";
|
||||
public static final String CACHE_NAME_SEO_KEYWORDS = CACHE_NAME + ".seoKeyword";
|
||||
public static final String CACHE_NAME_COUNTS = CACHE_NAME + ".counts_tags";
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PostService.class);
|
||||
|
||||
@Cacheable(CACHE_NAME)
|
||||
public Post getPost(Long postId) {
|
||||
logger.debug("Get post " + postId);
|
||||
|
||||
Post post = postRepository.findOne(postId);
|
||||
|
||||
if (post == null) {
|
||||
throw new NotFoundException("Post with id " + postId + " is not found.");
|
||||
}
|
||||
|
||||
return post;
|
||||
}
|
||||
|
||||
@Cacheable(CACHE_NAME)
|
||||
public Post getPublishedPost(Long postId) {
|
||||
logger.debug("Get published post " + postId);
|
||||
|
||||
Post post = this.postRepository.findByIdAndPostStatus(postId, PostStatus.PUBLISHED);
|
||||
|
||||
if (post == null) {
|
||||
throw new NotFoundException("Post with id " + postId + " is not found.");
|
||||
}
|
||||
|
||||
return post;
|
||||
}
|
||||
|
||||
@Cacheable(CACHE_NAME)
|
||||
public Post getPublishedPostByPermalink(String permalink) {
|
||||
logger.debug("Get post with permalink " + permalink);
|
||||
|
||||
Post post = postRepository.findByPermalinkAndPostStatus(permalink, PostStatus.PUBLISHED);
|
||||
|
||||
if (post == null) {
|
||||
throw new NotFoundException("Post with permalink '" + permalink + "' is not found.");
|
||||
}
|
||||
|
||||
return post;
|
||||
}
|
||||
|
||||
@Caching(evict = {
|
||||
@CacheEvict(value = CACHE_NAME_ARCHIVE, allEntries = true),
|
||||
@CacheEvict(value = CACHE_NAME_PAGE, allEntries = true),
|
||||
@CacheEvict(value = CACHE_NAME_COUNTS, allEntries = true)
|
||||
})
|
||||
public Post createPost(Post post) {
|
||||
return this.savePost(post);
|
||||
}
|
||||
|
||||
@Caching(evict = {
|
||||
@CacheEvict(value = CACHE_NAME, key = "#post.id"),
|
||||
@CacheEvict(value = CACHE_NAME, key = "#post.permalink", condition = "#post.permalink != null"),
|
||||
@CacheEvict(value = CACHE_NAME_TAGS, key = "#post.id.toString().concat('-tags')"),
|
||||
@CacheEvict(value = CACHE_NAME_SEO_KEYWORDS, key = "#post.id.toString().concat('-seoKeywords')"),
|
||||
@CacheEvict(value = CACHE_NAME_ARCHIVE, allEntries = true),
|
||||
@CacheEvict(value = CACHE_NAME_PAGE, allEntries = true),
|
||||
@CacheEvict(value = CACHE_NAME_COUNTS, allEntries = true)
|
||||
})
|
||||
public Post updatePost(Post post) {
|
||||
return this.savePost(post);
|
||||
}
|
||||
|
||||
|
||||
private Post savePost(Post post) {
|
||||
if (post.getPostFormat() == PostFormat.MARKDOWN) {
|
||||
post.setRenderedContent(String.format("<div class=\"markdown-post\">%s</div>", markdownService.renderToHtml(post.getContent())));
|
||||
} else {
|
||||
post.setRenderedContent(String.format("<div class=\"html-post\">%s</div>", post.getContent()));
|
||||
}
|
||||
this.saveSeoData(post);
|
||||
return postRepository.save(post);
|
||||
}
|
||||
|
||||
@Caching(evict = {
|
||||
@CacheEvict(value = CACHE_NAME, key = "#post.id"),
|
||||
@CacheEvict(value = CACHE_NAME, key = "#post.permalink", condition = "#post.permalink != null"),
|
||||
@CacheEvict(value = CACHE_NAME_TAGS, key = "#post.id.toString().concat('-tags')"),
|
||||
@CacheEvict(value = CACHE_NAME_SEO_KEYWORDS, key = "#post.id.toString().concat('-seoKeywords')"),
|
||||
@CacheEvict(value = CACHE_NAME_ARCHIVE, allEntries = true),
|
||||
@CacheEvict(value = CACHE_NAME_PAGE, allEntries = true),
|
||||
@CacheEvict(value = CACHE_NAME_COUNTS, allEntries = true)
|
||||
})
|
||||
public void deletePost(Post post) {
|
||||
post.setDeletedMark(!post.getDeletedMark());
|
||||
postRepository.save(post);
|
||||
}
|
||||
|
||||
public void censorePost(Post post) {
|
||||
post.setCensored(!post.getCensored());
|
||||
postRepository.save(post);
|
||||
}
|
||||
|
||||
@Cacheable(value = CACHE_NAME_ARCHIVE, key = "#root.method.name")
|
||||
public List<Post> getArchivePosts() {
|
||||
logger.debug("Get all archive posts from database.");
|
||||
|
||||
Iterable<Post> posts = postRepository.findAllByPostTypeAndPostStatus(
|
||||
PostType.POST,
|
||||
PostStatus.PUBLISHED,
|
||||
new PageRequest(0, Integer.MAX_VALUE, Sort.Direction.DESC, "createdAt"));
|
||||
|
||||
List<Post> cachedPosts = new ArrayList<>();
|
||||
posts.forEach(post -> cachedPosts.add(extractPostMeta(post)));
|
||||
|
||||
return cachedPosts;
|
||||
}
|
||||
|
||||
@Cacheable(value = CACHE_NAME_TAGS, key = "#post.id.toString().concat('-tags')")
|
||||
public List<Tag> getPostTags(Post post) {
|
||||
logger.debug("Get tags of post " + post.getId());
|
||||
|
||||
List<Tag> tags = new ArrayList<>();
|
||||
|
||||
// Load the post first. If not, when the post is cached before while the tags not,
|
||||
// then the LAZY loading of post tags will cause an initialization error because
|
||||
// of not hibernate connection session
|
||||
postRepository.findOne(post.getId()).getTags().forEach(tags::add);
|
||||
return tags;
|
||||
}
|
||||
|
||||
@Cacheable(value = CACHE_NAME_SEO_KEYWORDS, key = "#post.id.toString().concat('-seoKeywords')")
|
||||
public String getSeoKeywordsAsString(Post post) {
|
||||
logger.debug("Get seoKeywordsAsString of post " + post.getId());
|
||||
|
||||
return post.getSeoKeywords();
|
||||
}
|
||||
|
||||
private Post extractPostMeta(Post post) {
|
||||
Post archivePost = new Post();
|
||||
archivePost.setId(post.getId());
|
||||
archivePost.setTitle(post.getTitle());
|
||||
archivePost.setPermalink(post.getPermalink());
|
||||
archivePost.setCreatedAt(post.getCreatedAt());
|
||||
|
||||
archivePost.setSympathyCount(this.likeService.getTotalLikesByPost(post));
|
||||
archivePost.setVisitsCount(this.visitService.getUniqueVisitsCount(post));
|
||||
|
||||
return archivePost;
|
||||
}
|
||||
|
||||
@Cacheable(value = CACHE_NAME_PAGE, key = "T(java.lang.String).valueOf(#page).concat('-').concat(#pageSize)")
|
||||
public Page<Post> getAllPublishedPostsByPage(int page, int pageSize) {
|
||||
logger.debug("Get posts by page " + page);
|
||||
|
||||
Page<Post> posts = postRepository.findAllByPostTypeAndPostStatus(
|
||||
PostType.POST,
|
||||
PostStatus.PUBLISHED,
|
||||
new PageRequest(page, pageSize, Sort.Direction.DESC, "createdAt"));
|
||||
|
||||
posts.forEach(p -> {
|
||||
p.setSympathyCount(this.likeService.getTotalLikesByPost(p));
|
||||
p.setVisitsCount(this.visitService.getUniqueVisitsCount(p));
|
||||
});
|
||||
|
||||
return posts;
|
||||
}
|
||||
|
||||
@Cacheable(value = CACHE_NAME_PAGE, key = "T(java.lang.String).valueOf(#page).concat('-').concat(#pageSize)")
|
||||
public Page<Post> getAllPublishedNotDeletedPostsByPage(int page, int pageSize) {
|
||||
logger.debug("Get not deleted posts by page " + page);
|
||||
|
||||
Page<Post> posts = postRepository.findAllByPostTypeAndPostStatusAndDeletedMark(
|
||||
PostType.POST,
|
||||
PostStatus.PUBLISHED,
|
||||
false,
|
||||
new PageRequest(page, pageSize, Sort.Direction.DESC, "createdAt"));
|
||||
|
||||
posts.forEach(p -> {
|
||||
p.setSympathyCount(this.likeService.getTotalLikesByPost(p));
|
||||
p.setVisitsCount(this.visitService.getUniqueVisitsCount(p));
|
||||
});
|
||||
|
||||
return posts;
|
||||
}
|
||||
|
||||
@Cacheable(value = CACHE_NAME_PAGE, key = "T(java.lang.String).valueOf(#page).concat('-').concat(#pageSize)")
|
||||
public Page<Post> getAllPublishedNotCensoredNotDeletedPostsByPage(int page, int pageSize) {
|
||||
logger.debug("Get not censored posts by page " + page);
|
||||
|
||||
Page<Post> posts = postRepository.findAllByPostTypeAndPostStatusAndDeletedMarkAndCensored(
|
||||
PostType.POST,
|
||||
PostStatus.PUBLISHED,
|
||||
false, false,
|
||||
new PageRequest(page, pageSize, Sort.Direction.DESC, "createdAt"));
|
||||
|
||||
posts.forEach(p -> {
|
||||
p.setSympathyCount(this.likeService.getTotalLikesByPost(p));
|
||||
p.setVisitsCount(this.visitService.getUniqueVisitsCount(p));
|
||||
});
|
||||
|
||||
return posts;
|
||||
}
|
||||
|
||||
|
||||
public List<Post> getAllPublishedPosts() {
|
||||
logger.debug("Get all published posts");
|
||||
|
||||
return this.postRepository.findAllByPostTypeAndPostStatus(PostType.POST, PostStatus.PUBLISHED);
|
||||
}
|
||||
|
||||
// public Post createAboutPage() {
|
||||
// logger.debug("Create default about page");
|
||||
//
|
||||
// Post post = new Post();
|
||||
// post.setTitle(Constants.ABOUT_PAGE_PERMALINK);
|
||||
// post.setContent(Constants.ABOUT_PAGE_PERMALINK.toLowerCase());
|
||||
// post.setPermalink(Constants.ABOUT_PAGE_PERMALINK);
|
||||
// post.setUser(userService.getSuperUser());
|
||||
// post.setPostFormat(PostFormat.MARKDOWN);
|
||||
//
|
||||
// return createPost(post);
|
||||
// }
|
||||
|
||||
// public Post createProjectsPage() {
|
||||
// logger.debug("Create default projects page");
|
||||
//
|
||||
// Post post = new Post();
|
||||
// post.setTitle(Constants.PROJECTS_PAGE_PERMALINK);
|
||||
// post.setContent(Constants.PROJECTS_PAGE_PERMALINK.toLowerCase());
|
||||
// post.setPermalink(Constants.PROJECTS_PAGE_PERMALINK);
|
||||
// post.setUser(userService.getSuperUser());
|
||||
// post.setPostFormat(PostFormat.MARKDOWN);
|
||||
//
|
||||
// return createPost(post);
|
||||
// }
|
||||
|
||||
public Set<Tag> parseTagNames(String tagNames) {
|
||||
Set<Tag> tags = new HashSet<>();
|
||||
|
||||
if (tagNames != null && !tagNames.isEmpty()) {
|
||||
tagNames = tagNames.toLowerCase();
|
||||
String[] names = tagNames.split("\\s*,\\s*");
|
||||
for (String name : names) {
|
||||
tags.add(tagService.findOrCreateByName(name));
|
||||
}
|
||||
}
|
||||
|
||||
return tags;
|
||||
}
|
||||
|
||||
public String getTagNames(Set<Tag> tags) {
|
||||
if (tags == null || tags.isEmpty())
|
||||
return "";
|
||||
|
||||
StringBuilder names = new StringBuilder();
|
||||
tags.forEach(tag -> names.append(tag.getName()).append(","));
|
||||
names.deleteCharAt(names.length() - 1);
|
||||
|
||||
return names.toString();
|
||||
}
|
||||
|
||||
// cache or not?
|
||||
public Page<Post> findPostsByTag(String tagName, int page, int pageSize) {
|
||||
return postRepository.findByTag(tagName, new PageRequest(page, pageSize, Sort.Direction.DESC, "createdAt"));
|
||||
}
|
||||
|
||||
@Cacheable(value = CACHE_NAME_COUNTS, key = "#root.method.name")
|
||||
public List<Object[]> countPostsByTags() {
|
||||
logger.debug("Count posts group by tags.");
|
||||
|
||||
return postRepository.countPostsByTags(PostStatus.PUBLISHED);
|
||||
}
|
||||
|
||||
public Post findPostByPermalink(String permalink) {
|
||||
Post post = null;
|
||||
|
||||
try{
|
||||
post = this.getPublishedPostByPermalink(permalink);
|
||||
} catch (NotFoundException ex){
|
||||
if (permalink.matches("\\d+")) {
|
||||
if (this.userService.isCurrentUserAdmin()) {
|
||||
post = this.getPost(Long.valueOf(permalink));
|
||||
} else {
|
||||
post = this.getPublishedPost(Long.valueOf(permalink));
|
||||
}
|
||||
}/* else if (permalink.toLowerCase().trim().equals(Constants.PROJECTS_PAGE_PERMALINK)) {
|
||||
post = this.createProjectsPage();
|
||||
}*/
|
||||
}
|
||||
|
||||
if (post == null) {
|
||||
throw new NotFoundException("Post with permalink " + permalink + " is not found");
|
||||
}
|
||||
|
||||
return post;
|
||||
}
|
||||
|
||||
private void saveSeoData(Post post) {
|
||||
if (post.getSeoData() != null && post.getSeoData().getId() == null) {
|
||||
SeoPostData data = post.getSeoData();
|
||||
this.seoPostDataRepository.save(data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package ru.bvn13.voidforum.services;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class PrivilegeService {
|
||||
public static final String PRIVILEGE_OWNER = "OWNER_PRIVILEGE";
|
||||
public static final String PRIVILEGE_ADMIN = "ADMIN_PRIVILEGE";
|
||||
public static final String PRIVILEGE_READ = "READ_PRIVILEGE";
|
||||
public static final String PRIVILEGE_WRITE = "WRITE_PRIVILEGE";
|
||||
public static final String PRIVILEGE_WRITE_HTML = "WRITE_PRIVILEGE_HTML";
|
||||
public static final String PRIVILEGE_BLOCKED = "BLOCKED_PRIVILEGE";
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package ru.bvn13.voidforum.services;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@Service
|
||||
public class RequestProcessorService {
|
||||
|
||||
public String getRealIp(HttpServletRequest request) {
|
||||
String xRealIp = request.getHeader("X-Real-IP");
|
||||
if (xRealIp == null || request.getHeader("X-Real-IP").isEmpty()) {
|
||||
return request.getRemoteAddr();
|
||||
}
|
||||
return xRealIp;
|
||||
}
|
||||
|
||||
public String getUserAgent(HttpServletRequest request) {
|
||||
String userAgent = request.getHeader("User-Agent");
|
||||
return userAgent;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package ru.bvn13.voidforum.services;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class RoleService {
|
||||
public static final String ROLE_OWNER = "ROLE_OWNER";
|
||||
public static final String ROLE_ADMIN = "ROLE_ADMIN";
|
||||
public static final String ROLE_ADMIN_WITH_HTML_EDITOR = "ROLE_ADMIN_WITH_HTML_EDITOR";
|
||||
public static final String ROLE_USER = "ROLE_USER";
|
||||
public static final String ROLE_USER_WITH_HTML_EDITOR = "ROLE_USER_WITH_HTML_EDITOR";
|
||||
public static final String ROLE_VISITOR = "ROLE_VISITOR";
|
||||
public static final String ROLE_BLOCKED = "ROLE_BLOCKED";
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package ru.bvn13.voidforum.services;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class SeoRobotAgentService {
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package ru.bvn13.voidforum.services;
|
||||
|
||||
import ru.bvn13.voidforum.models.Post;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import java.io.StringWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class SeoService {
|
||||
|
||||
public static final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
|
||||
|
||||
@Autowired
|
||||
private AppSetting appSetting;
|
||||
|
||||
|
||||
public String createSitemap(List<Post> posts) {
|
||||
|
||||
String slash = appSetting.getMainUri().trim().endsWith("/") ? "" : "/";
|
||||
|
||||
try {
|
||||
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
|
||||
|
||||
Document doc = docBuilder.newDocument();
|
||||
Element root = doc.createElement("urlset");
|
||||
root.setAttribute("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9");
|
||||
doc.appendChild(root);
|
||||
|
||||
for(Post post : posts) {
|
||||
Element url = doc.createElement("url");
|
||||
//loc
|
||||
Element loc = doc.createElement("loc");
|
||||
loc.appendChild(doc.createTextNode(String.format("%s%sposts/%s", appSetting.getMainUri().trim(), slash, post.getPermalink() == null || post.getPermalink().isEmpty() ? post.getId() : post.getPermalink())));
|
||||
url.appendChild(loc);
|
||||
//lastmod
|
||||
//yyyy-MM-dd'T'HH:mm:ss
|
||||
Element lastMod = doc.createElement("lastmod");
|
||||
lastMod.appendChild(doc.createTextNode(dateFormatter.format(post.getUpdatedAt())));
|
||||
url.appendChild(lastMod);
|
||||
//
|
||||
Element changeFreq = doc.createElement("changefreq");
|
||||
changeFreq.appendChild(doc.createTextNode("daily"));
|
||||
url.appendChild(changeFreq);
|
||||
|
||||
root.appendChild(url);
|
||||
}
|
||||
|
||||
// write the content into xml file
|
||||
TransformerFactory transformerFactory = TransformerFactory.newInstance();
|
||||
Transformer transformer = transformerFactory.newTransformer();
|
||||
DOMSource source = new DOMSource(doc);
|
||||
|
||||
StringWriter sw = new StringWriter();
|
||||
transformer.transform(new DOMSource(doc), new StreamResult(sw));
|
||||
return sw.toString();
|
||||
|
||||
} catch (ParserConfigurationException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} catch (TransformerException tfe) {
|
||||
tfe.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package ru.bvn13.voidforum.services;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* bvn13 <mail4bvn@gmail.com>
|
||||
*/
|
||||
public interface SettingService {
|
||||
Serializable get(String key);
|
||||
Serializable get(String key, Serializable defaultValue);
|
||||
void put(String key, Serializable value);
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package ru.bvn13.voidforum.services;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.cache.annotation.Caching;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ru.bvn13.voidforum.models.Tag;
|
||||
import ru.bvn13.voidforum.repositories.TagRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* bvn13 <mail4bvn@gmail.com>.
|
||||
*/
|
||||
@Service
|
||||
public class TagService {
|
||||
private TagRepository tagRepository;
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PostService.class);
|
||||
|
||||
public static final String CACHE_NAME = "cache.tag";
|
||||
public static final String CACHE_NAME_TAGS = "cache.tag.all";
|
||||
|
||||
public static final String CACHE_TYPE = "'_Tag_'";
|
||||
public static final String CACHE_KEY = CACHE_TYPE + " + #tagName";
|
||||
public static final String CACHE_TAG_KEY = CACHE_TYPE + " + #tag.name";
|
||||
|
||||
@Autowired
|
||||
public TagService(TagRepository tagRepository){
|
||||
this.tagRepository = tagRepository;
|
||||
}
|
||||
|
||||
public Tag findOrCreateByName(String name){
|
||||
Tag tag = tagRepository.findByName(name);
|
||||
if (tag == null){
|
||||
tag = tagRepository.save(new Tag(name));
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Cacheable(value = CACHE_NAME, key = CACHE_KEY)
|
||||
public Tag getTag(String tagName) {
|
||||
return tagRepository.findByName(tagName);
|
||||
}
|
||||
|
||||
@Caching(evict = {
|
||||
@CacheEvict(value = CACHE_NAME, key = CACHE_TAG_KEY),
|
||||
@CacheEvict(value = CACHE_NAME_TAGS, allEntries = true)
|
||||
})
|
||||
public void deleteTag(Tag tag){
|
||||
tagRepository.delete(tag);
|
||||
}
|
||||
|
||||
@Cacheable(value = CACHE_NAME_TAGS, key = "#root.method.name")
|
||||
public List<Tag> getAllTags(){
|
||||
return tagRepository.findAll();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,233 @@
|
|||
package ru.bvn13.voidforum.services;
|
||||
|
||||
import com.domingosuarez.boot.autoconfigure.jade4j.JadeHelper;
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.hql.internal.ast.util.SessionFactoryHelper;
|
||||
import ru.bvn13.voidforum.error.EmailExistsException;
|
||||
import ru.bvn13.voidforum.error.NicknameExistsException;
|
||||
import ru.bvn13.voidforum.models.Privilege;
|
||||
import ru.bvn13.voidforum.models.User;
|
||||
import ru.bvn13.voidforum.models.Role;
|
||||
import ru.bvn13.voidforum.models.support.PostFormat;
|
||||
import ru.bvn13.voidforum.repositories.PrivilegeRepository;
|
||||
import ru.bvn13.voidforum.repositories.UserRepository;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import ru.bvn13.voidforum.repositories.RoleRepository;
|
||||
import ru.bvn13.voidforum.utils.DTOUtil;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.inject.Inject;
|
||||
import javax.transaction.Transactional;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@JadeHelper("userService")
|
||||
public class UserService implements UserDetailsService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(UserService.class);
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private RoleRepository roleRepository;
|
||||
|
||||
@Autowired
|
||||
private PrivilegeRepository privilegeRepository;
|
||||
|
||||
@Inject
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
// @Autowired
|
||||
// private SessionFactory sessionFactory;
|
||||
|
||||
|
||||
|
||||
@PostConstruct
|
||||
protected void initialize() {
|
||||
//getSuperUser();
|
||||
}
|
||||
|
||||
public User createUser(User user){
|
||||
user.setPassword(passwordEncoder.encode(user.getPassword()));
|
||||
return userRepository.save(user);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
|
||||
|
||||
org.springframework.security.core.userdetails.User springUser = null;
|
||||
|
||||
//sessionFactory.openSession();
|
||||
|
||||
User user = userRepository.findByEmail(email);
|
||||
if (user == null) {
|
||||
springUser = new org.springframework.security.core.userdetails.User(
|
||||
" ", " ", true, true, true, true,
|
||||
getAuthorities(Arrays.asList(
|
||||
roleRepository.findByName(RoleService.ROLE_VISITOR))
|
||||
)
|
||||
);
|
||||
} else {
|
||||
List<Role> roles = roleRepository.findAllByUser(user);
|
||||
springUser = new org.springframework.security.core.userdetails.User(
|
||||
user.getEmail(), user.getPassword(), !user.getDisabled(), true, true,
|
||||
true, getAuthorities(roles)
|
||||
);
|
||||
}
|
||||
|
||||
//sessionFactory.close();
|
||||
|
||||
return springUser;
|
||||
}
|
||||
|
||||
private Collection<? extends GrantedAuthority> getAuthorities(Collection<Role> roles) {
|
||||
return getGrantedAuthorities(getPrivileges(roles));
|
||||
}
|
||||
|
||||
public List<String> getPrivileges(Collection<Role> roles) {
|
||||
|
||||
List<String> privileges = new ArrayList<>();
|
||||
List<Privilege> collection = new ArrayList<>();
|
||||
for (Role role : roles) {
|
||||
//role.setPrivileges(privilegeRepository.findAllByRole(role));
|
||||
collection.addAll(privilegeRepository.findAllByRole(role));
|
||||
}
|
||||
for (Privilege item : collection) {
|
||||
privileges.add(item.getName());
|
||||
}
|
||||
return privileges;
|
||||
}
|
||||
|
||||
private List<GrantedAuthority> getGrantedAuthorities(List<String> privileges) {
|
||||
List<GrantedAuthority> authorities = new ArrayList<>();
|
||||
for (String privilege : privileges) {
|
||||
authorities.add(new SimpleGrantedAuthority(privilege));
|
||||
}
|
||||
return authorities;
|
||||
}
|
||||
|
||||
|
||||
public User currentUser(){
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
if(auth == null || auth instanceof AnonymousAuthenticationToken){
|
||||
return null;
|
||||
}
|
||||
|
||||
String email = ((org.springframework.security.core.userdetails.User) auth.getPrincipal()).getUsername();
|
||||
|
||||
return userRepository.findByEmail(email);
|
||||
}
|
||||
|
||||
public Boolean isCurrentUserAdmin() {
|
||||
User user = this.currentUser();
|
||||
Boolean isAdmin = user != null ? this.hasPrivilege(user, PrivilegeService.PRIVILEGE_ADMIN) : false;
|
||||
return isAdmin;
|
||||
}
|
||||
|
||||
public boolean changePassword(User user, String password, String newPassword){
|
||||
if (password == null || newPassword == null || password.isEmpty() || newPassword.isEmpty())
|
||||
return false;
|
||||
|
||||
logger.info("" + passwordEncoder.matches(password, user.getPassword()));
|
||||
boolean match = passwordEncoder.matches(password, user.getPassword());
|
||||
if (!match)
|
||||
return false;
|
||||
|
||||
user.setPassword(passwordEncoder.encode(newPassword));
|
||||
userRepository.save(user);
|
||||
|
||||
logger.info("User @"+user.getEmail() + " changed password.");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public Boolean currentUserHasPrivilege(String privilege) {
|
||||
User user = this.currentUser();
|
||||
return this.hasPrivilege(user, privilege);
|
||||
}
|
||||
|
||||
|
||||
public User registerNewUserAccount(User user) throws EmailExistsException, NicknameExistsException {
|
||||
|
||||
if (emailExist(user.getEmail())) {
|
||||
throw new EmailExistsException("There is an account with that email address: " + user.getEmail());
|
||||
}
|
||||
if (nicknameExists(user.getNickname())) {
|
||||
throw new NicknameExistsException("There is an account with that nickname: " + user.getNickname());
|
||||
}
|
||||
user.setPassword(passwordEncoder.encode(user.getPassword()));
|
||||
user.setDisabled(false);
|
||||
|
||||
user.setRoles(Arrays.asList(roleRepository.findByName(RoleService.ROLE_USER)));
|
||||
return userRepository.save(user);
|
||||
}
|
||||
|
||||
|
||||
public Boolean emailExist(String email) {
|
||||
return this.userRepository.findByEmail(email) != null;
|
||||
}
|
||||
|
||||
public Boolean nicknameExists(String nickname) {
|
||||
return this.userRepository.findByNickname(nickname) != null;
|
||||
}
|
||||
|
||||
public Boolean hasRole(User user, String role) {
|
||||
if (user == null) {
|
||||
return false;
|
||||
}
|
||||
AtomicReference<Boolean> hasRole = new AtomicReference<>(false);
|
||||
user.getRoles().forEach(r -> {
|
||||
if (r.getName().equals(role)) {
|
||||
hasRole.set(true);
|
||||
}
|
||||
});
|
||||
return hasRole.get();
|
||||
}
|
||||
|
||||
public Boolean hasPrivilege(User user, String privilege) {
|
||||
if (user == null) {
|
||||
return false;
|
||||
}
|
||||
AtomicReference<Boolean> hasPrivilege = new AtomicReference<>(false);
|
||||
user.getRoles().forEach(r -> {
|
||||
r.getPrivileges().forEach(p -> {
|
||||
if (p.getName().equals(privilege)) {
|
||||
hasPrivilege.set(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
return hasPrivilege.get();
|
||||
}
|
||||
|
||||
|
||||
public List<PostFormat> getAvailablePostFormats(User user) {
|
||||
List<PostFormat> availableFormats = new ArrayList<>();
|
||||
for (PostFormat postFormat : PostFormat.values()) {
|
||||
if (postFormat.equals(PostFormat.HTML)) {
|
||||
if (hasPrivilege(user, PrivilegeService.PRIVILEGE_WRITE_HTML)) {
|
||||
availableFormats.add(postFormat);
|
||||
}
|
||||
} else {
|
||||
availableFormats.add(postFormat);
|
||||
}
|
||||
}
|
||||
return availableFormats;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
package ru.bvn13.voidforum.services;
|
||||
|
||||
import ru.bvn13.voidforum.models.Post;
|
||||
import ru.bvn13.voidforum.models.SeoRobotAgent;
|
||||
import ru.bvn13.voidforum.models.User;
|
||||
import ru.bvn13.voidforum.models.Visit;
|
||||
import ru.bvn13.voidforum.repositories.SeoRobotAgentRepository;
|
||||
import ru.bvn13.voidforum.repositories.VisitRepository;
|
||||
import org.hibernate.SQLQuery;
|
||||
import org.hibernate.Session;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@Service
|
||||
public class VisitService {
|
||||
|
||||
@Autowired
|
||||
private VisitRepository visitRepository;
|
||||
|
||||
@Autowired
|
||||
private SeoRobotAgentRepository seoRobotAgentRepository;
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Autowired
|
||||
private EntityManager entityManager;
|
||||
|
||||
public void saveVisit(Post post, String clientIp, String userAgent) {
|
||||
// if (this.userService.currentUser().isAdmin())
|
||||
// return;
|
||||
|
||||
User user = this.userService.currentUser();
|
||||
|
||||
Visit visit = new Visit();
|
||||
visit.setClientIp(clientIp);
|
||||
visit.setPost(post);
|
||||
visit.setUser(user);
|
||||
visit.setIsAdmin(user != null ? userService.hasPrivilege(user, PrivilegeService.PRIVILEGE_ADMIN) : false);
|
||||
visit.setUserAgent(userAgent);
|
||||
this.visitRepository.save(visit);
|
||||
}
|
||||
|
||||
public Long getUniqueVisitsCount(Post post) {
|
||||
|
||||
Session session = (Session) this.entityManager.getDelegate();
|
||||
SQLQuery query = session.createSQLQuery(
|
||||
"SELECT COUNT(DISTINCT v.clientIp) " +
|
||||
"FROM visits AS v " +
|
||||
"LEFT JOIN seo_robots_agents AS ra " +
|
||||
//"ON LOWER(v.userAgent) LIKE concat('%', LOWER(ra.userAgent), '%') " +
|
||||
"ON CASE WHEN ra.isregexp = TRUE THEN " +
|
||||
"LOWER(v.userAgent) SIMILAR TO concat(LOWER(ra.userAgent)) " +
|
||||
"ELSE " +
|
||||
"LOWER(v.userAgent) LIKE concat('%', LOWER(ra.userAgent), '%') " +
|
||||
"END " +
|
||||
"WHERE v.post_id = :post_id AND v.isAdmin = FALSE " +
|
||||
"AND ra.id IS NULL ");
|
||||
query.setLong("post_id", post.getId());
|
||||
List<Object> result = query.list();
|
||||
if (result.size() > 0L) {
|
||||
return ((BigInteger)result.get(0)).longValue();
|
||||
}
|
||||
|
||||
return 0L;
|
||||
|
||||
}
|
||||
|
||||
public Long getUniqueVisitsCount_old(Post post) {
|
||||
//return this.visitRepository.getUniquePostVisitsCount(post);
|
||||
|
||||
// exclude queries from robots if matches by UserAgent
|
||||
List<SeoRobotAgent> robotsAgents = this.seoRobotAgentRepository.findAll();
|
||||
|
||||
final Long[] count = {0L};
|
||||
|
||||
this.visitRepository.getVisitsByPostAndIsAdminIsFalse(post).forEach(vr -> {
|
||||
|
||||
Object[] v = (Object[]) vr;
|
||||
|
||||
if (robotsAgents.size() == 0 || v[1] == null) {
|
||||
count[0]++;
|
||||
} else {
|
||||
robotsAgents.forEach(ra -> {
|
||||
Pattern p = Pattern.compile(".*("+ra.getUserAgent()+").*", Pattern.CASE_INSENSITIVE);
|
||||
Matcher m = p.matcher((String) v[1]);
|
||||
if (!m.matches()) {
|
||||
count[0]++;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return count[0];
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
package ru.bvn13.voidforum.support;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Component;
|
||||
import ru.bvn13.voidforum.Constants;
|
||||
import ru.bvn13.voidforum.models.Privilege;
|
||||
import ru.bvn13.voidforum.models.User;
|
||||
import ru.bvn13.voidforum.models.Role;
|
||||
import ru.bvn13.voidforum.repositories.PrivilegeRepository;
|
||||
import ru.bvn13.voidforum.repositories.UserRepository;
|
||||
import ru.bvn13.voidforum.repositories.RoleRepository;
|
||||
import ru.bvn13.voidforum.services.PrivilegeService;
|
||||
import ru.bvn13.voidforum.services.RoleService;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class InitialDataLoader implements ApplicationListener<ContextRefreshedEvent> {
|
||||
|
||||
boolean alreadySetup = false;
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private RoleRepository roleRepository;
|
||||
|
||||
@Autowired
|
||||
private PrivilegeRepository privilegeRepository;
|
||||
|
||||
@Autowired
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void onApplicationEvent(ContextRefreshedEvent event) {
|
||||
|
||||
if (alreadySetup)
|
||||
return;
|
||||
|
||||
Privilege ownerPrivilege = createPrivilegeIfNotFound(PrivilegeService.PRIVILEGE_OWNER);
|
||||
Privilege adminPrivilege = createPrivilegeIfNotFound(PrivilegeService.PRIVILEGE_ADMIN);
|
||||
Privilege readPrivilege = createPrivilegeIfNotFound(PrivilegeService.PRIVILEGE_READ);
|
||||
Privilege writePrivilege = createPrivilegeIfNotFound(PrivilegeService.PRIVILEGE_WRITE);
|
||||
Privilege writeHtmlPrivilege = createPrivilegeIfNotFound(PrivilegeService.PRIVILEGE_WRITE_HTML);
|
||||
Privilege blockedPrivilege = createPrivilegeIfNotFound(PrivilegeService.PRIVILEGE_BLOCKED);
|
||||
|
||||
|
||||
Role roleOwner = createRoleIfNotFound(RoleService.ROLE_OWNER, Arrays.asList(ownerPrivilege, adminPrivilege, writePrivilege, writeHtmlPrivilege, readPrivilege));
|
||||
|
||||
createRoleIfNotFound(RoleService.ROLE_ADMIN, Arrays.asList(adminPrivilege, readPrivilege, writePrivilege));
|
||||
createRoleIfNotFound(RoleService.ROLE_ADMIN_WITH_HTML_EDITOR, Arrays.asList(adminPrivilege, readPrivilege, writePrivilege, writeHtmlPrivilege));
|
||||
createRoleIfNotFound(RoleService.ROLE_USER, Arrays.asList(readPrivilege, writePrivilege));
|
||||
createRoleIfNotFound(RoleService.ROLE_USER_WITH_HTML_EDITOR, Arrays.asList(readPrivilege, writePrivilege, writeHtmlPrivilege));
|
||||
createRoleIfNotFound(RoleService.ROLE_VISITOR, Arrays.asList(readPrivilege));
|
||||
createRoleIfNotFound(RoleService.ROLE_BLOCKED, Arrays.asList(readPrivilege, blockedPrivilege));
|
||||
|
||||
|
||||
if (userRepository.findAllByOneRoleByNameOrderById(RoleService.ROLE_OWNER).size() == 0) {
|
||||
User user = new User();
|
||||
user.setNickname(Constants.DEFAULT_ADMIN_NICKNAME);
|
||||
user.setEmail(Constants.DEFAULT_ADMIN_EMAIL);
|
||||
user.setPassword(passwordEncoder.encode(Constants.DEFAULT_ADMIN_PASSWORD));
|
||||
user.setRoles(Arrays.asList(roleOwner));
|
||||
user.setDisabled(false);
|
||||
userRepository.save(user);
|
||||
}
|
||||
|
||||
alreadySetup = true;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Privilege createPrivilegeIfNotFound(String name) {
|
||||
|
||||
Privilege privilege = privilegeRepository.findByName(name);
|
||||
if (privilege == null) {
|
||||
privilege = new Privilege(name);
|
||||
privilegeRepository.save(privilege);
|
||||
}
|
||||
return privilege;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Role createRoleIfNotFound(String name, Collection<Privilege> privileges) {
|
||||
|
||||
Role role = roleRepository.findByName(name);
|
||||
if (role == null) {
|
||||
role = new Role(name);
|
||||
role.setPrivileges(privileges);
|
||||
} else {
|
||||
// add new privileges
|
||||
for (Privilege privilege : privileges) {
|
||||
boolean found = false;
|
||||
for (Privilege p : role.getPrivileges()) {
|
||||
if (p.getName().equals(privilege.getName())) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
role.getPrivileges().add(privilege);
|
||||
}
|
||||
}
|
||||
// remove unused privileges
|
||||
List<Privilege> privilegeListForRemoving = new ArrayList<>();
|
||||
for (Privilege p : role.getPrivileges()) {
|
||||
boolean found = false;
|
||||
for (Privilege privilege : privileges) {
|
||||
if (p.getName().equals(privilege.getName())) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
privilegeListForRemoving.add(p);
|
||||
}
|
||||
}
|
||||
for (Privilege privilege : privilegeListForRemoving) {
|
||||
role.getPrivileges().remove(privilege);
|
||||
}
|
||||
}
|
||||
roleRepository.save(role);
|
||||
return role;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package ru.bvn13.voidforum.support.web;
|
||||
|
||||
import com.vladsch.flexmark.ast.Node;
|
||||
import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughExtension;
|
||||
import com.vladsch.flexmark.ext.tables.TablesExtension;
|
||||
import com.vladsch.flexmark.ext.youtube.embedded.YouTubeLinkExtension;
|
||||
import com.vladsch.flexmark.html.HtmlRenderer;
|
||||
import com.vladsch.flexmark.parser.Parser;
|
||||
import com.vladsch.flexmark.util.options.MutableDataSet;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@Service
|
||||
@Qualifier("flexmark")
|
||||
public class FlexmarkMarkdownService implements MarkdownService, SyntaxHighlightService {
|
||||
@Override
|
||||
public String renderToHtml(String content) {
|
||||
|
||||
MutableDataSet options = new MutableDataSet();
|
||||
|
||||
// uncomment to set optional extensions
|
||||
options.set(Parser.EXTENSIONS, Arrays.asList(
|
||||
TablesExtension.create(),
|
||||
StrikethroughExtension.create(),
|
||||
//YoutubeLinkTransformer.YouTubeLinkExtension.create(),
|
||||
YouTubeLinkExtension.create()
|
||||
));
|
||||
|
||||
// uncomment to convert soft-breaks to hard breaks
|
||||
//options.set(HtmlRenderer.SOFT_BREAK, "<br />\n");
|
||||
|
||||
Parser parser = Parser.builder(options).build();
|
||||
HtmlRenderer renderer = HtmlRenderer.builder(options).build();
|
||||
|
||||
// You can re-use parser and renderer instances
|
||||
Node document = parser.parse(content);
|
||||
String html = renderer.render(document); // "<p>This is <em>Sparta</em></p>\n"
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String highlight(String content) {
|
||||
return content;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package ru.bvn13.voidforum.support.web;
|
||||
|
||||
/**
|
||||
* @author bvn13 <mail4bvn@gmail.com>
|
||||
*/
|
||||
public interface MarkdownService {
|
||||
public String renderToHtml(String content);
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package ru.bvn13.voidforum.support.web;
|
||||
|
||||
/**
|
||||
* A message to be displayed in web context. Depending on the type, different style will be applied.
|
||||
*/
|
||||
public class Message implements java.io.Serializable {
|
||||
/**
|
||||
* Name of the flash attribute.
|
||||
*/
|
||||
public static final String MESSAGE_ATTRIBUTE = "message";
|
||||
|
||||
/**
|
||||
* The type of the message to be displayed. The type is used to show message in a different style.
|
||||
*/
|
||||
public static enum Type {
|
||||
DANGER, WARNING, INFO, SUCCESS;
|
||||
}
|
||||
|
||||
private final String message;
|
||||
private final Type type;
|
||||
private final Object[] args;
|
||||
|
||||
public Message(String message, Type type) {
|
||||
this.message = message;
|
||||
this.type = type;
|
||||
this.args = null;
|
||||
}
|
||||
|
||||
public Message(String message, Type type, Object... args) {
|
||||
this.message = message;
|
||||
this.type = type;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public Object[] getArgs() {
|
||||
return args;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package ru.bvn13.voidforum.support.web;
|
||||
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
|
||||
import static ru.bvn13.voidforum.support.web.Message.MESSAGE_ATTRIBUTE;
|
||||
|
||||
public final class MessageHelper {
|
||||
|
||||
private MessageHelper() {
|
||||
|
||||
}
|
||||
|
||||
public static void addSuccessAttribute(RedirectAttributes ra, String message, Object... args) {
|
||||
addAttribute(ra, message, Message.Type.SUCCESS, args);
|
||||
}
|
||||
|
||||
public static void addErrorAttribute(RedirectAttributes ra, String message, Object... args) {
|
||||
addAttribute(ra, message, Message.Type.DANGER, args);
|
||||
}
|
||||
|
||||
public static void addInfoAttribute(RedirectAttributes ra, String message, Object... args) {
|
||||
addAttribute(ra, message, Message.Type.INFO, args);
|
||||
}
|
||||
|
||||
public static void addWarningAttribute(RedirectAttributes ra, String message, Object... args) {
|
||||
addAttribute(ra, message, Message.Type.WARNING, args);
|
||||
}
|
||||
|
||||
private static void addAttribute(RedirectAttributes ra, String message, Message.Type type, Object... args) {
|
||||
ra.addFlashAttribute(MESSAGE_ATTRIBUTE, new Message(message, type, args));
|
||||
}
|
||||
|
||||
public static void addSuccessAttribute(Model model, String message, Object... args) {
|
||||
addAttribute(model, message, Message.Type.SUCCESS, args);
|
||||
}
|
||||
|
||||
public static void addErrorAttribute(Model model, String message, Object... args) {
|
||||
addAttribute(model, message, Message.Type.DANGER, args);
|
||||
}
|
||||
|
||||
public static void addInfoAttribute(Model model, String message, Object... args) {
|
||||
addAttribute(model, message, Message.Type.INFO, args);
|
||||
}
|
||||
|
||||
public static void addWarningAttribute(Model model, String message, Object... args) {
|
||||
addAttribute(model, message, Message.Type.WARNING, args);
|
||||
}
|
||||
|
||||
private static void addAttribute(Model model, String message, Message.Type type, Object... args) {
|
||||
model.addAttribute(MESSAGE_ATTRIBUTE, new Message(message, type, args));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package ru.bvn13.voidforum.support.web;
|
||||
|
||||
/**
|
||||
* @author bvn13 <mail4bvn@gmail.com>
|
||||
*/
|
||||
public interface SyntaxHighlightService {
|
||||
public String highlight(String content);
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
package ru.bvn13.voidforum.support.web;
|
||||
|
||||
|
||||
import com.domingosuarez.boot.autoconfigure.jade4j.JadeHelper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ru.bvn13.voidforum.models.Post;
|
||||
import ru.bvn13.voidforum.models.support.WebError;
|
||||
import ru.bvn13.voidforum.services.AppSetting;
|
||||
|
||||
import java.text.DateFormatSymbols;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author bvn13 <mail4bvn@gmail.com>
|
||||
*/
|
||||
@Service
|
||||
@JadeHelper("viewHelper")
|
||||
public class ViewHelperVF {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(ViewHelperVF.class);
|
||||
|
||||
private static DateFormatSymbols ruDateFormatSymbolsFull = new DateFormatSymbols(){
|
||||
@Override
|
||||
public String[] getMonths() {
|
||||
return new String[]{"январь", "февраль", "март", "апрель", "май", "июнь", "июль", "август", "сентябрь", "октябрь", "ноябрь", "декабрь"};
|
||||
}
|
||||
};
|
||||
private static DateFormatSymbols ruDateFormatSymbolsShort = new DateFormatSymbols(){
|
||||
@Override
|
||||
public String[] getMonths() {
|
||||
return new String[]{"янв", "фев", "мар", "апр", "май", "июн", "июл", "авг", "сен", "окт", "ноя", "дек"};
|
||||
}
|
||||
};
|
||||
|
||||
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("MMMM dd, yyyy", ViewHelperVF.ruDateFormatSymbolsFull);
|
||||
private static final SimpleDateFormat DATE_FORMAT_MONTH_DAY = new SimpleDateFormat("MMM dd", ViewHelperVF.ruDateFormatSymbolsShort);
|
||||
|
||||
private AppSetting appSetting;
|
||||
|
||||
private String applicationEnv;
|
||||
|
||||
@Autowired
|
||||
public ViewHelperVF(AppSetting appSetting){
|
||||
this.appSetting = appSetting;
|
||||
}
|
||||
|
||||
private long startTime;
|
||||
|
||||
public long getResponseTime(){
|
||||
return System.currentTimeMillis() - startTime;
|
||||
}
|
||||
|
||||
public long getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public void setStartTime(long startTime) {
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
public String getFormattedDate(Date date){
|
||||
return date == null ? "" : DATE_FORMAT.format(date);
|
||||
}
|
||||
|
||||
public String getMonthAndDay(Date date){
|
||||
return date == null ? "" : DATE_FORMAT_MONTH_DAY.format(date);
|
||||
}
|
||||
|
||||
public String metaTitle(String title){
|
||||
return title + " · " + appSetting.getSiteName();
|
||||
}
|
||||
|
||||
public String getApplicationEnv() {
|
||||
return applicationEnv;
|
||||
}
|
||||
|
||||
public Boolean isProductionMode() {
|
||||
return this.applicationEnv.equalsIgnoreCase("production");
|
||||
}
|
||||
|
||||
public void setApplicationEnv(String applicationEnv) {
|
||||
this.applicationEnv = applicationEnv;
|
||||
}
|
||||
|
||||
public String formatNumberByThousands(Long number) {
|
||||
if (number == null)
|
||||
return "0";
|
||||
|
||||
double thousands = number / 1000;
|
||||
double millions = thousands / 1000;
|
||||
if (millions > 0d) {
|
||||
return String.format("%.3f", millions);
|
||||
} else if (thousands > 0d) {
|
||||
return String.format("%.3fK", thousands);
|
||||
} else {
|
||||
return String.format("%d", number);
|
||||
}
|
||||
}
|
||||
|
||||
public String formatNumberByThousands(Integer number) {
|
||||
return this.formatNumberByThousands((long) number);
|
||||
}
|
||||
|
||||
public String errorFormat(Map<String, WebError> errors, String field) {
|
||||
if (errors != null && errors.containsKey(field)) {
|
||||
return errors.get(field).getErrorMessage();
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public String getPostUrl(Post post) {
|
||||
return String.format("%s/posts/%s",
|
||||
this.appSetting.getMainUri().endsWith("/") ? this.appSetting.getMainUri().substring(0, this.appSetting.getMainUri().length()-1) : this.appSetting.getMainUri(),
|
||||
post.getPermalink().isEmpty() ? post.getId() : post.getPermalink()
|
||||
);
|
||||
}
|
||||
|
||||
public String getAbsoluteUrl(String url) {
|
||||
if (url.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
return String.format("%s/%s",
|
||||
this.appSetting.getMainUri().endsWith("/") ? this.appSetting.getMainUri().substring(0, this.appSetting.getMainUri().length()-1) : this.appSetting.getMainUri(),
|
||||
url.startsWith("/") ? url.substring(1) : url
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package ru.bvn13.voidforum.utils;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
import org.modelmapper.ModelMapper;
|
||||
import org.modelmapper.convention.MatchingStrategies;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author bvn13 <mail4bvn@gmail.com>
|
||||
*/
|
||||
public class DTOUtil {
|
||||
|
||||
private static ModelMapper MAPPER = null;
|
||||
|
||||
private static ModelMapper getMapper(){
|
||||
if(MAPPER == null){
|
||||
MAPPER = new ModelMapper();
|
||||
MAPPER.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
|
||||
}
|
||||
|
||||
return MAPPER;
|
||||
}
|
||||
|
||||
public static <S, T> T map(S source, Class<T> targetClass) {
|
||||
return getMapper().map(source, targetClass);
|
||||
}
|
||||
|
||||
public static <S, T> void mapTo(S source, T dist) {
|
||||
getMapper().map(source, dist);
|
||||
}
|
||||
|
||||
public static <S, T> List<T> mapList(List<S> source, Class<T> targetClass) {
|
||||
List<T> list = new ArrayList<>();
|
||||
for (S s : source) {
|
||||
list.add(getMapper().map(s, targetClass));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static <T> T initializeAndUnproxy(T entity) {
|
||||
if (entity == null) {
|
||||
throw new
|
||||
NullPointerException("Entity passed for initialization is null");
|
||||
}
|
||||
|
||||
Hibernate.initialize(entity);
|
||||
if (entity instanceof HibernateProxy) {
|
||||
entity = (T) ((HibernateProxy) entity).getHibernateLazyInitializer().getImplementation();
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
server:
|
||||
port: 9000
|
||||
contextPath:
|
||||
|
||||
spring:
|
||||
profiles:
|
||||
active: dev
|
||||
|
||||
thymeleaf:
|
||||
#mode: html5
|
||||
#suffix: .html
|
||||
cache: false
|
||||
|
||||
jade4j:
|
||||
caching: false
|
||||
|
||||
dataSource:
|
||||
driverClassName: org.postgresql.Driver
|
||||
url: jdbc:postgresql://localhost:5432/voidforum
|
||||
username: voidforum
|
||||
password: vfpass
|
||||
|
||||
hibernate:
|
||||
dialect: org.hibernate.dialect.PostgreSQLDialect
|
||||
hbm2ddl.auto: update
|
||||
show_sql: false
|
||||
|
||||
redis:
|
||||
embedded : false
|
||||
host: localhost
|
||||
port: 6379
|
||||
default_expire_time: 86400
|
||||
|
||||
session:
|
||||
store-type: redis
|
||||
|
||||
|
||||
jpa:
|
||||
properties:
|
||||
hibernate:
|
||||
current_session_context_class: org.springframework.orm.hibernate5.SpringSessionContext
|
||||
|
||||
http:
|
||||
multipart:
|
||||
max-file-size: 100Mb
|
||||
max-request-size: 100Mb
|
|
@ -0,0 +1,7 @@
|
|||
view.index.title=Home page
|
||||
signup.success=Congratulations {0}! You have successfully signed up.
|
||||
signin.already=You have already signed in.
|
||||
|
||||
# Validation messages
|
||||
notBlank.message = The value may not be empty!
|
||||
email.message = The value must be a valid email!
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue