Created repo
This commit is contained in:
parent
5fad221028
commit
56c99abeb6
43 changed files with 1892 additions and 0 deletions
25
.gitignore
vendored
Normal file
25
.gitignore
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
.gradle
|
||||
/build/
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### NetBeans ###
|
||||
nbproject/private/
|
||||
build/
|
||||
nbbuild/
|
||||
dist/
|
||||
nbdist/
|
||||
.nb-gradle/
|
13
annotation/build.gradle
Normal file
13
annotation/build.gradle
Normal file
|
@ -0,0 +1,13 @@
|
|||
group 'com.faendir'
|
||||
version 'unspecified'
|
||||
|
||||
apply plugin: 'java'
|
||||
|
||||
sourceCompatibility = 1.8
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.faendir.acra.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author Lukas
|
||||
* @since 14.05.2017
|
||||
*/
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface AutoDiscoverView {
|
||||
}
|
16
annotationprocessor/build.gradle
Normal file
16
annotationprocessor/build.gradle
Normal file
|
@ -0,0 +1,16 @@
|
|||
group 'com.faendir'
|
||||
version 'unspecified'
|
||||
|
||||
apply plugin: 'java'
|
||||
|
||||
sourceCompatibility = 1.8
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'com.squareup:javapoet:1.9.0'
|
||||
compile 'com.google.auto.service:auto-service:1.0-rc2'
|
||||
compile project(':annotation')
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package com.faendir.acra.processor;
|
||||
|
||||
import com.faendir.acra.annotation.AutoDiscoverView;
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import com.squareup.javapoet.JavaFile;
|
||||
import com.squareup.javapoet.MethodSpec;
|
||||
import com.squareup.javapoet.ParameterizedTypeName;
|
||||
import com.squareup.javapoet.TypeName;
|
||||
import com.squareup.javapoet.TypeSpec;
|
||||
import com.squareup.javapoet.WildcardTypeName;
|
||||
|
||||
import javax.annotation.processing.AbstractProcessor;
|
||||
import javax.annotation.processing.Processor;
|
||||
import javax.annotation.processing.RoundEnvironment;
|
||||
import javax.annotation.processing.SupportedSourceVersion;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.tools.Diagnostic;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Lukas
|
||||
* @since 14.05.2017
|
||||
*/
|
||||
@AutoService(Processor.class)
|
||||
@SupportedSourceVersion(SourceVersion.RELEASE_8)
|
||||
public class AnnotationProcessor extends AbstractProcessor {
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
Set<? extends Element> views = roundEnv.getElementsAnnotatedWith(AutoDiscoverView.class);
|
||||
if (!views.isEmpty()) {
|
||||
try {
|
||||
JavaFile.builder("com.faendir.acra.gen", TypeSpec.classBuilder("ViewDefinition")
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.addMethod(MethodSpec.methodBuilder("getViewClasses")
|
||||
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
|
||||
.returns(ParameterizedTypeName.get(ClassName.get(List.class), ParameterizedTypeName.get(ClassName.get(Class.class), WildcardTypeName.subtypeOf(Object.class))))
|
||||
.addCode("return $T.asList($L);", TypeName.get(Arrays.class), views.stream()
|
||||
.filter(element -> !element.getModifiers().contains(Modifier.ABSTRACT))
|
||||
.map(element -> ((TypeElement) element).getQualifiedName().toString() + ".class")
|
||||
.reduce((s1, s2) -> s1 + ", " + s2).orElse(""))
|
||||
.build())
|
||||
.build())
|
||||
.skipJavaLangImports(true)
|
||||
.indent(" ")
|
||||
.build()
|
||||
.writeTo(processingEnv.getFiler());
|
||||
} catch (IOException e) {
|
||||
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Failed to generate classes");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSupportedAnnotationTypes() {
|
||||
return Collections.singleton(AutoDiscoverView.class.getName());
|
||||
}
|
||||
}
|
46
backend/build.gradle
Normal file
46
backend/build.gradle
Normal file
|
@ -0,0 +1,46 @@
|
|||
buildscript {
|
||||
ext {
|
||||
springBootVersion = '1.5.3.RELEASE'
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id "net.ltgt.apt" version "0.10"
|
||||
}
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'eclipse'
|
||||
apply plugin: 'org.springframework.boot'
|
||||
apply plugin: 'war'
|
||||
|
||||
group 'com.faendir'
|
||||
version = '0.0.1-SNAPSHOT'
|
||||
sourceCompatibility = 1.8
|
||||
|
||||
dependencies {
|
||||
compile('org.springframework.boot:spring-boot-starter-data-mongodb')
|
||||
compile('org.springframework.boot:spring-boot-starter-security')
|
||||
compile('com.vaadin:vaadin-spring-boot-starter')
|
||||
compile('org.codeartisans:org.json:20161124')
|
||||
compile('org.apache.commons:commons-collections4:4.1')
|
||||
compile('org.ocpsoft.prettytime:prettytime:3.2.7.Final')
|
||||
compileOnly project(':annotation')
|
||||
apt project(':annotationprocessor')
|
||||
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
|
||||
}
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom "com.vaadin:vaadin-bom:8.0.6"
|
||||
}
|
||||
}
|
||||
|
||||
war {
|
||||
archiveName = "acra.war"
|
||||
version = version
|
||||
}
|
172
backend/gradlew
vendored
Normal file
172
backend/gradlew
vendored
Normal file
|
@ -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" "$@"
|
84
backend/gradlew.bat
vendored
Normal file
84
backend/gradlew.bat
vendored
Normal file
|
@ -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,27 @@
|
|||
package com.faendir.acra;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.web.support.SpringBootServletInitializer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
@SpringBootApplication(exclude = { SecurityAutoConfiguration.class })
|
||||
public class BackendApplication extends SpringBootServletInitializer {
|
||||
@Override
|
||||
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
|
||||
return builder.sources(BackendApplication.class);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(BackendApplication.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecureRandom secureRandom(){
|
||||
return new SecureRandom();
|
||||
}
|
||||
}
|
34
backend/src/main/java/com/faendir/acra/data/App.java
Normal file
34
backend/src/main/java/com/faendir/acra/data/App.java
Normal file
|
@ -0,0 +1,34 @@
|
|||
package com.faendir.acra.data;
|
||||
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
/**
|
||||
* @author Lukas
|
||||
* @since 22.03.2017
|
||||
*/
|
||||
@Document
|
||||
public class App {
|
||||
private String id;
|
||||
private String name;
|
||||
private String password;
|
||||
|
||||
public App() {
|
||||
}
|
||||
|
||||
public App(String name, String password) {
|
||||
this.name = name;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
38
backend/src/main/java/com/faendir/acra/data/AppManager.java
Normal file
38
backend/src/main/java/com/faendir/acra/data/AppManager.java
Normal file
|
@ -0,0 +1,38 @@
|
|||
package com.faendir.acra.data;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Base64Utils;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Lukas
|
||||
* @since 22.03.2017
|
||||
*/
|
||||
@Component
|
||||
public class AppManager {
|
||||
private final SecureRandom secureRandom;
|
||||
private final AppRepository appRepository;
|
||||
|
||||
@Autowired
|
||||
public AppManager(SecureRandom secureRandom, AppRepository appRepository) {
|
||||
this.secureRandom = secureRandom;
|
||||
this.appRepository = appRepository;
|
||||
}
|
||||
|
||||
public App createNewApp(String name){
|
||||
byte[] bytes = new byte[12];
|
||||
secureRandom.nextBytes(bytes);
|
||||
return appRepository.save(new App(name, Base64Utils.encodeToString(bytes)));
|
||||
}
|
||||
|
||||
public List<App> getApps(){
|
||||
return appRepository.findAll();
|
||||
}
|
||||
|
||||
public App getApp(String id){
|
||||
return appRepository.findOne(id);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.faendir.acra.data;
|
||||
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
|
||||
/**
|
||||
* @author Lukas
|
||||
* @since 22.03.2017
|
||||
*/
|
||||
public interface AppRepository extends MongoRepository<App, String> {
|
||||
}
|
41
backend/src/main/java/com/faendir/acra/data/Bug.java
Normal file
41
backend/src/main/java/com/faendir/acra/data/Bug.java
Normal file
|
@ -0,0 +1,41 @@
|
|||
package com.faendir.acra.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Lukas
|
||||
* @since 13.05.2017
|
||||
*/
|
||||
public class Bug {
|
||||
private List<Report> reports;
|
||||
private String trace;
|
||||
private int versionCode;
|
||||
|
||||
public Bug(Report report){
|
||||
reports = new ArrayList<>();
|
||||
this.trace = report.getContent().getString("STACK_TRACE");
|
||||
this.versionCode = report.getContent().getInt("APP_VERSION_CODE");
|
||||
}
|
||||
|
||||
public boolean is(Report report){
|
||||
return report.getContent().getString("STACK_TRACE").equals(trace) && report.getContent().getInt("APP_VERSION_CODE") == versionCode;
|
||||
}
|
||||
|
||||
public List<Report> getReports() {
|
||||
return reports;
|
||||
}
|
||||
|
||||
public Date getLastDate(){
|
||||
return reports.stream().map(Report::getDate).reduce((d1, d2) -> d1.after(d2) ? d1 : d2).orElse(new Date());
|
||||
}
|
||||
|
||||
public String getTrace() {
|
||||
return trace;
|
||||
}
|
||||
|
||||
public int getVersionCode() {
|
||||
return versionCode;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.faendir.acra.data;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.mongodb.MongoDbFactory;
|
||||
import org.springframework.data.mongodb.core.convert.DbRefResolver;
|
||||
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
|
||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
|
||||
/**
|
||||
* @author Lukas
|
||||
* @since 13.05.2017
|
||||
*/
|
||||
@Configuration
|
||||
public class MongoConfiguration {
|
||||
|
||||
@Bean
|
||||
public MappingMongoConverter mongoConverter(MongoDbFactory mongoFactory, MongoMappingContext mongoMappingContext) throws Exception {
|
||||
DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoFactory);
|
||||
MappingMongoConverter mongoConverter = new MappingMongoConverter(dbRefResolver, mongoMappingContext);
|
||||
mongoConverter.setMapKeyDotReplacement("%&&%");
|
||||
|
||||
return mongoConverter;
|
||||
}
|
||||
}
|
40
backend/src/main/java/com/faendir/acra/data/Report.java
Normal file
40
backend/src/main/java/com/faendir/acra/data/Report.java
Normal file
|
@ -0,0 +1,40 @@
|
|||
package com.faendir.acra.data;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.springframework.data.mongodb.core.index.Indexed;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author Lukas
|
||||
* @since 22.03.2017
|
||||
*/
|
||||
@Document
|
||||
public class Report {
|
||||
private String id;
|
||||
@Indexed
|
||||
private String app;
|
||||
private JSONObject content;
|
||||
|
||||
public Report() {
|
||||
}
|
||||
|
||||
public Report(JSONObject content, String app) {
|
||||
id = content == null ? null : content.getString("REPORT_ID");
|
||||
this.content = content;
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public JSONObject getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public Date getDate() {
|
||||
return ReportUtils.getDateFromString(content.getString("USER_CRASH_DATE"));
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package com.faendir.acra.data;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Example;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Lukas
|
||||
* @since 22.03.2017
|
||||
*/
|
||||
@Component
|
||||
public class ReportManager {
|
||||
private final ReportRepository reportRepository;
|
||||
|
||||
@Autowired
|
||||
public ReportManager(ReportRepository reportRepository) {
|
||||
this.reportRepository = reportRepository;
|
||||
}
|
||||
|
||||
public Report newReport(JSONObject content) {
|
||||
return reportRepository.save(new Report(content, SecurityContextHolder.getContext().getAuthentication().getName()));
|
||||
}
|
||||
|
||||
public List<Report> getReports(String app) {
|
||||
return reportRepository.findAll(Example.of(new Report(null, app)));
|
||||
}
|
||||
|
||||
public Report getReport(String id) {
|
||||
return reportRepository.findOne(id);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.faendir.acra.data;
|
||||
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
|
||||
/**
|
||||
* @author Lukas
|
||||
* @since 22.03.2017
|
||||
*/
|
||||
public interface ReportRepository extends MongoRepository<Report, String> {
|
||||
}
|
37
backend/src/main/java/com/faendir/acra/data/ReportUtils.java
Normal file
37
backend/src/main/java/com/faendir/acra/data/ReportUtils.java
Normal file
|
@ -0,0 +1,37 @@
|
|||
package com.faendir.acra.data;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* @author Lukas
|
||||
* @since 13.05.2017
|
||||
*/
|
||||
public final class ReportUtils {
|
||||
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH);
|
||||
|
||||
public static List<Bug> getBugs(List<Report> reports) {
|
||||
List<Bug> bugs = new ArrayList<>();
|
||||
for (Report report : reports) {
|
||||
bugs.stream().filter(bug -> bug.is(report)).findAny().orElseGet(() -> {
|
||||
Bug bug = new Bug(report);
|
||||
bugs.add(bug);
|
||||
return bug;
|
||||
}).getReports().add(report);
|
||||
}
|
||||
return bugs;
|
||||
}
|
||||
|
||||
static Date getDateFromString(String s) {
|
||||
try {
|
||||
return dateFormat.parse(s);
|
||||
} catch (ParseException e) {
|
||||
return new Date();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.faendir.acra.security;
|
||||
|
||||
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
|
||||
|
||||
/**
|
||||
* @author Lukas
|
||||
* @since 13.05.2017
|
||||
*/
|
||||
public class SecurityInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
|
||||
@Override
|
||||
protected Class<?>[] getRootConfigClasses() {
|
||||
return new Class[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getServletConfigClasses() {
|
||||
return new Class[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] getServletMappings() {
|
||||
return new String[0];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package com.faendir.acra.security;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
public final class SecurityUtils {
|
||||
|
||||
private SecurityUtils() {
|
||||
}
|
||||
|
||||
public static boolean isLoggedIn() {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
return authentication != null && authentication.isAuthenticated();
|
||||
}
|
||||
|
||||
public static boolean hasRole(String role) {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
return authentication != null && authentication.getAuthorities().contains(new SimpleGrantedAuthority(role));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package com.faendir.acra.security;
|
||||
|
||||
import com.vaadin.server.VaadinService;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||
import org.springframework.security.core.context.SecurityContextImpl;
|
||||
|
||||
import com.vaadin.server.VaadinSession;
|
||||
|
||||
/**
|
||||
* A custom {@link SecurityContextHolderStrategy} that stores the {@link SecurityContext} in the Vaadin Session.
|
||||
*/
|
||||
public class VaadinSessionSecurityContextHolderStrategy implements SecurityContextHolderStrategy {
|
||||
|
||||
@Override
|
||||
public void clearContext() {
|
||||
getSession().setAttribute(SecurityContext.class, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecurityContext getContext() {
|
||||
VaadinSession session = getSession();
|
||||
SecurityContext context = session.getAttribute(SecurityContext.class);
|
||||
if (context == null) {
|
||||
context = createEmptyContext();
|
||||
session.setAttribute(SecurityContext.class, context);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContext(SecurityContext context) {
|
||||
getSession().setAttribute(SecurityContext.class, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecurityContext createEmptyContext() {
|
||||
return new SecurityContextImpl();
|
||||
}
|
||||
|
||||
private static VaadinSession getSession() {
|
||||
VaadinSession session = VaadinSession.getCurrent();
|
||||
if (session == null) {
|
||||
session = new VaadinSession(VaadinService.getCurrent());
|
||||
VaadinSession.setCurrent(session);
|
||||
}
|
||||
return session;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
package com.faendir.acra.security;
|
||||
|
||||
import com.faendir.acra.data.App;
|
||||
import com.faendir.acra.data.AppManager;
|
||||
import com.vaadin.server.VaadinService;
|
||||
import com.vaadin.server.VaadinSession;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.config.BeanIds;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.context.SecurityContextImpl;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
|
||||
/**
|
||||
* @author Lukas
|
||||
* @since 22.03.2017
|
||||
*/
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
|
||||
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
static {
|
||||
SecurityContextHolder.setStrategyName(VaadinSessionSecurityContextHolderStrategy.class.getName());
|
||||
}
|
||||
|
||||
private final String user;
|
||||
private final String password;
|
||||
private final AppManager appManager;
|
||||
private final AuthenticationProvider authenticationProvider = new AuthenticationProvider() {
|
||||
@Override
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
if (authentication instanceof UsernamePasswordAuthenticationToken) {
|
||||
if (user.equals(authentication.getName())) {
|
||||
if (password.equals(authentication.getCredentials())) {
|
||||
return new UsernamePasswordAuthenticationToken(authentication.getName(), authentication.getCredentials(), AuthorityUtils.createAuthorityList("ROLE_ADMIN"));
|
||||
} else {
|
||||
throw new BadCredentialsException("Password mismatch for user " + authentication.getName());
|
||||
}
|
||||
}
|
||||
App app = appManager.getApp(authentication.getName());
|
||||
if (app != null) {
|
||||
if (app.getPassword().equals(authentication.getCredentials())) {
|
||||
Authentication auth = new UsernamePasswordAuthenticationToken(authentication.getName(), authentication.getCredentials(), AuthorityUtils.createAuthorityList("ROLE_REPORTER"));
|
||||
VaadinSession session = VaadinSession.getCurrent();
|
||||
if (session == null) session = new VaadinSession(VaadinService.getCurrent());
|
||||
VaadinSession.setCurrent(session);
|
||||
SecurityContext securityContext = new SecurityContextImpl();
|
||||
securityContext.setAuthentication(auth);
|
||||
session.setAttribute(SecurityContext.class, securityContext);
|
||||
return auth;
|
||||
} else {
|
||||
throw new BadCredentialsException("Password mismatch for user " + authentication.getName());
|
||||
}
|
||||
} else {
|
||||
throw new UsernameNotFoundException("Username " + authentication.getName() + " not found");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Class<?> authentication) {
|
||||
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
|
||||
}
|
||||
};
|
||||
|
||||
@Autowired
|
||||
public WebSecurityConfig(@Value("${security.user.name}") String user, @Value("${security.user.password}") String password, AppManager appManager) {
|
||||
this.user = user;
|
||||
this.password = password;
|
||||
this.appManager = appManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.authenticationProvider(authenticationProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.csrf().disable()
|
||||
.headers().disable()
|
||||
.httpBasic();
|
||||
}
|
||||
|
||||
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
|
||||
@Override
|
||||
public AuthenticationManager authenticationManagerBean() throws Exception {
|
||||
return authenticationManager();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.faendir.acra.service;
|
||||
|
||||
import com.faendir.acra.data.ReportManager;
|
||||
import org.json.JSONObject;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Lukas
|
||||
* @since 22.03.2017
|
||||
*/
|
||||
@RestController
|
||||
public class ReportService {
|
||||
private final ReportManager reportManager;
|
||||
|
||||
@Autowired
|
||||
public ReportService(ReportManager reportManager) {
|
||||
this.reportManager = reportManager;
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('REPORTER')")
|
||||
@RequestMapping(value = "/report", consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
public void report(@RequestBody String content) throws IOException {
|
||||
JSONObject jsonObject = new JSONObject(content);
|
||||
reportManager.newReport(jsonObject);
|
||||
}
|
||||
}
|
84
backend/src/main/java/com/faendir/acra/ui/BackendUI.java
Normal file
84
backend/src/main/java/com/faendir/acra/ui/BackendUI.java
Normal file
|
@ -0,0 +1,84 @@
|
|||
package com.faendir.acra.ui;
|
||||
|
||||
import com.faendir.acra.security.SecurityUtils;
|
||||
import com.faendir.acra.util.Style;
|
||||
import com.vaadin.annotations.Theme;
|
||||
import com.vaadin.server.VaadinRequest;
|
||||
import com.vaadin.server.VaadinService;
|
||||
import com.vaadin.spring.annotation.SpringUI;
|
||||
import com.vaadin.spring.annotation.UIScope;
|
||||
import com.vaadin.ui.Button;
|
||||
import com.vaadin.ui.HorizontalLayout;
|
||||
import com.vaadin.ui.LoginForm;
|
||||
import com.vaadin.ui.UI;
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
/**
|
||||
* @author Lukas
|
||||
* @since 22.03.2017
|
||||
*/
|
||||
@SpringUI
|
||||
@Theme("acratheme")
|
||||
public class BackendUI extends UI {
|
||||
private final AuthenticationManager authenticationManager;
|
||||
private final ApplicationContext applicationContext;
|
||||
private final VerticalLayout content;
|
||||
|
||||
@Autowired
|
||||
public BackendUI(AuthenticationManager authenticationManager, ApplicationContext applicationContext) {
|
||||
this.authenticationManager = authenticationManager;
|
||||
this.applicationContext = applicationContext;
|
||||
content = new VerticalLayout();
|
||||
content.setSizeFull();
|
||||
Style.NO_PADDING.apply(content);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init(VaadinRequest request) {
|
||||
if (SecurityUtils.isLoggedIn()) {
|
||||
showMain();
|
||||
} else {
|
||||
LoginForm loginForm = new LoginForm();
|
||||
loginForm.addLoginListener(event -> login(event.getLoginParameter("username"), event.getLoginParameter("password")));
|
||||
setContent(loginForm);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean login(String username, String password) {
|
||||
try {
|
||||
Authentication token = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
|
||||
VaadinService.reinitializeSession(VaadinService.getCurrentRequest());
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
showMain();
|
||||
return true;
|
||||
} catch (AuthenticationException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void showMain() {
|
||||
NavigationManager navigationManager = applicationContext.getBean(NavigationManager.class);
|
||||
HorizontalLayout header = new HorizontalLayout(new Button("Up", e -> navigationManager.navigateBack()));
|
||||
Style.apply(header, Style.MARGIN_TOP, Style.MARGIN_LEFT, Style.MARGIN_RIGHT);
|
||||
VerticalLayout root = new VerticalLayout(header, content);
|
||||
root.setExpandRatio(content, 1);
|
||||
root.setSizeFull();
|
||||
Style.NO_PADDING.apply(root);
|
||||
setContent(root);
|
||||
}
|
||||
|
||||
@UIScope
|
||||
@Bean
|
||||
public VerticalLayout mainView() {
|
||||
return content;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package com.faendir.acra.ui;
|
||||
|
||||
import com.faendir.acra.gen.ViewDefinition;
|
||||
import com.faendir.acra.ui.view.NamedView;
|
||||
import com.vaadin.navigator.Navigator;
|
||||
import com.vaadin.navigator.View;
|
||||
import com.vaadin.navigator.ViewProvider;
|
||||
import com.vaadin.spring.annotation.UIScope;
|
||||
import com.vaadin.ui.UI;
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author Lukas
|
||||
* @since 14.05.2017
|
||||
*/
|
||||
@UIScope
|
||||
@Component
|
||||
public class NavigationManager {
|
||||
private final Navigator navigator;
|
||||
private final ApplicationContext applicationContext;
|
||||
private final List<Class<?>> views;
|
||||
private final List<String> backStack;
|
||||
|
||||
@Autowired
|
||||
public NavigationManager(UI ui, VerticalLayout mainView, ApplicationContext applicationContext) {
|
||||
navigator = new Navigator(ui, mainView);
|
||||
backStack = new ArrayList<>();
|
||||
this.applicationContext = applicationContext;
|
||||
navigator.addProvider(new ViewProvider() {
|
||||
@Override
|
||||
public String getViewName(String viewAndParameters) {
|
||||
String name = viewAndParameters.split("/", 2)[0];
|
||||
if (views.stream().map(applicationContext::getBean).map(NamedView.class::cast).map(NamedView::getName).anyMatch(name::equals))
|
||||
return name;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(String viewName) {
|
||||
return views.stream().map(applicationContext::getBean).map(NamedView.class::cast).filter(view -> view.getName().equals(viewName)).findAny().orElse(null);
|
||||
}
|
||||
});
|
||||
views = ViewDefinition.getViewClasses();
|
||||
String target = Optional.ofNullable(ui.getPage().getLocation().getFragment()).orElse("").replace("!", "");
|
||||
backStack.add(target);
|
||||
navigator.navigateTo(target);
|
||||
}
|
||||
|
||||
public void navigateTo(Class<? extends NamedView> namedView, String contentId) {
|
||||
String target = applicationContext.getBean(namedView).getName() + (contentId == null ? "" : "/" + contentId);
|
||||
backStack.add(0, target);
|
||||
navigator.navigateTo(target);
|
||||
}
|
||||
|
||||
public void navigateBack() {
|
||||
if (backStack.size() < 2) {
|
||||
backStack.set(0, "");
|
||||
navigator.navigateTo("");
|
||||
} else {
|
||||
backStack.remove(0);
|
||||
navigator.navigateTo(backStack.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
73
backend/src/main/java/com/faendir/acra/ui/view/AppView.java
Normal file
73
backend/src/main/java/com/faendir/acra/ui/view/AppView.java
Normal file
|
@ -0,0 +1,73 @@
|
|||
package com.faendir.acra.ui.view;
|
||||
|
||||
import com.faendir.acra.data.App;
|
||||
import com.faendir.acra.data.AppManager;
|
||||
import com.faendir.acra.data.Report;
|
||||
import com.faendir.acra.data.ReportManager;
|
||||
import com.faendir.acra.util.Style;
|
||||
import com.vaadin.data.ValueProvider;
|
||||
import com.vaadin.navigator.ViewChangeListener;
|
||||
import com.vaadin.shared.ui.ContentMode;
|
||||
import com.vaadin.spring.annotation.UIScope;
|
||||
import com.vaadin.ui.Grid;
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.TabSheet;
|
||||
import com.vaadin.ui.UI;
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Lukas
|
||||
* @since 13.05.2017
|
||||
*/
|
||||
@UIScope
|
||||
@Component
|
||||
public class AppView extends NamedView {
|
||||
|
||||
private final AppManager appManager;
|
||||
private final ReportManager reportManager;
|
||||
|
||||
@Autowired
|
||||
public AppView(AppManager appManager, ReportManager reportManager) {
|
||||
this.appManager = appManager;
|
||||
this.reportManager = reportManager;
|
||||
}
|
||||
|
||||
private <T> Grid.Column addColumn(Grid<T> grid, ValueProvider<T, String> valueProvider, String caption) {
|
||||
Grid.Column column = grid.addColumn(valueProvider);
|
||||
column.setId(caption);
|
||||
column.setCaption(caption);
|
||||
return column;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "app";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enter(ViewChangeListener.ViewChangeEvent event) {
|
||||
App app = appManager.getApp(event.getParameters());
|
||||
List<Report> reportList = reportManager.getReports(app.getId());
|
||||
VerticalLayout statistics = new VerticalLayout(new Label("Coming soon"));
|
||||
statistics.setCaption("Statistics");
|
||||
statistics.setSizeFull();
|
||||
String location = UI.getCurrent().getPage().getLocation().toASCIIString();
|
||||
location = location.substring(0, location.indexOf('#'));
|
||||
VerticalLayout properties = new VerticalLayout(new Label(String.format("Required ACRA configuration:<br><code>formUri = \"%sreport\",<br>" +
|
||||
"formUriBasicAuthLogin = \"%s\",<br>formUriBasicAuthPassword = \"%s\",<br>httpMethod = HttpSender.Method.POST,<br>reportType = HttpSender.Type.JSON</code>",
|
||||
location, app.getId(), app.getPassword()), ContentMode.HTML));
|
||||
properties.setCaption("Properties");
|
||||
properties.setSizeFull();
|
||||
TabSheet tabSheet = new TabSheet(new BugTab(reportList, getNavigationManager()), new ReportList(reportList, getNavigationManager()), statistics, properties);
|
||||
tabSheet.setSizeFull();
|
||||
VerticalLayout content = new VerticalLayout(tabSheet);
|
||||
content.setSizeFull();
|
||||
Style.apply(content, Style.NO_PADDING, Style.PADDING_LEFT, Style.PADDING_RIGHT, Style.PADDING_BOTTOM);
|
||||
setCompositionRoot(content);
|
||||
setSizeFull();
|
||||
}
|
||||
}
|
46
backend/src/main/java/com/faendir/acra/ui/view/BugTab.java
Normal file
46
backend/src/main/java/com/faendir/acra/ui/view/BugTab.java
Normal file
|
@ -0,0 +1,46 @@
|
|||
package com.faendir.acra.ui.view;
|
||||
|
||||
import com.faendir.acra.data.Bug;
|
||||
import com.faendir.acra.data.Report;
|
||||
import com.faendir.acra.data.ReportUtils;
|
||||
import com.faendir.acra.ui.NavigationManager;
|
||||
import com.faendir.acra.util.StringUtils;
|
||||
import com.faendir.acra.util.Style;
|
||||
import com.vaadin.event.selection.SelectionEvent;
|
||||
import com.vaadin.ui.CustomComponent;
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Lukas
|
||||
* @since 17.05.2017
|
||||
*/
|
||||
public class BugTab extends CustomComponent {
|
||||
private final VerticalLayout root;
|
||||
private final NavigationManager navigationManager;
|
||||
|
||||
public BugTab(List<Report> reportList, NavigationManager navigationManager) {
|
||||
this.navigationManager = navigationManager;
|
||||
MyGrid<Bug> bugs = new MyGrid<>(null, ReportUtils.getBugs(reportList));
|
||||
bugs.setSizeFull();
|
||||
bugs.addColumn(bug -> String.valueOf(bug.getReports().size()), "Reports");
|
||||
bugs.addColumn(bug -> StringUtils.distanceFromNowAsString(bug.getLastDate()), "Latest Report");
|
||||
bugs.addColumn(bug -> String.valueOf(bug.getVersionCode()), "Version");
|
||||
bugs.addColumn(bug -> bug.getTrace().split("\n", 2)[0], "Stacktrace").setExpandRatio(1);
|
||||
bugs.addSelectionListener(this::handleBugSelection);
|
||||
root = new VerticalLayout(bugs);
|
||||
Style.NO_PADDING.apply(root);
|
||||
root.setSizeFull();
|
||||
setCompositionRoot(root);
|
||||
setSizeFull();
|
||||
setCaption("Bugs");
|
||||
}
|
||||
|
||||
private void handleBugSelection(SelectionEvent<Bug> e) {
|
||||
if(root.getComponentCount() == 2){
|
||||
root.removeComponent(root.getComponent(1));
|
||||
}
|
||||
e.getFirstSelectedItem().ifPresent(bug -> root.addComponent(new ReportList(bug.getReports(), navigationManager)));
|
||||
}
|
||||
}
|
23
backend/src/main/java/com/faendir/acra/ui/view/MyGrid.java
Normal file
23
backend/src/main/java/com/faendir/acra/ui/view/MyGrid.java
Normal file
|
@ -0,0 +1,23 @@
|
|||
package com.faendir.acra.ui.view;
|
||||
|
||||
import com.vaadin.data.ValueProvider;
|
||||
import com.vaadin.ui.Grid;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author Lukas
|
||||
* @since 14.05.2017
|
||||
*/
|
||||
public class MyGrid<T> extends Grid<T> {
|
||||
public MyGrid(String caption, Collection<T> items) {
|
||||
super(caption, items);
|
||||
}
|
||||
|
||||
public Grid.Column addColumn(ValueProvider<T, String> valueProvider, String caption) {
|
||||
Grid.Column column = addColumn(valueProvider);
|
||||
column.setId(caption);
|
||||
column.setCaption(caption);
|
||||
return column;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package com.faendir.acra.ui.view;
|
||||
|
||||
import com.faendir.acra.annotation.AutoDiscoverView;
|
||||
import com.faendir.acra.ui.NavigationManager;
|
||||
import com.vaadin.navigator.View;
|
||||
import com.vaadin.ui.CustomComponent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Lukas
|
||||
* @since 14.05.2017
|
||||
*/
|
||||
@AutoDiscoverView
|
||||
@Component
|
||||
public abstract class NamedView extends CustomComponent implements View {
|
||||
private NavigationManager navigationManager;
|
||||
|
||||
public abstract String getName();
|
||||
|
||||
NavigationManager getNavigationManager() {
|
||||
return navigationManager;
|
||||
}
|
||||
|
||||
@Lazy
|
||||
@Autowired
|
||||
public void setNavigationManager(NavigationManager navigationManager) {
|
||||
this.navigationManager = navigationManager;
|
||||
}
|
||||
}
|
74
backend/src/main/java/com/faendir/acra/ui/view/Overview.java
Normal file
74
backend/src/main/java/com/faendir/acra/ui/view/Overview.java
Normal file
|
@ -0,0 +1,74 @@
|
|||
package com.faendir.acra.ui.view;
|
||||
|
||||
import com.faendir.acra.data.App;
|
||||
import com.faendir.acra.data.AppManager;
|
||||
import com.faendir.acra.data.ReportManager;
|
||||
import com.faendir.acra.util.Style;
|
||||
import com.vaadin.navigator.ViewChangeListener;
|
||||
import com.vaadin.spring.annotation.UIScope;
|
||||
import com.vaadin.ui.Button;
|
||||
import com.vaadin.ui.Grid;
|
||||
import com.vaadin.ui.TextField;
|
||||
import com.vaadin.ui.UI;
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
import com.vaadin.ui.Window;
|
||||
import com.vaadin.ui.components.grid.FooterCell;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Lukas
|
||||
* @since 23.03.2017
|
||||
*/
|
||||
@UIScope
|
||||
@Component
|
||||
public class Overview extends NamedView {
|
||||
|
||||
private final AppManager appManager;
|
||||
private final ReportManager reportManager;
|
||||
private MyGrid<App> grid;
|
||||
|
||||
@Autowired
|
||||
public Overview(AppManager appManager, ReportManager reportManager) {
|
||||
this.appManager = appManager;
|
||||
this.reportManager = reportManager;
|
||||
}
|
||||
|
||||
private void addApp() {
|
||||
Window window = new Window("New App");
|
||||
TextField name = new TextField("Name");
|
||||
Button create = new Button("Create");
|
||||
create.addClickListener(e -> {
|
||||
appManager.createNewApp(name.getValue());
|
||||
window.close();
|
||||
grid.setItems(appManager.getApps());
|
||||
|
||||
});
|
||||
VerticalLayout layout = new VerticalLayout(name, create);
|
||||
window.setContent(layout);
|
||||
window.center();
|
||||
UI.getCurrent().addWindow(window);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enter(ViewChangeListener.ViewChangeEvent event) {
|
||||
grid = new MyGrid<>("Apps", appManager.getApps());
|
||||
grid.setSizeFull();
|
||||
Grid.Column column = grid.addColumn(App::getName, "Name");
|
||||
grid.addColumn(app -> String.valueOf(reportManager.getReports(app.getId()).size()), "Reports");
|
||||
FooterCell footerCell = grid.appendFooterRow().getCell(column.getId());
|
||||
Button add = new Button("New App");
|
||||
add.setSizeFull();
|
||||
add.addClickListener(e -> addApp());
|
||||
footerCell.setComponent(add);
|
||||
VerticalLayout layout = new VerticalLayout(grid);
|
||||
Style.apply(layout, Style.NO_PADDING, Style.PADDING_LEFT, Style.PADDING_RIGHT, Style.PADDING_BOTTOM);
|
||||
setCompositionRoot(layout);
|
||||
grid.addItemClickListener(e -> getNavigationManager().navigateTo(AppView.class, e.getItem().getId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package com.faendir.acra.ui.view;
|
||||
|
||||
import com.faendir.acra.data.Report;
|
||||
import com.faendir.acra.ui.NavigationManager;
|
||||
import com.faendir.acra.util.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Lukas
|
||||
* @since 14.05.2017
|
||||
*/
|
||||
public class ReportList extends MyGrid<Report> {
|
||||
public ReportList(List<Report> reportList, NavigationManager navigationManager) {
|
||||
super("Reports", reportList);
|
||||
setSizeFull();
|
||||
addColumn(report -> StringUtils.distanceFromNowAsString(report.getDate()), "Date");
|
||||
addReportColumn("APP_VERSION_NAME", "App Version");
|
||||
addReportColumn( "ANDROID_VERSION", "Android Version");
|
||||
addReportColumn("PHONE_MODEL", "Device");
|
||||
addColumn(report -> report.getContent().getString("STACK_TRACE").split("\n", 2)[0], "Stacktrace").setExpandRatio(1);
|
||||
addItemClickListener(e -> navigationManager.navigateTo(ReportView.class, e.getItem().getId()));
|
||||
}
|
||||
|
||||
|
||||
private void addReportColumn(String key, String caption) {
|
||||
addColumn(report -> report.getContent().getString(key), caption);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package com.faendir.acra.ui.view;
|
||||
|
||||
import com.faendir.acra.data.Report;
|
||||
import com.faendir.acra.data.ReportManager;
|
||||
import com.faendir.acra.util.Style;
|
||||
import com.vaadin.navigator.ViewChangeListener;
|
||||
import com.vaadin.shared.ui.ContentMode;
|
||||
import com.vaadin.spring.annotation.UIScope;
|
||||
import com.vaadin.ui.Alignment;
|
||||
import com.vaadin.ui.Component;
|
||||
import com.vaadin.ui.GridLayout;
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.Panel;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* @author Lukas
|
||||
* @since 13.05.2017
|
||||
*/
|
||||
@UIScope
|
||||
@org.springframework.stereotype.Component
|
||||
public class ReportView extends NamedView {
|
||||
|
||||
private final ReportManager reportManager;
|
||||
|
||||
@Autowired
|
||||
public ReportView(ReportManager reportManager) {
|
||||
this.reportManager = reportManager;
|
||||
}
|
||||
|
||||
private Stream<Component> getLayoutForEntry(String key, Object value) {
|
||||
return Stream.of(new Label(key, ContentMode.PREFORMATTED), getComponentForContent(value));
|
||||
}
|
||||
|
||||
private GridLayout getLayoutForMap(Map<String, ?> map) {
|
||||
GridLayout layout = new GridLayout(2, 1, map.entrySet().stream().sorted(Comparator.comparing(Map.Entry::getKey)).flatMap(entry -> getLayoutForEntry(entry.getKey(), entry.getValue())).toArray(Component[]::new));
|
||||
layout.setDefaultComponentAlignment(Alignment.MIDDLE_LEFT);
|
||||
layout.setSpacing(false);
|
||||
layout.setMargin(false);
|
||||
return layout;
|
||||
}
|
||||
|
||||
private Component getComponentForContent(Object value) {
|
||||
if (value instanceof Map) {
|
||||
//noinspection unchecked
|
||||
return getLayoutForMap((Map<String, ?>) value);
|
||||
} else if (value instanceof List) {
|
||||
//noinspection unchecked
|
||||
List<Object> values = (List<Object>) value;
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
for (int i = 0; i < values.size(); i++) {
|
||||
map.put(String.valueOf(i), values.get(0));
|
||||
}
|
||||
return getLayoutForMap(map);
|
||||
}
|
||||
return new Label(value.toString(), ContentMode.PREFORMATTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "report";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enter(ViewChangeListener.ViewChangeEvent event) {
|
||||
Report report = reportManager.getReport(event.getParameters());
|
||||
Component content = getLayoutForMap(report.getContent().toMap());
|
||||
Panel panel = new Panel(content);
|
||||
panel.setSizeFull();
|
||||
Style.apply(this, Style.PADDING_LEFT, Style.PADDING_RIGHT, Style.PADDING_BOTTOM);
|
||||
setCompositionRoot(panel);
|
||||
setSizeFull();
|
||||
}
|
||||
}
|
16
backend/src/main/java/com/faendir/acra/util/StringUtils.java
Normal file
16
backend/src/main/java/com/faendir/acra/util/StringUtils.java
Normal file
|
@ -0,0 +1,16 @@
|
|||
package com.faendir.acra.util;
|
||||
|
||||
import org.ocpsoft.prettytime.PrettyTime;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author Lukas
|
||||
* @since 14.05.2017
|
||||
*/
|
||||
public class StringUtils {
|
||||
|
||||
public static String distanceFromNowAsString(Date dateTime){
|
||||
return new PrettyTime().format(dateTime);
|
||||
}
|
||||
}
|
35
backend/src/main/java/com/faendir/acra/util/Style.java
Normal file
35
backend/src/main/java/com/faendir/acra/util/Style.java
Normal file
|
@ -0,0 +1,35 @@
|
|||
package com.faendir.acra.util;
|
||||
|
||||
import com.vaadin.ui.Component;
|
||||
|
||||
/**
|
||||
* @author Lukas
|
||||
* @since 17.05.2017
|
||||
*/
|
||||
public enum Style {
|
||||
NO_PADDING("no-padding"),
|
||||
PADDING_LEFT("padding-left"),
|
||||
PADDING_TOP("padding-top"),
|
||||
PADDING_RIGHT("padding-right"),
|
||||
PADDING_BOTTOM("padding-bottom"),
|
||||
MARGIN_LEFT("margin-left"),
|
||||
MARGIN_TOP("margin-top"),
|
||||
MARGIN_RIGHT("margin-right"),
|
||||
MARGIN_BOTTOM("margin-bottom"),
|
||||
BACKGROUND_LIGHT_GRAY("background-light-gray");
|
||||
final String name;
|
||||
|
||||
Style(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void apply(Component component) {
|
||||
component.addStyleName(name);
|
||||
}
|
||||
|
||||
public static void apply(Component component, Style... styles){
|
||||
for (Style style : styles){
|
||||
style.apply(component);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
@import "../valo/valo.scss";
|
||||
|
||||
@mixin acratheme {
|
||||
@include valo;
|
||||
|
||||
.v-gridlayout-slot {
|
||||
box-shadow: inset -1px -1px 0px 0px black;
|
||||
.v-widget {
|
||||
display: inline;
|
||||
padding-bottom: 4px;
|
||||
pre {
|
||||
padding-left: 6px;
|
||||
padding-right: 6px;
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
}
|
||||
.v-gridlayout-slot:last-child {
|
||||
box-shadow: inset -1px 0px 0px 0px black;
|
||||
}
|
||||
.v-gridlayout-slot:nth-last-child(2) {
|
||||
box-shadow: inset -1px 0px 0px 0px black;
|
||||
}
|
||||
|
||||
.no-padding {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
$padding: 10px;
|
||||
|
||||
.padding-left {
|
||||
padding-left: $padding !important;
|
||||
}
|
||||
|
||||
.padding-top {
|
||||
padding-top: $padding !important;
|
||||
}
|
||||
|
||||
.padding-right {
|
||||
padding-right: $padding !important;
|
||||
}
|
||||
|
||||
.padding-bottom {
|
||||
padding-bottom: $padding !important;
|
||||
}
|
||||
|
||||
$margin: 10px;
|
||||
|
||||
.margin-left {
|
||||
margin-left: $margin;
|
||||
}
|
||||
|
||||
.margin-top {
|
||||
margin-top: $margin;
|
||||
}
|
||||
|
||||
.margin-right {
|
||||
margin-right: $margin;
|
||||
}
|
||||
|
||||
.margin-bottom {
|
||||
margin-bottom: $margin;
|
||||
}
|
||||
|
||||
.background-light-gray {
|
||||
background: lightgray;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
/* This file is automatically managed and will be overwritten from time to time. */
|
||||
/* Do not manually edit this file. */
|
||||
|
||||
/* Import and include this mixin into your project theme to include the addon themes */
|
||||
@mixin addons {
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
@import "addons.scss";
|
||||
@import "acratheme.scss";
|
||||
|
||||
@include addons;
|
||||
@include acratheme;
|
8
backend/src/main/resources/application.properties
Normal file
8
backend/src/main/resources/application.properties
Normal file
|
@ -0,0 +1,8 @@
|
|||
spring.data.mongodb.port=27017
|
||||
spring.data.mongodb.host=127.0.0.1
|
||||
|
||||
security.user.name=admin
|
||||
security.user.password=admin
|
||||
security.user.role=USER
|
||||
|
||||
server.context-path=/acra
|
7
build.gradle
Normal file
7
build.gradle
Normal file
|
@ -0,0 +1,7 @@
|
|||
allprojects{
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
|
2
gradle.properties
Normal file
2
gradle.properties
Normal file
|
@ -0,0 +1,2 @@
|
|||
org.gradle.daemon=true
|
||||
org.gradle.jvmargs=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
|
172
gradlew
vendored
Normal file
172
gradlew
vendored
Normal file
|
@ -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" "$@"
|
84
gradlew.bat
vendored
Normal file
84
gradlew.bat
vendored
Normal file
|
@ -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
|
4
settings.gradle
Normal file
4
settings.gradle
Normal file
|
@ -0,0 +1,4 @@
|
|||
include 'backend'
|
||||
include 'annotation'
|
||||
include 'annotationprocessor'
|
||||
|
Loading…
Reference in a new issue