Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • arsnova/arsnova-backend
  • pcvl72/arsnova-backend
  • tksl38/arsnova-backend
3 results
Show changes
Commits on Source (340)
Showing
with 1451 additions and 627 deletions
......@@ -7,61 +7,66 @@ stages:
- post-build
- deploy
.maven_cache: &maven_cache
paths:
- .m2/
.maven: &maven
image: maven:3-jdk-11-slim
variables:
MAVEN_OPTS: "-Dhttps.protocols=TLSv1.2 -Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=WARN -Dorg.slf4j.simpleLogger.showDateTime=true -Dorg.slf4j.simpleLogger.dateTimeFormat=HH:mm:ss.SSS -Djava.awt.headless=true"
MAVEN_CLI_OPTS: "--batch-mode --fail-at-end --show-version"
cache:
key: maven-repository
paths:
- .m2/repository
checkstyle:
<<: *maven
stage: build
script:
- mvn $MAVEN_CLI_OPTS checkstyle:check -Dcheckstyle.missing-javadoc.severity=info
checkstyle_javadoc:
<<: *maven
stage: build
tags:
- maven
cache: *maven_cache
allow_failure: true
script:
- mvn -B checkstyle:check
- mvn $MAVEN_CLI_OPTS checkstyle:check -Dcheckstyle.missing-javadoc.severity=warning
compile:
<<: *maven
stage: build
tags:
- maven
artifacts:
paths:
- $OUTPUT_DIR
cache: *maven_cache
script:
- mvn -B test-compile
- mvn $MAVEN_CLI_OPTS test-compile
unit_test:
<<: *maven
stage: post-build
tags:
- maven
dependencies:
- compile
artifacts:
paths:
- $OUTPUT_DIR
cache: *maven_cache
coverage: '/Code coverage: \d+\.\d+/'
script:
- mvn -B surefire:test
- mvn $MAVEN_CLI_OPTS jacoco:prepare-agent surefire:test jacoco:report
- awk -F"," '{ instructions += $4 + $5; covered += $5 } END { print "Instructions covered:", covered, "/", instructions; print "Code coverage:", 100 * covered / instructions "%" }' "$OUTPUT_DIR/site/jacoco/jacoco.csv"
package:
<<: *maven
stage: post-build
tags:
- maven
dependencies:
- compile
artifacts:
name: package
paths:
- $WAR_FILE
cache: *maven_cache
script:
- mvn -B war:war
- mvn $MAVEN_CLI_OPTS war:war
.deploy: &deploy
stage: deploy
tags:
- python
image: python:3
when: manual
variables:
DEPLOY_CONTEXT: api
......@@ -109,15 +114,13 @@ tomcat_development:
- DEPLOY_HOST=$DEV_DEPLOY_HOST
sonarqube:
<<: *maven
stage: deploy
only:
- master
tags:
- maven
dependencies:
- compile
- unit_test
cache: *maven_cache
allow_failure: true
script:
- mvn -B sonar:sonar
- mvn $MAVEN_CLI_OPTS sonar:sonar
dist: trusty
dist: xenial
language: java
jdk:
- openjdk8
- oraclejdk8
sudo: false
notifications:
slack: f112a:GOZb6ewuAf2AVxduDXzdiCTG
email: admin@arsnova.eu
- openjdk11
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.2//EN"
"http://www.puppycrawl.com/dtds/configuration_1_2.dtd">
<!--
Checkstyle configuration that checks the sun coding conventions from:
- the Java Language Specification at
http://java.sun.com/docs/books/jls/second_edition/html/index.html
- the Sun Code Conventions at http://java.sun.com/docs/codeconv/
- the Javadoc guidelines at
http://java.sun.com/j2se/javadoc/writingdoccomments/index.html
- the JDK Api documentation http://java.sun.com/j2se/docs/api/index.html
- some best practices
Checkstyle is very configurable. Be sure to read the documentation at
http://checkstyle.sf.net (or in your downloaded distribution).
Most Checks are configurable, be sure to consult the documentation.
To completely disable a check, just comment it out or delete it from the file.
Finally, it is worth reading the documentation.
-->
<module name="Checker">
<!--
If you set the basedir property below, then all reported file
names will be relative to the specified directory. See
http://checkstyle.sourceforge.net/5.x/config.html#Checker
<property name="basedir" value="${basedir}"/>
-->
<!-- Checks that each Java package has a Javadoc file used for commenting. -->
<!-- See http://checkstyle.sf.net/config_javadoc.html#JavadocPackage -->
<module name="JavadocPackage">
<property name="allowLegacy" value="true"/>
</module>
<!-- Checks whether files end with a new line. -->
<!-- See http://checkstyle.sf.net/config_misc.html#NewlineAtEndOfFile -->
<module name="NewlineAtEndOfFile"/>
<!-- Checks that property files contain the same keys. -->
<!-- See http://checkstyle.sf.net/config_misc.html#Translation -->
<module name="Translation"/>
<module name="FileLength"/>
<!-- Following interprets the header file as regular expressions. -->
<!-- <module name="RegexpHeader"/> -->
<!--module name="FileTabCharacter">
<property name="eachLine" value="true"/>
</module-->
<module name="RegexpSingleline">
<!-- \s matches whitespace character, $ matches end of line. -->
<property name="format" value="\s+$"/>
<property name="message" value="Line has trailing spaces."/>
</module>
<module name="TreeWalker">
<property name="cacheFile" value="${checkstyle.cache.file}"/>
<property name="tabWidth" value="4"/>
<!-- Checks for Javadoc comments. -->
<!-- See http://checkstyle.sf.net/config_javadoc.html -->
<!-- module name="JavadocMethod">
<property name="allowMissingJavadoc" value="true"/>
</module>
<module name="JavadocType"/>
<module name="JavadocVariable"/>
<module name="JavadocStyle"/-->
<!-- Checks for Naming Conventions. -->
<!-- See http://checkstyle.sf.net/config_naming.html -->
<module name="ConstantName"/>
<module name="LocalFinalVariableName"/>
<module name="LocalVariableName"/>
<module name="MemberName"/>
<module name="MethodName"/>
<module name="PackageName"/>
<module name="ParameterName"/>
<module name="StaticVariableName"/>
<module name="TypeName"/>
<!-- Checks for Headers -->
<!-- See http://checkstyle.sf.net/config_header.html -->
<!-- <module name="Header"> -->
<!-- The follow property value demonstrates the ability -->
<!-- to have access to ANT properties. In this case it uses -->
<!-- the ${basedir} property to allow Checkstyle to be run -->
<!-- from any directory within a project. See property -->
<!-- expansion, -->
<!-- http://checkstyle.sf.net/config.html#properties -->
<!-- <property -->
<!-- name="headerFile" -->
<!-- value="${basedir}/java.header"/> -->
<!-- </module> -->
<!-- Checks for imports -->
<!-- See http://checkstyle.sf.net/config_import.html -->
<module name="AvoidStarImport"/>
<module name="IllegalImport"/> <!-- defaults to sun.* packages -->
<module name="RedundantImport"/>
<module name="UnusedImports"/>
<!-- Checks for Size Violations. -->
<!-- See http://checkstyle.sf.net/config_sizes.html -->
<module name="LineLength">
<property name="max" value="120" />
</module>
<module name="MethodLength"/>
<module name="ParameterNumber"/>
<!-- Checks for whitespace -->
<!-- See http://checkstyle.sf.net/config_whitespace.html -->
<module name="EmptyForIteratorPad"/>
<module name="MethodParamPad"/>
<module name="NoWhitespaceAfter"/>
<module name="NoWhitespaceBefore"/>
<module name="OperatorWrap"/>
<module name="ParenPad"/>
<module name="TypecastParenPad"/>
<module name="WhitespaceAfter"/>
<module name="WhitespaceAround"/>
<!-- Modifier Checks -->
<!-- See http://checkstyle.sf.net/config_modifiers.html -->
<module name="ModifierOrder"/>
<module name="RedundantModifier"/>
<!-- Checks for blocks. You know, those {}'s -->
<!-- See http://checkstyle.sf.net/config_blocks.html -->
<module name="AvoidNestedBlocks"/>
<module name="EmptyBlock"/>
<module name="LeftCurly"/>
<module name="NeedBraces"/>
<module name="RightCurly"/>
<!-- Checks for common coding problems -->
<!-- See http://checkstyle.sf.net/config_coding.html -->
<!-- module name="AvoidInlineConditionals" /-->
<!-- module name="DoubleCheckedLocking"/--> <!-- MY FAVOURITE -->
<module name="EmptyStatement"/>
<module name="EqualsHashCode"/>
<module name="HiddenField">
<property name="ignoreSetter" value="true"/>
</module>
<module name="IllegalInstantiation"/>
<module name="InnerAssignment"/>
<module name="MagicNumber"/>
<module name="MissingSwitchDefault"/>
<!-- module name="RedundantThrows"/ -->
<module name="SimplifyBooleanExpression"/>
<module name="SimplifyBooleanReturn"/>
<!-- Checks for class design -->
<!-- See http://checkstyle.sf.net/config_design.html -->
<!-- module name="DesignForExtension"/ -->
<!-- module name="FinalClass"/ -->
<module name="HideUtilityClassConstructor"/>
<module name="InterfaceIsType"/>
<module name="VisibilityModifier"/>
<!-- Miscellaneous other checks. -->
<!-- See http://checkstyle.sf.net/config_misc.html -->
<module name="ArrayTypeStyle"/>
<!-- module name="FinalParameters"/ -->
<module name="TodoComment"/>
<module name="UpperEll"/>
</module>
</module>
# Changelog
## 2.7.3
This is a maintenance release which only brings libraries up to date to fix
potential bugs.
## 2.7.2
This is a maintenance release which only brings libraries up to date to fix
potential bugs.
## 2.7.1
This is a maintenance release which only brings libraries up to date to fix
potential bugs.
## 2.6.4
This is a maintenance release which only brings libraries up to date to fix
potential bugs.
## 2.5.10
This is a maintenance release which only brings libraries up to date to fix
potential bugs.
## 2.7
Features:
* Account deletion: Users can now delete their own accounts. Admins can delete
any user account. Account deletion removes sessions and their contents created
by the user and anonymizes data created through participation in other
sessions.
* Auto-deletion: Accounts can be deleted automatically after a configurable
period of inactivity.
* OpenID Connect: OIDC is now supported for authentication. Configuration
discovery support is required.
Improvements:
* Public Session Pool: Added API endpoint to clone a session from the pool.
Previously, cloning had to be performed by the client.
Bug fixes:
* Import/Export: The handling of session features during import has been fixed.
The raw exported data can now be imported without further manipulation by the
client.
**This version is brought to you by:**
Project management: Klaus Quibeldey-Cirkel
Lead programming: Daniel Gerhardt, Tom "tekay" Käsler
Sponsoring: [AG QLS](https://www.thm.de/site/en/hochschule/service/ag-qls.html),
[HMWK](https://wissenschaft.hessen.de/wissenschaft/it-neue-medien/kompetenznetz-e-learning-hessen)
## 2.6.3
Bug fixes:
* The backend now correctly responds with 4xx error codes instead of 500 to less
common errors caused by bad requests from the client-side.
Additional changes:
* Libraries have been upgraded to fix potential bugs.
## 2.5.9
This is a maintenance release which only brings libraries up to date to fix
potential bugs.
## 2.6.2
This is a maintenance release which only brings libraries up to date to fix
potential bugs.
......
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
"https://checkstyle.org/dtds/configuration_1_3.dtd">
<!--
Checkstyle configuration that checks the coding conventions for ARSnova Java
projects. The conventions and configuration are based on Google coding
conventions from Google Java Style that can be found at
https://google.github.io/styleguide/javaguide.html.
Checkstyle is very configurable. Be sure to read the documentation at
http://checkstyle.sf.net (or in your downloaded distribution).
To completely disable a check, just comment it out or delete it from the file.
Original authors: Max Vetrenko, Ruslan Diachenko, Roman Ivanov.
-->
<module name="Checker">
<property name="charset" value="UTF-8"/>
<property name="severity" value="warning"/>
<module name="SeverityMatchFilter">
<property name="severity" value="info"/>
<property name="acceptOnMatch" value="false"/>
</module>
<property name="fileExtensions" value="java, properties, xml"/>
<!-- Excludes all 'module-info.java' files -->
<!-- See https://checkstyle.org/config_filefilters.html -->
<module name="BeforeExecutionExclusionFileFilter">
<property name="fileNamePattern" value="module\-info\.java$"/>
</module>
<module name="TreeWalker">
<!-- Checks for whitespace -->
<property name="tabWidth" value="2"/>
<module name="RegexpSinglelineJava">
<property name="format" value="^\t* "/>
<property name="message" value="Indent must use tab characters"/>
<property name="ignoreComments" value="true"/>
</module>
<module name="OuterTypeFilename"/>
<module name="IllegalTokenText">
<property name="tokens" value="STRING_LITERAL, CHAR_LITERAL"/>
<property name="format"
value="\\u00(09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/>
<property name="message"
value="Consider using special escape sequence instead of octal value or Unicode escaped value."/>
</module>
<module name="AvoidEscapedUnicodeCharacters">
<property name="allowEscapesForControlCharacters" value="true"/>
<property name="allowByTailComment" value="true"/>
<property name="allowNonPrintableEscapes" value="true"/>
</module>
<module name="LineLength">
<property name="max" value="120"/>
<property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
</module>
<module name="AvoidStarImport"/>
<module name="OneTopLevelClass"/>
<module name="NoLineWrap"/>
<module name="EmptyBlock">
<property name="option" value="TEXT"/>
<property name="tokens"
value="LITERAL_TRY, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/>
</module>
<module name="NeedBraces"/>
<module name="LeftCurly"/>
<module name="RightCurly">
<property name="id" value="RightCurlySame"/>
<property name="tokens"
value="LITERAL_TRY, LITERAL_CATCH, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE,
LITERAL_DO"/>
</module>
<module name="RightCurly">
<property name="id" value="RightCurlyAlone"/>
<property name="option" value="alone"/>
<property name="tokens"
value="CLASS_DEF, METHOD_DEF, CTOR_DEF, LITERAL_FOR, LITERAL_WHILE, STATIC_INIT,
INSTANCE_INIT"/>
</module>
<module name="WhitespaceAround">
<property name="allowEmptyConstructors" value="true"/>
<property name="allowEmptyLambdas" value="true"/>
<property name="allowEmptyMethods" value="true"/>
<property name="allowEmptyTypes" value="true"/>
<property name="allowEmptyLoops" value="true"/>
<message key="ws.notFollowed"
value="WhitespaceAround: ''{0}'' is not followed by whitespace. Empty blocks may only be represented as '{}' when not part of a multi-block statement (4.1.3)"/>
<message key="ws.notPreceded"
value="WhitespaceAround: ''{0}'' is not preceded with whitespace."/>
</module>
<module name="OneStatementPerLine"/>
<module name="MultipleVariableDeclarations"/>
<module name="ArrayTypeStyle"/>
<module name="MissingSwitchDefault"/>
<module name="FallThrough"/>
<module name="UpperEll"/>
<module name="ModifierOrder"/>
<module name="EmptyLineSeparator">
<property name="allowNoEmptyLineBetweenFields" value="true"/>
</module>
<module name="SeparatorWrap">
<property name="id" value="SeparatorWrapDot"/>
<property name="tokens" value="DOT"/>
<property name="option" value="nl"/>
</module>
<module name="SeparatorWrap">
<property name="id" value="SeparatorWrapComma"/>
<property name="tokens" value="COMMA"/>
<property name="option" value="EOL"/>
</module>
<module name="SeparatorWrap">
<!-- ELLIPSIS is EOL until https://github.com/google/styleguide/issues/258 -->
<property name="id" value="SeparatorWrapEllipsis"/>
<property name="tokens" value="ELLIPSIS"/>
<property name="option" value="EOL"/>
</module>
<module name="SeparatorWrap">
<!-- ARRAY_DECLARATOR is EOL until https://github.com/google/styleguide/issues/259 -->
<property name="id" value="SeparatorWrapArrayDeclarator"/>
<property name="tokens" value="ARRAY_DECLARATOR"/>
<property name="option" value="EOL"/>
</module>
<module name="SeparatorWrap">
<property name="id" value="SeparatorWrapMethodRef"/>
<property name="tokens" value="METHOD_REF"/>
<property name="option" value="nl"/>
</module>
<module name="PackageName">
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
<message key="name.invalidPattern"
value="Package name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="TypeName">
<message key="name.invalidPattern"
value="Type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="MemberName">
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
<message key="name.invalidPattern"
value="Member name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="ParameterName">
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
<message key="name.invalidPattern"
value="Parameter name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="LambdaParameterName">
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
<message key="name.invalidPattern"
value="Lambda parameter name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="CatchParameterName">
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
<message key="name.invalidPattern"
value="Catch parameter name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="LocalVariableName">
<property name="tokens" value="VARIABLE_DEF"/>
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
<message key="name.invalidPattern"
value="Local variable name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="ClassTypeParameterName">
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
<message key="name.invalidPattern"
value="Class type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="MethodTypeParameterName">
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
<message key="name.invalidPattern"
value="Method type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="InterfaceTypeParameterName">
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
<message key="name.invalidPattern"
value="Interface type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="NoFinalizer"/>
<module name="GenericWhitespace">
<message key="ws.followed"
value="GenericWhitespace ''{0}'' is followed by whitespace."/>
<message key="ws.preceded"
value="GenericWhitespace ''{0}'' is preceded with whitespace."/>
<message key="ws.illegalFollow"
value="GenericWhitespace ''{0}'' should followed by whitespace."/>
<message key="ws.notPreceded"
value="GenericWhitespace ''{0}'' is not preceded with whitespace."/>
</module>
<module name="Indentation">
<property name="basicOffset" value="2"/>
<property name="braceAdjustment" value="0"/>
<property name="caseIndent" value="2"/>
<property name="throwsIndent" value="4"/>
<property name="lineWrappingIndentation" value="4"/>
<property name="arrayInitIndent" value="2"/>
</module>
<module name="AbbreviationAsWordInName">
<property name="ignoreFinal" value="false"/>
<property name="allowedAbbreviationLength" value="1"/>
</module>
<module name="OverloadMethodsDeclarationOrder"/>
<module name="VariableDeclarationUsageDistance"/>
<module name="CustomImportOrder">
<property name="sortImportsInGroupAlphabetically" value="true"/>
<property name="separateLineBetweenGroups" value="true"/>
<property name="customImportOrderRules" value="STATIC###THIRD_PARTY_PACKAGE###SPECIAL_IMPORTS"/>
<property name="specialImportsRegExp" value="^de\.thm\.arsnova"/>
</module>
<module name="MethodParamPad"/>
<module name="NoWhitespaceBefore">
<property name="tokens"
value="COMMA, SEMI, POST_INC, POST_DEC, DOT, ELLIPSIS, METHOD_REF"/>
<property name="allowLineBreaks" value="true"/>
</module>
<module name="ParenPad"/>
<module name="OperatorWrap">
<property name="option" value="NL"/>
<property name="tokens"
value="BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR,
LT, MINUS, MOD, NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR, METHOD_REF "/>
</module>
<module name="AnnotationLocation">
<property name="id" value="AnnotationLocationMostCases"/>
<property name="tokens"
value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF"/>
</module>
<module name="AnnotationLocation">
<property name="id" value="AnnotationLocationVariables"/>
<property name="tokens" value="VARIABLE_DEF"/>
<property name="allowSamelineMultipleAnnotations" value="true"/>
</module>
<module name="NonEmptyAtclauseDescription"/>
<module name="JavadocTagContinuationIndentation"/>
<module name="SummaryJavadoc">
<property name="forbiddenSummaryFragments"
value="^@return the *|^This method returns |^A [{]@code [a-zA-Z0-9]+[}]( is a )"/>
</module>
<module name="JavadocParagraph"/>
<module name="AtclauseOrder">
<property name="tagOrder" value="@param, @return, @throws, @deprecated"/>
<property name="target"
value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/>
</module>
<module name="JavadocMethod">
<property name="scope" value="public"/>
<property name="allowMissingParamTags" value="true"/>
<property name="allowMissingThrowsTags" value="true"/>
<property name="allowMissingReturnTag" value="true"/>
<property name="allowedAnnotations" value="Override, Test"/>
<property name="allowThrowsTagsForSubclasses" value="true"/>
</module>
<module name="MissingJavadocMethod">
<property name="severity" value="${checkstyle.missing-javadoc.severity}" default="warning"/>
<property name="scope" value="public"/>
<property name="minLineCount" value="2"/>
<property name="allowedAnnotations" value="Override, Test"/>
</module>
<module name="MethodName">
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9_]*$"/>
<message key="name.invalidPattern"
value="Method name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="SingleLineJavadoc">
<property name="ignoreInlineTags" value="false"/>
</module>
<module name="EmptyCatchBlock">
<property name="exceptionVariableName" value="expected"/>
</module>
<module name="CommentsIndentation"/>
<!-- ARSnova-specific rules -->
<module name="FinalLocalVariable">
<property name="tokens" value="VARIABLE_DEF,PARAMETER_DEF"/>
<property name="validateEnhancedForLoopVariable" value="true"/>
</module>
<module name="RedundantModifier"/>
<module name="RedundantImport"/>
<module name="UnusedImports"/>
</module>
</module>
......@@ -7,12 +7,18 @@
<packaging>war</packaging>
<properties>
<io.spring.platform-version>Cairo-SR5</io.spring.platform-version>
<io.netty-version>4.1.30.Final</io.netty-version>
<org.aspectj-version>1.8.13</org.aspectj-version>
<spring-boot-version>2.2.0.RELEASE</spring-boot-version>
<commons-lang-version>2.6</commons-lang-version>
<guava-version>28.1-jre</guava-version>
<directory-server-version>1.5.5</directory-server-version>
<io.netty-version>4.1.39.Final</io.netty-version>
<org.aspectj-version>1.9.4</org.aspectj-version>
<jakarta-xml-bind.version>2.3.2</jakarta-xml-bind.version>
<graalvm.version>19.2.0</graalvm.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<timestamp>${maven.build.timestamp}</timestamp>
<sonar.language>java</sonar.language>
<checkstyle.missing-javadoc.severity>warning</checkstyle.missing-javadoc.severity>
</properties>
<developers>
......@@ -71,9 +77,13 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.0.1</version>
<version>3.1.1</version>
<configuration></configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</reporting>
......@@ -122,9 +132,10 @@
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.spring.platform</groupId>
<artifactId>platform-bom</artifactId>
<version>${io.spring.platform-version}</version>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
......@@ -139,9 +150,14 @@
</dependencyManagement>
<dependencies>
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>${commons-lang-version}</version>
</dependency>
<!-- Spring -->
<dependency>
......@@ -152,6 +168,10 @@
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
......@@ -160,6 +180,20 @@
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.projectreactor.netty</groupId>
<artifactId>reactor-netty</artifactId>
</dependency>
<!-- Security -->
<dependency>
<groupId>org.springframework.security</groupId>
......@@ -185,9 +219,35 @@
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-jmx</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator-annotation-processor</artifactId>
</dependency>
<!-- A jakarta.el-api (Unified Expression Language) implementation is needed for bean validation. -->
<dependency>
<groupId>org.mortbay.jasper</groupId>
<artifactId>apache-el</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava-version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
......@@ -216,18 +276,17 @@
<version>1.5.0</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
<artifactId>jakarta.mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
......@@ -235,6 +294,16 @@
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
......@@ -243,22 +312,27 @@
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.1</version>
<version>3.8.2</version>
</dependency>
<dependency>
<groupId>org.pac4j</groupId>
<artifactId>pac4j-oauth</artifactId>
<version>2.3.1</version>
<version>3.8.1</version>
</dependency>
<dependency>
<groupId>com.corundumstudio.socketio</groupId>
<artifactId>netty-socketio</artifactId>
<version>1.7.16</version>
<groupId>org.pac4j</groupId>
<artifactId>pac4j-oidc</artifactId>
<version>3.8.1</version>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<scope>test</scope>
<groupId>org.pac4j</groupId>
<artifactId>pac4j-saml</artifactId>
<version>3.8.1</version>
</dependency>
<dependency>
<groupId>com.corundumstudio.socketio</groupId>
<artifactId>netty-socketio</artifactId>
<version>1.7.17</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
......@@ -272,6 +346,10 @@
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
......@@ -285,10 +363,19 @@
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
<dependency>
<groupId>org.graalvm.js</groupId>
<artifactId>js</artifactId>
<version>${graalvm.version}</version>
</dependency>
<dependency>
<groupId>org.graalvm.js</groupId>
<artifactId>js-scriptengine</artifactId>
<version>${graalvm.version}</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
......@@ -301,30 +388,20 @@
<artifactId>json-path-assert</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.directory.server</groupId>
<artifactId>apacheds-core</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.directory.server</groupId>
<artifactId>apacheds-server-jndi</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.5.21</version>
</dependency>
<dependency>
<groupId>com.codahale.metrics</groupId>
<artifactId>metrics-annotation</artifactId>
<version>3.0.2</version>
<version>1.5.23</version>
</dependency>
<dependency>
<groupId>org.checkerframework</groupId>
<artifactId>checker-qual</artifactId>
<version>2.5.6</version>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>jakarta.websocket</groupId>
<artifactId>jakarta.websocket-api</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
......@@ -356,6 +433,12 @@
<source>1.8</source>
<target>1.8</target>
<aspectLibraries>
<!-- Disabled for now, see https://github.com/micrometer-metrics/micrometer/issues/1149.
<aspectLibrary>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
</aspectLibrary>
-->
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
......@@ -386,12 +469,20 @@
<artifactId>aspectjtools</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<!-- Workaround: Override unnecessary dependency which causes compatibility issues. -->
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>${java.version}</version>
<scope>system</scope>
<systemPath>${project.basedir}/pom.xml</systemPath>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
......@@ -400,7 +491,7 @@
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.4.12.v20180830</version>
<version>9.4.19.v20190610</version>
<configuration>
<scanIntervalSeconds>0</scanIntervalSeconds>
<webApp>
......@@ -421,7 +512,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
<version>3.8.2</version>
<configuration>
<locales>en</locales>
</configuration>
......@@ -429,17 +520,17 @@
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.5.0.1254</version>
<version>3.6.1.1688</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
<version>2.22.2</version>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.2</version>
<version>0.8.4</version>
<executions>
<execution>
<id>default-prepare-agent</id>
......@@ -459,9 +550,20 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.0.0</version>
<version>3.1.0</version>
<dependencies>
<dependency>
<groupId>com.puppycrawl.tools</groupId>
<artifactId>checkstyle</artifactId>
<version>8.21</version>
</dependency>
</dependencies>
<configuration>
<configLocation>ARSnova-checkstyle-checker.xml</configLocation>
<configLocation>checkstyle.xml</configLocation>
<violationSeverity>warning</violationSeverity>
<propertyExpansion>
checkstyle.missing-javadoc.severity=${checkstyle.missing-javadoc.severity}
</propertyExpansion>
</configuration>
</plugin>
<plugin>
......@@ -477,12 +579,12 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
<version>3.2.3</version>
</plugin>
<plugin>
<groupId>com.github.kongchen</groupId>
<artifactId>swagger-maven-plugin</artifactId>
<version>3.1.7</version>
<version>3.1.8</version>
<configuration>
<apiSources>
<apiSource>
......@@ -505,6 +607,7 @@
</contact>
</info>
<swaggerDirectory>${project.build.directory}/classes</swaggerDirectory>
<outputFormats>json</outputFormats>
</apiSource>
</apiSources>
</configuration>
......@@ -516,11 +619,18 @@
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>${jakarta-xml-bind.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<version>2.2.5</version>
<version>3.0.1</version>
<executions>
<execution>
<goals>
......@@ -530,6 +640,18 @@
</executions>
</plugin>
</plugins>
<!-- Workaround for JDK 11 support. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=539791 -->
<extensions>
<extension>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
</extension>
<extension>
<groupId>javax.annotation</groupId>
<artifactId>jsr250-api</artifactId>
</extension>
</extensions>
</build>
<name>ARSnova Backend</name>
......
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2018 The ARSnova Team and Contributors
* Copyright (C) 2012-2019 The ARSnova Team and Contributors
*
* ARSnova Backend is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -15,9 +15,12 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.thm.arsnova.cache;
/**
* This interface is used as a tag to make Spring dependency injection happy...
*/
public interface CacheBuster { }
public interface CacheBuster {
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2018 The ARSnova Team and Contributors
* Copyright (C) 2012-2019 The ARSnova Team and Contributors
*
* ARSnova Backend is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -15,116 +15,60 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.thm.arsnova.cache;
import de.thm.arsnova.event.*;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import de.thm.arsnova.event.AfterCreationEvent;
import de.thm.arsnova.event.AfterDeletionEvent;
import de.thm.arsnova.event.ChangeScoreEvent;
import de.thm.arsnova.model.Answer;
import de.thm.arsnova.model.Comment;
import de.thm.arsnova.model.Room;
/**
* This class is used to evict caches based on events. The events carry all necessary information to clear the
* caches, e.g, for a specific session.
*/
@Component
public class CacheBusterImpl implements CacheBuster, ArsnovaEventVisitor {
public class CacheBusterImpl implements CacheBuster {
@CacheEvict(value = "statistics", allEntries = true)
@Override
public void visit(NewCommentEvent event) { }
@EventListener
public void handleAfterCommentCreation(final AfterCreationEvent<Comment> event) {
/* Implementation provided by caching aspect. */
}
@CacheEvict(value = "statistics", allEntries = true)
@Override
public void visit(DeleteCommentEvent event) { }
@Override
public void visit(NewQuestionEvent event) { }
@Override
public void visit(UnlockQuestionEvent event) { }
@Override
public void visit(UnlockQuestionsEvent newQuestionsEvent) { }
@Override
public void visit(LockQuestionEvent lockQuestionEvent) { }
@Override
public void visit(LockQuestionsEvent lockQuestionsEvent) { }
@EventListener
public void handleAfterCommentDeletion(final AfterDeletionEvent<Comment> event) {
/* Implementation provided by caching aspect. */
}
@CacheEvict(value = "answerlists", key = "#event.content.id")
@Override
public void visit(NewAnswerEvent event) { }
@Override
public void visit(DeleteAnswerEvent event) { }
@Override
public void visit(DeleteQuestionEvent event) { }
@Override
public void visit(DeleteAllQuestionsEvent event) { }
@Override
public void visit(DeleteAllQuestionsAnswersEvent event) { }
@Override
public void visit(DeleteAllPreparationAnswersEvent event) { }
@Override
public void visit(DeleteAllLectureAnswersEvent event) { }
@Override
public void visit(NewFeedbackEvent event) { }
@Override
public void visit(DeleteFeedbackForRoomsEvent event) { }
@Override
public void visit(StatusRoomEvent event) { }
@EventListener
public void handleAfterAnswerCreation(final AfterCreationEvent<Answer> event) {
/* Implementation provided by caching aspect. */
}
@CacheEvict(value = "statistics", allEntries = true)
@Override
public void visit(ChangeScoreEvent changeLearningProgress) { }
@Override
public void visit(PiRoundDelayedStartEvent piRoundDelayedStartEvent) { }
@Override
public void visit(PiRoundEndEvent piRoundEndEvent) { }
@Override
public void visit(PiRoundCancelEvent piRoundCancelEvent) { }
@Override
public void visit(PiRoundResetEvent piRoundResetEvent) { }
@EventListener
public void handleChangeScore(final ChangeScoreEvent event) {
/* Implementation provided by caching aspect. */
}
@CacheEvict(value = "statistics", allEntries = true)
@Override
public void visit(NewRoomEvent newSessionEvent) { }
@EventListener
public void handleAfterRoomCreation(final AfterCreationEvent<Room> event) {
/* Implementation provided by caching aspect. */
}
@CacheEvict(value = "statistics", allEntries = true)
@Override
public void visit(DeleteRoomEvent deleteSessionEvent) { }
@Override
public void visit(LockVoteEvent lockVoteEvent) { }
@Override
public void visit(LockVotesEvent lockVotesEvent) { }
@Override
public void visit(UnlockVoteEvent unlockVoteEvent) { }
@Override
public void visit(UnlockVotesEvent unlockVotesEvent) { }
@Override
public void visit(FeatureChangeEvent featureChangeEvent) { }
@Override
public void visit(LockFeedbackEvent lockFeedbackEvent) { }
@Override
public void visit(FlipFlashcardsEvent flipFlashcardsEvent) { }
@EventListener
public void handleAfterRoomDeletion(final AfterDeletionEvent<Room> event) {
/* Implementation provided by caching aspect. */
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2018 The ARSnova Team and Contributors
* Copyright (C) 2012-2019 The ARSnova Team and Contributors
*
* ARSnova Backend is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -15,13 +15,16 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.thm.arsnova.cache;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/** This component cleares caches at fixed time intervals:
/** This component cleares caches at fixed time intervals.
*
* <p>Time intervals:
* <ul>
* <li><code>sessions</code>: 6h</li>
* <li><code>skillquestions</code>, <code>lecturequestions</code>, <code>preparationquestions</code>,
......@@ -30,40 +33,57 @@ import org.springframework.stereotype.Component;
* <li><code>answers</code>: 15min</li>
* <li><code>learningprogress</code>: 15min</li>
* </ul>
* </p>
*/
@Component
public class ScheduledCacheBuster {
@CacheEvict(value = "rooms", allEntries = true)
@Scheduled(initialDelay = 1000 * 25, fixedRate = 1000 * 60 * 60 * 6)
private void clearSessionCache() { }
private void clearSessionCache() {
/* Implementation provided by caching aspect. */
}
@CacheEvict(value = "contents", allEntries = true)
@Scheduled(initialDelay = 1000 * 50, fixedRate = 1000 * 60 * 30)
private void clearQuestionCache() { }
private void clearQuestionCache() {
/* Implementation provided by caching aspect. */
}
@CacheEvict(value = "contentlists", allEntries = true)
@Scheduled(initialDelay = 1000 * 75, fixedRate = 1000 * 60 * 30)
private void clearSkillQuestionCache() { }
private void clearSkillQuestionCache() {
/* Implementation provided by caching aspect. */
}
@CacheEvict(value = "lecturecontentlists", allEntries = true)
@Scheduled(initialDelay = 1000 * 100, fixedRate = 1000 * 60 * 30)
private void clearLectureQuestionCache() { }
private void clearLectureQuestionCache() {
/* Implementation provided by caching aspect. */
}
@CacheEvict(value = "preparationcontentlists", allEntries = true)
@Scheduled(initialDelay = 1000 * 125, fixedRate = 1000 * 60 * 30)
private void clearPreparationQuestionCache() { }
private void clearPreparationQuestionCache() {
/* Implementation provided by caching aspect. */
}
@CacheEvict(value = "flashcardcontentlists", allEntries = true)
@Scheduled(initialDelay = 1000 * 150, fixedRate = 1000 * 60 * 30)
private void clearFlashcardQuestionCache() { }
private void clearFlashcardQuestionCache() {
/* Implementation provided by caching aspect. */
}
@CacheEvict(value = "answerlists", allEntries = true)
@Scheduled(initialDelay = 1000 * 175, fixedRate = 1000 * 60 * 15)
private void clearAnswerCache() { }
private void clearAnswerCache() {
/* Implementation provided by caching aspect. */
}
@CacheEvict(value = "score", allEntries = true)
@Scheduled(initialDelay = 1000 * 200, fixedRate = 1000 * 60 * 15)
private void clearLearningProgressCache() { }
private void clearLearningProgressCache() {
/* Implementation provided by caching aspect. */
}
}
/**
* Classes and interfaces related to caching
* Classes and interfaces related to caching.
*/
package de.thm.arsnova.cache;
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2018 The ARSnova Team and Contributors
* Copyright (C) 2012-2019 The ARSnova Team and Contributors
*
* ARSnova Backend is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -15,34 +15,37 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.thm.arsnova.event;
import de.thm.arsnova.model.Content;
import de.thm.arsnova.model.Room;
package de.thm.arsnova.config;
import java.util.Arrays;
import java.util.List;
import org.springframework.boot.autoconfigure.AutoConfigurationImportFilter;
import org.springframework.boot.autoconfigure.AutoConfigurationMetadata;
/**
* Fires whenever a set of contents are enabled, i.e., they become visible to students.
* An {@link AutoConfigurationImportFilter} that only selects AutoConfiguration
* classes needed for Spring Actuator.
*
* @author Daniel Gerhardt
*/
public class UnlockQuestionsEvent extends RoomEvent {
private static final long serialVersionUID = 1L;
private List<Content> contents;
public UnlockQuestionsEvent(Object source, Room room, List<Content> contents) {
super(source, room);
this.contents = contents;
}
public List<Content> getQuestions() {
return this.contents;
}
public class ActuatorAutoConfigurationFilter implements AutoConfigurationImportFilter {
private static final List<String> actuatorClassesPrefixes = Arrays.asList(new String[] {
"org.springframework.boot.actuate.autoconfigure.",
"org.springframework.boot.autoconfigure.web.servlet."});
@Override
public void accept(ArsnovaEventVisitor visitor) {
visitor.visit(this);
public boolean[] match(final String[] autoConfigurationClasses,
final AutoConfigurationMetadata autoConfigurationMetadata) {
final boolean[] results = new boolean[autoConfigurationClasses.length];
for (int i = 0; i < results.length; i++) {
results[i] = autoConfigurationClasses[i] != null && checkPrefix(autoConfigurationClasses[i]);
}
return results;
}
private boolean checkPrefix(final String className) {
return actuatorClassesPrefixes.stream().anyMatch(p -> className.startsWith(p));
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2018 The ARSnova Team and Contributors
* Copyright (C) 2012-2019 The ARSnova Team and Contributors
*
* ARSnova Backend is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -15,29 +15,26 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.thm.arsnova.config;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import de.thm.arsnova.connector.client.ConnectorClient;
import de.thm.arsnova.connector.client.ConnectorClientImpl;
import de.thm.arsnova.model.migration.FromV2Migrator;
import de.thm.arsnova.model.migration.ToV2Migrator;
import de.thm.arsnova.model.serialization.CouchDbDocumentModule;
import de.thm.arsnova.model.serialization.View;
import de.thm.arsnova.util.ImageUtils;
import de.thm.arsnova.web.CacheControlInterceptorHandler;
import de.thm.arsnova.web.CorsFilter;
import de.thm.arsnova.web.DeprecatedApiInterceptorHandler;
import de.thm.arsnova.web.PathApiVersionContentNegotiationStrategy;
import de.thm.arsnova.web.ResponseInterceptorHandler;
import de.thm.arsnova.websocket.ArsnovaSocketioServer;
import de.thm.arsnova.websocket.ArsnovaSocketioServerImpl;
import de.thm.arsnova.websocket.ArsnovaSocketioServerListener;
import io.micrometer.core.instrument.MeterRegistry;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.CharEncoding;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties;
import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType;
import org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter;
import org.springframework.boot.actuate.metrics.web.servlet.WebMvcTagsProvider;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
......@@ -68,70 +65,95 @@ import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import de.thm.arsnova.config.properties.FeatureProperties;
import de.thm.arsnova.config.properties.SecurityProperties;
import de.thm.arsnova.config.properties.SystemProperties;
import de.thm.arsnova.connector.client.ConnectorClient;
import de.thm.arsnova.connector.client.ConnectorClientImpl;
import de.thm.arsnova.model.migration.FromV2Migrator;
import de.thm.arsnova.model.migration.ToV2Migrator;
import de.thm.arsnova.model.serialization.CouchDbDocumentModule;
import de.thm.arsnova.model.serialization.View;
import de.thm.arsnova.util.ImageUtils;
import de.thm.arsnova.web.CacheControlInterceptorHandler;
import de.thm.arsnova.web.CorsFilter;
import de.thm.arsnova.web.DeprecatedApiInterceptorHandler;
import de.thm.arsnova.web.PathBasedContentNegotiationStrategy;
import de.thm.arsnova.web.ResponseInterceptorHandler;
import de.thm.arsnova.websocket.ArsnovaSocketioServer;
import de.thm.arsnova.websocket.ArsnovaSocketioServerImpl;
/**
* Loads property file and configures non-security related beans and components.
*
* <p>
* expose-proxy for AspectJ is needed to access the proxy object via AopContext.currentProxy() in CouchDBDao. It might
* have a negative impact on performance but is needed for caching until a better solution is implemented (e.g. use of
* AspectJ's weaving).
* </p>
*/
@ComponentScan({
"de.thm.arsnova.cache",
"de.thm.arsnova.controller",
"de.thm.arsnova.event",
"de.thm.arsnova.management",
"de.thm.arsnova.security",
"de.thm.arsnova.service",
"de.thm.arsnova.web"})
"de.thm.arsnova.web",
"de.thm.arsnova.websocket.handler"})
@Configuration
@EnableAsync
@EnableAsync(mode = AdviceMode.ASPECTJ)
@EnableAutoConfiguration
@EnableCaching(mode = AdviceMode.ASPECTJ)
@EnableScheduling
@EnableSpringConfigured
@EnableWebMvc
@PropertySource(
value = {"classpath:arsnova.properties.example", "file:/etc/arsnova/arsnova.properties"},
value = {
"classpath:config/defaults.yml",
"classpath:config/actuator.yml",
"file:${arsnova.config-dir:.}/application.yml",
"file:${arsnova.config-dir:.}/secrets.yml",
"file:${arsnova.config-dir:.}/ui.yml"},
ignoreResourceNotFound = true,
encoding = "UTF-8"
encoding = CharEncoding.UTF_8,
factory = YamlPropertySourceFactory.class
)
@EnableConfigurationProperties({
FeatureProperties.class,
SystemProperties.class})
public class AppConfig implements WebMvcConfigurer {
public static final String API_V2_MEDIA_TYPE_VALUE = "application/vnd.de.thm.arsnova.v2+json";
public static final String API_V3_MEDIA_TYPE_VALUE = "application/vnd.de.thm.arsnova.v3+json";
public static final MediaType API_V2_MEDIA_TYPE = MediaType.valueOf(API_V2_MEDIA_TYPE_VALUE);
public static final MediaType API_V3_MEDIA_TYPE = MediaType.valueOf(API_V3_MEDIA_TYPE_VALUE);
public static final MediaType ACTUATOR_MEDIA_TYPE = MediaType.valueOf(ActuatorMediaType.V2_JSON);
@Autowired
private Environment env;
@Value(value = "${connector.enable}") private boolean connectorEnable;
@Value(value = "${connector.uri}") private String connectorUri;
@Value(value = "${connector.username}") private String connectorUsername;
@Value(value = "${connector.password}") private String connectorPassword;
@Autowired
private SystemProperties systemProperties;
@Value(value = "${socketio.bind-address}") private String socketAddress;
@Value(value = "${socketio.port}") private int socketPort;
@Value(value = "${socketio.ssl.jks-file:}") private String socketKeystore;
@Value(value = "${socketio.ssl.jks-password:}") private String socketKeystorePassword;
@Value(value = "${security.cors.origins:}") private String[] corsOrigins;
@Value(value = "${mail.host}") private String mailHost;
@Value(value = "${api.indent-response-body:false}") private boolean apiIndent;
@Autowired
private SecurityProperties securityProperties;
@Autowired
private WebEndpointProperties webEndpointProperties;
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
public void configureMessageConverters(final List<HttpMessageConverter<?>> converters) {
converters.add(defaultJsonMessageConverter());
converters.add(apiV2JsonMessageConverter());
converters.add(managementJsonMessageConverter());
converters.add(stringMessageConverter());
//converters.add(new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()));
}
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
PathApiVersionContentNegotiationStrategy strategy =
new PathApiVersionContentNegotiationStrategy(API_V3_MEDIA_TYPE);
public void configureContentNegotiation(final ContentNegotiationConfigurer configurer) {
final PathBasedContentNegotiationStrategy strategy =
new PathBasedContentNegotiationStrategy(API_V3_MEDIA_TYPE, webEndpointProperties.getBasePath());
configurer.mediaType("json", MediaType.APPLICATION_JSON_UTF8);
configurer.mediaType("xml", MediaType.APPLICATION_XML);
configurer.favorParameter(false);
......@@ -146,22 +168,31 @@ public class AppConfig implements WebMvcConfigurer {
}
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
public void configureViewResolvers(final ViewResolverRegistry registry) {
registry.viewResolver(new InternalResourceViewResolver());
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
public void addInterceptors(final InterceptorRegistry registry) {
registry.addInterceptor(cacheControlInterceptorHandler());
registry.addInterceptor(deprecatedApiInterceptorHandler());
registry.addInterceptor(responseInterceptorHandler());
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger.json").addResourceLocations("classpath:/");
}
/* Provides a Spring Framework (non-Boot) compatible Filter. */
@Bean
public WebMvcMetricsFilter webMvcMetricsFilterOverride(
final MeterRegistry registry, final WebMvcTagsProvider tagsProvider) {
final MetricsProperties.Web.Server serverProperties = new MetricsProperties.Web.Server();
return new WebMvcMetricsFilter(registry, tagsProvider,
serverProperties.getRequestsMetricName(), serverProperties.isAutoTimeRequests());
}
@Bean
public CacheControlInterceptorHandler cacheControlInterceptorHandler() {
return new CacheControlInterceptorHandler();
......@@ -179,11 +210,12 @@ public class AppConfig implements WebMvcConfigurer {
@Bean
public StringHttpMessageConverter stringMessageConverter() {
StringHttpMessageConverter messageConverter = new StringHttpMessageConverter();
messageConverter.setDefaultCharset(Charset.forName("UTF-8"));
final StringHttpMessageConverter messageConverter = new StringHttpMessageConverter();
messageConverter.setDefaultCharset(StandardCharsets.UTF_8);
messageConverter.setWriteAcceptCharset(false);
List<MediaType> mediaTypes = new ArrayList<>();
final List<MediaType> mediaTypes = new ArrayList<>();
mediaTypes.add(MediaType.TEXT_PLAIN);
mediaTypes.add(MediaType.APPLICATION_XML);
messageConverter.setSupportedMediaTypes(mediaTypes);
return messageConverter;
......@@ -191,16 +223,16 @@ public class AppConfig implements WebMvcConfigurer {
@Bean
public MappingJackson2HttpMessageConverter defaultJsonMessageConverter() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
final Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder
.serializationInclusion(JsonInclude.Include.NON_EMPTY)
.defaultViewInclusion(false)
.indentOutput(apiIndent)
.indentOutput(systemProperties.getApi().isIndentResponseBody())
.simpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
ObjectMapper mapper = builder.build();
final ObjectMapper mapper = builder.build();
mapper.setConfig(mapper.getSerializationConfig().withView(View.Public.class));
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(mapper);
List<MediaType> mediaTypes = new ArrayList<>();
final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(mapper);
final List<MediaType> mediaTypes = new ArrayList<>();
mediaTypes.add(API_V3_MEDIA_TYPE);
mediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
converter.setSupportedMediaTypes(mediaTypes);
......@@ -210,18 +242,18 @@ public class AppConfig implements WebMvcConfigurer {
@Bean
public MappingJackson2HttpMessageConverter apiV2JsonMessageConverter() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
final Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder
.serializationInclusion(JsonInclude.Include.NON_NULL)
.defaultViewInclusion(false)
.indentOutput(apiIndent)
.indentOutput(systemProperties.getApi().isIndentResponseBody())
.featuresToEnable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.featuresToEnable(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS)
.modules(new CouchDbDocumentModule());
ObjectMapper mapper = builder.build();
final ObjectMapper mapper = builder.build();
mapper.setConfig(mapper.getSerializationConfig().withView(View.Public.class));
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(mapper);
List<MediaType> mediaTypes = new ArrayList<>();
final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(mapper);
final List<MediaType> mediaTypes = new ArrayList<>();
mediaTypes.add(API_V2_MEDIA_TYPE);
mediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
converter.setSupportedMediaTypes(mediaTypes);
......@@ -229,6 +261,22 @@ public class AppConfig implements WebMvcConfigurer {
return converter;
}
@Bean
public MappingJackson2HttpMessageConverter managementJsonMessageConverter() {
final Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder
.indentOutput(systemProperties.getApi().isIndentResponseBody())
.simpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
final ObjectMapper mapper = builder.build();
final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(mapper);
final List<MediaType> mediaTypes = new ArrayList<>();
mediaTypes.add(ACTUATOR_MEDIA_TYPE);
mediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
converter.setSupportedMediaTypes(mediaTypes);
return converter;
}
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
final PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
......@@ -239,7 +287,7 @@ public class AppConfig implements WebMvcConfigurer {
@Bean
public PropertiesFactoryBean versionInfoProperties() {
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
final PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("version.properties"));
return propertiesFactoryBean;
......@@ -247,19 +295,19 @@ public class AppConfig implements WebMvcConfigurer {
@Bean
public CorsFilter corsFilter() {
return new CorsFilter(Arrays.asList(corsOrigins));
return new CorsFilter(securityProperties.getCorsOrigins());
}
@Bean(name = "connectorClient")
public ConnectorClient connectorClient() {
if (!connectorEnable) {
if (!systemProperties.getLmsConnector().isEnabled()) {
return null;
}
final ConnectorClientImpl connectorClient = new ConnectorClientImpl();
connectorClient.setServiceLocation(connectorUri);
connectorClient.setUsername(connectorUsername);
connectorClient.setPassword(connectorPassword);
connectorClient.setServiceLocation(systemProperties.getLmsConnector().getHostUrl());
connectorClient.setUsername(systemProperties.getLmsConnector().getUsername());
connectorClient.setPassword(systemProperties.getLmsConnector().getPassword());
return connectorClient;
}
......@@ -267,17 +315,10 @@ public class AppConfig implements WebMvcConfigurer {
@Bean(name = "socketServer", initMethod = "startServer", destroyMethod = "stopServer")
public ArsnovaSocketioServer socketServer() {
final ArsnovaSocketioServerImpl socketioServer = new ArsnovaSocketioServerImpl();
socketioServer.setHostIp(socketAddress);
socketioServer.setPortNumber(socketPort);
socketioServer.setUseSSL(!socketKeystore.isEmpty());
socketioServer.setKeystore(socketKeystore);
socketioServer.setStorepass(socketKeystorePassword);
return socketioServer;
}
socketioServer.setHostIp(systemProperties.getSocketio().getBindAddress());
socketioServer.setPortNumber(systemProperties.getSocketio().getPort());
@Bean
public ArsnovaSocketioServerListener arsnovaSocketListener() {
return new ArsnovaSocketioServerListener();
return socketioServer;
}
@Bean
......@@ -288,7 +329,7 @@ public class AppConfig implements WebMvcConfigurer {
@Bean
public JavaMailSenderImpl mailSender() {
final JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
mailSender.setHost(mailHost);
mailSender.setHost(systemProperties.getMail().getHost());
return mailSender;
}
......
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2019 The ARSnova Team and Contributors
*
* ARSnova Backend is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ARSnova Backend is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.thm.arsnova.config;
import javax.servlet.Filter;
import javax.servlet.ServletRegistration;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import javax.servlet.Filter;
import javax.servlet.ServletRegistration;
public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] {
AppConfig.class,
PersistenceConfig.class,
SecurityConfig.class
SecurityConfig.class,
WebSocketConfig.class,
};
}
......@@ -31,12 +49,14 @@ public class AppInitializer extends AbstractAnnotationConfigDispatcherServletIni
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter("UTF-8");
DelegatingFilterProxy corsFilter = new DelegatingFilterProxy("corsFilter");
DelegatingFilterProxy maintenanceModeFilter = new DelegatingFilterProxy("maintenanceModeFilter");
DelegatingFilterProxy v2ContentTypeOverrideFilter = new DelegatingFilterProxy("v2ContentTypeOverrideFilter");
final CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter("UTF-8");
final DelegatingFilterProxy webMvcMetricsFilter = new DelegatingFilterProxy("webMvcMetricsFilterOverride");
final DelegatingFilterProxy corsFilter = new DelegatingFilterProxy("corsFilter");
final DelegatingFilterProxy maintenanceModeFilter = new DelegatingFilterProxy("maintenanceModeFilter");
final DelegatingFilterProxy v2ContentTypeOverrideFilter = new DelegatingFilterProxy("v2ContentTypeOverrideFilter");
return new Filter[] {
webMvcMetricsFilter,
characterEncodingFilter,
corsFilter,
maintenanceModeFilter,
......
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2019 The ARSnova Team and Contributors
*
* ARSnova Backend is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ARSnova Backend is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.thm.arsnova.config;
import org.ektorp.impl.StdCouchDbInstance;
import org.ektorp.spring.HttpClientFactoryBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;
import de.thm.arsnova.config.properties.CouchDbProperties;
import de.thm.arsnova.model.serialization.CouchDbObjectMapperFactory;
import de.thm.arsnova.persistence.AnswerRepository;
import de.thm.arsnova.persistence.CommentRepository;
import de.thm.arsnova.persistence.ContentGroupRepository;
import de.thm.arsnova.persistence.ContentRepository;
import de.thm.arsnova.persistence.LogEntryRepository;
import de.thm.arsnova.persistence.MotdRepository;
......@@ -12,6 +42,7 @@ import de.thm.arsnova.persistence.StatisticsRepository;
import de.thm.arsnova.persistence.UserRepository;
import de.thm.arsnova.persistence.couchdb.CouchDbAnswerRepository;
import de.thm.arsnova.persistence.couchdb.CouchDbCommentRepository;
import de.thm.arsnova.persistence.couchdb.CouchDbContentGroupRepository;
import de.thm.arsnova.persistence.couchdb.CouchDbContentRepository;
import de.thm.arsnova.persistence.couchdb.CouchDbLogEntryRepository;
import de.thm.arsnova.persistence.couchdb.CouchDbMotdRepository;
......@@ -20,42 +51,34 @@ import de.thm.arsnova.persistence.couchdb.CouchDbSessionStatisticsRepository;
import de.thm.arsnova.persistence.couchdb.CouchDbStatisticsRepository;
import de.thm.arsnova.persistence.couchdb.CouchDbUserRepository;
import de.thm.arsnova.persistence.couchdb.support.MangoCouchDbConnector;
import org.ektorp.impl.StdCouchDbInstance;
import org.ektorp.spring.HttpClientFactoryBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;
@ComponentScan({
"de.thm.arsnova.persistence.couchdb"
})
@Configuration
@EnableConfigurationProperties(CouchDbProperties.class)
@Profile("!test")
public class PersistenceConfig {
private static final int MIGRATION_SOCKET_TIMEOUT = 30000;
@Value("${couchdb.name}") private String couchDbName;
@Value("${couchdb.host}") private String couchDbHost;
@Value("${couchdb.port}") private int couchDbPort;
@Value("${couchdb.username:}") private String couchDbUsername;
@Value("${couchdb.password:}") private String couchDbPassword;
@Value("${couchdb.migrate-from:}") private String couchDbMigrateFrom;
private CouchDbProperties properties;
public PersistenceConfig(final CouchDbProperties couchDbProperties) {
this.properties = couchDbProperties;
}
@Bean
@Primary
public MangoCouchDbConnector couchDbConnector() throws Exception {
return new MangoCouchDbConnector(couchDbName, couchDbInstance(), couchDbObjectMapperFactory());
return new MangoCouchDbConnector(properties.getDbName(), couchDbInstance(), couchDbObjectMapperFactory());
}
@Bean
@ConditionalOnProperty(
name = "migrate-from",
prefix = CouchDbProperties.PREFIX)
public MangoCouchDbConnector couchDbMigrationConnector() throws Exception {
if (couchDbMigrateFrom.isEmpty()) {
return null;
}
return new MangoCouchDbConnector(couchDbMigrateFrom, couchDbInstance(), couchDbObjectMapperFactory());
return new MangoCouchDbConnector(properties.getMigrateFrom(), couchDbInstance(), couchDbObjectMapperFactory());
}
@Bean
......@@ -64,6 +87,9 @@ public class PersistenceConfig {
}
@Bean
@ConditionalOnProperty(
name = "migrate-from",
prefix = CouchDbProperties.PREFIX)
public StdCouchDbInstance couchDbMigrationInstance() throws Exception {
return new StdCouchDbInstance(couchDbMigrationHttpClientFactory().getObject());
}
......@@ -71,17 +97,20 @@ public class PersistenceConfig {
@Bean
public HttpClientFactoryBean couchDbHttpClientFactory() throws Exception {
final HttpClientFactoryBean factory = new HttpClientFactoryBean();
factory.setHost(couchDbHost);
factory.setPort(couchDbPort);
if (!couchDbUsername.isEmpty()) {
factory.setUsername(couchDbUsername);
factory.setPassword(couchDbPassword);
factory.setHost(properties.getHost());
factory.setPort(properties.getPort());
if (!properties.getUsername().isEmpty()) {
factory.setUsername(properties.getUsername());
factory.setPassword(properties.getPassword());
}
return factory;
}
@Bean
@ConditionalOnProperty(
name = "migrate-from",
prefix = CouchDbProperties.PREFIX)
public HttpClientFactoryBean couchDbMigrationHttpClientFactory() throws Exception {
final HttpClientFactoryBean factory = couchDbHttpClientFactory();
factory.setSocketTimeout(MIGRATION_SOCKET_TIMEOUT);
......@@ -119,6 +148,11 @@ public class PersistenceConfig {
return new CouchDbContentRepository(couchDbConnector(), false);
}
@Bean
public ContentGroupRepository contentGroupRepository() throws Exception {
return new CouchDbContentGroupRepository(couchDbConnector(), false);
}
@Bean
public AnswerRepository answerRepository() throws Exception {
return new CouchDbAnswerRepository(couchDbConnector(), false);
......
package de.thm.arsnova.config;
import java.util.Properties;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.CollectionFactory;
public class PrefixedYamlPropertiesFactoryBean extends YamlPropertiesFactoryBean {
private static final String PREFIX = "arsnova";
@Override
protected Properties createProperties() {
final Properties result = CollectionFactory.createStringAdaptingProperties();
process((properties, map) -> properties.forEach((k, v) -> {
if (k.toString().startsWith(PREFIX + ".")) {
result.put(k.toString().substring(PREFIX.length() + 1), v);
}
}));
return result;
}
}
/*
* This file is part of ARSnova Backend.
* Copyright (C) 2012-2019 The ARSnova Team and Contributors
*
* ARSnova Backend is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ARSnova Backend is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.thm.arsnova.config;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
......
package de.thm.arsnova.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
import de.thm.arsnova.config.properties.MessageBrokerProperties;
import de.thm.arsnova.config.properties.SecurityProperties;
import de.thm.arsnova.websocket.handler.AuthChannelInterceptorAdapter;
@Configuration
@EnableWebSocketMessageBroker
@EnableConfigurationProperties(MessageBrokerProperties.class)
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
private static final String MESSAGING_PREFIX = "/backend";
private static final String[] DESTINATION_PREFIX = {"/exchange", "/topic", "/queue"};
private static final String USER_REGISTRY_BROADCAST = "/topic/log-user-registry";
private static final String USER_DESTINATION_BROADCAST = "/queue/log-unresolved-user";
private final MessageBrokerProperties.Relay relayProperties;
private final AuthChannelInterceptorAdapter authChannelInterceptorAdapter;
private String[] corsOrigins;
@Autowired
public WebSocketConfig(
final MessageBrokerProperties messageBrokerProperties,
final SecurityProperties securityProperties,
final AuthChannelInterceptorAdapter authChannelInterceptorAdapter) {
this.relayProperties = messageBrokerProperties.getRelay();
this.corsOrigins = securityProperties.getCorsOrigins().stream().toArray(String[]::new);
this.authChannelInterceptorAdapter = authChannelInterceptorAdapter;
}
@Override
public void configureMessageBroker(final MessageBrokerRegistry config) {
config.setApplicationDestinationPrefixes(MESSAGING_PREFIX);
if (relayProperties.isEnabled()) {
config
.enableStompBrokerRelay(DESTINATION_PREFIX)
.setUserRegistryBroadcast(USER_REGISTRY_BROADCAST)
.setUserDestinationBroadcast(USER_DESTINATION_BROADCAST)
.setRelayHost(relayProperties.getHost())
.setRelayPort(relayProperties.getPort())
.setClientLogin(relayProperties.getUsername())
.setClientPasscode(relayProperties.getPassword());
} else {
config.enableSimpleBroker(DESTINATION_PREFIX);
}
}
@Override
public void registerStompEndpoints(final StompEndpointRegistry registry) {
registry.addEndpoint("/ws").setAllowedOrigins(corsOrigins).withSockJS();
}
@Override
public void configureClientInboundChannel(final ChannelRegistration registration) {
registration.interceptors(authChannelInterceptorAdapter);
}
}
package de.thm.arsnova.config;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.DefaultPropertySourceFactory;
import org.springframework.core.io.support.EncodedResource;
public class YamlPropertySourceFactory extends DefaultPropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(final String name, final EncodedResource resource)
throws IOException {
try {
final YamlPropertiesFactoryBean yamlPropertiesFactoryBean = new PrefixedYamlPropertiesFactoryBean();
yamlPropertiesFactoryBean.setResources(resource.getResource());
yamlPropertiesFactoryBean.afterPropertiesSet();
final Properties properties = yamlPropertiesFactoryBean.getObject();
return new PropertiesPropertySource(name != null ? name : resource.getResource().getFilename(), properties);
} catch (final IllegalStateException e) {
if (e.getCause() instanceof FileNotFoundException) {
throw (FileNotFoundException) e.getCause();
}
throw e;
}
}
}
/**
* Configuration of Spring's and ARSnova's components
* Configuration of Spring's and ARSnova's components.
*/
package de.thm.arsnova.config;