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 (1694)
Showing
with 1920 additions and 874 deletions
# editorconfig.org
# end_of_line: handled by Git
# indent_size: let the developer decide as long as tabs are used
root = true
[*]
charset = utf-8
indent_style = tab
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.yml]
indent_size = 2
indent_style = space
.project
.classpath
.settings/*
target/*
chromedriver.log
*.class
.checkstyle
/target
/target/
# Environment specific files
*~
*.bak
*.iml
*.log
*.orig
.*.sw?
.classpath
.directory
.DS_Store
.idea/
.project
.settings/
desktop.ini
nbproject/
/.metadata/
variables:
OUTPUT_DIR: target
WAR_FILE: $OUTPUT_DIR/arsnova-backend-*.war
stages:
- build
- post-build
- deploy
.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
allow_failure: true
script:
- mvn $MAVEN_CLI_OPTS checkstyle:check -Dcheckstyle.missing-javadoc.severity=warning
compile:
<<: *maven
stage: build
artifacts:
paths:
- $OUTPUT_DIR
script:
- mvn $MAVEN_CLI_OPTS test-compile
unit_test:
<<: *maven
stage: post-build
dependencies:
- compile
artifacts:
paths:
- $OUTPUT_DIR
coverage: '/Code coverage: \d+\.\d+/'
script:
- 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
dependencies:
- compile
artifacts:
name: package
paths:
- $WAR_FILE
script:
- mvn $MAVEN_CLI_OPTS war:war
.deploy: &deploy
stage: deploy
image: python:3
when: manual
variables:
DEPLOY_CONTEXT: api
GIT_STRATEGY: none
dependencies:
- package
script:
# Do some variable magic to access host-specific variables
- PREFIX=$(echo $CI_ENVIRONMENT_NAME | tr '.:/-' '_')
- HOST_VAR=${PREFIX}__HOST TOMCAT_PASSWORD_VAR=${PREFIX}__TOMCAT_PASSWORD TOMCAT_USER_VAR=${PREFIX}__TOMCAT_USER
- "[ -z \"${!HOST_VAR}\" ] && echo \"No configuration for $DEPLOY_HOST found.\" && exit 1"
# Abort if there are too many users online
- USER_COUNT=$(curl -fsSL ${CI_ENVIRONMENT_URL}statistics | python -c "import sys, json; data=json.loads(sys.stdin.read()); print(data['activeUsers']);")
- "[ \"$USER_COUNT\" -ge 10 ] && [ -z \"$FORCE\" ] && echo \"Too many users ($USER_COUNT) online.\" && exit 1"
# Deploy .war file to Tomcat
- curl -fsS --upload-file $WAR_FILE "https://${!TOMCAT_USER_VAR}:${!TOMCAT_PASSWORD_VAR}@${!HOST_VAR}/manager/text/deploy?path=%2F${DEPLOY_CONTEXT}&update=true"
tomcat_production:
<<: *deploy
environment:
name: production/$PROD_DEPLOY_HOST
url: https://$PROD_DEPLOY_HOST/$DEPLOY_CONTEXT/
only:
variables:
- $PROD_DEPLOY_HOST
# GitLab 11.0+
#- $PROD_DEPLOY_HOST =~ /^([a-z0-9-]+\.)*[a-z0-9-]+(:[0-9]+)?$/
refs:
- /^v[0-9]+/
- /^[0-9]+\.[0-9]+$/
before_script:
- DEPLOY_HOST=$PROD_DEPLOY_HOST
tomcat_development:
<<: *deploy
environment:
name: development/$DEV_DEPLOY_HOST
url: https://$DEV_DEPLOY_HOST/api/
only:
variables:
- $DEV_DEPLOY_HOST
# GitLab 11.0+
#- $DEV_DEPLOY_HOST =~ /^([a-z0-9-]+\.)*[a-z0-9-]+(:[0-9]+)?$/
before_script:
- DEPLOY_HOST=$DEV_DEPLOY_HOST
sonarqube:
<<: *maven
stage: deploy
only:
- master
dependencies:
- compile
- unit_test
allow_failure: true
script:
- mvn $MAVEN_CLI_OPTS sonar:sonar
dist: xenial
language: java
notifications:
slack: f112a:GOZb6ewuAf2AVxduDXzdiCTG
email: admin@ecollab.eu
jdk:
- openjdk8
- 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.
## 2.5.8
This is a maintenance release which only brings libraries up to date to fix
potential bugs.
## 2.6.1
Bug fixes:
* Fixed exception at startup caused by missing migration document.
* Fixed session export to correctly include all answers.
Additional changes:
* Libraries have been upgraded to fix potential bugs.
## 2.6
Features:
* Experimental support for CouchDB 2 has been added. Note: The data migration
script is not compatible with CouchDB 2 and has to be run before an upgrade.
Improvements:
* Error handling and logging has been improved. It should now be easier to find
the cause of problems. API error responses now contain the name of the
`Exception` which caused the error. Further details for debugging purposes can
be enabled with the new `api.expose-exception-messages` setting (Do NOT
enable in production environments!).
* Updated OAuth handling to restore compatibility with 3rd-party login services.
Bug fixes:
* Fixed multiple bugs caused by incorrect type handling in the database layer.
* Fixed XFO header check behind reverse proxy (used by clients when embedding
external websites).
* Fixed rounding error in learning progress calculation.
* Fixed `security.cors.origins` setting.
* Fixed import of data from older versions.
Security:
* Fixed DoS vulnerability in authentication handling behind reverse proxy.
Configuration changes:
Minor changes to the web server and Tomcat proxy configuration are required
(see [installation guide](src/site/markdown/installation.md)).
**This version is brought to you by:**
Project management: Klaus Quibeldey-Cirkel
Lead programming: Daniel Gerhardt, Tom "tekay" Käsler
Contributions: Marius Renner, Paul-Christian Volkmer
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.5.7
This is a maintenance release which only brings libraries up to date to fix
potential bugs.
## 2.5.6
This is a maintenance release which only brings libraries up to date to fix
potential bugs.
## 2.5.5
This is a maintenance release which only brings libraries up to date to fix
potential bugs.
## 2.5.4
This is a maintenance release which only brings libraries up to date to fix
potential bugs.
## 2.5.3
This is a maintenance release which only brings libraries up to date to fix
potential bugs.
## 2.5.2
This is a maintenance release which only brings libraries up to date to fix
potential bugs.
## 2.5.1
This release fixes a performance issue on session creation affecting large
installations.
Bug fixes:
* Session import works again.
Additional changes:
* Libraries have been upgraded to fix potential bugs
## 2.4.3
This release fixes a performance issue on session creation affecting large
installations.
Bug fixes:
* WebSocket communication now works correctly for course sessions.
(only affects installations using the LMS connector)
* The configuration parameter `security.facebook.allowed-roles` is now
respected.
Additional changes:
* Libraries have been upgraded to fix potential bugs
## 2.5
Major features:
* Administration API: New endpoints have been added which are accessible by
users defined by `security.admin-accounts`.
* Evaluation of free text answers
* Proxy support for WebSocket connections: It is now possible to use the same
port for standard HTTP requests and WebSocket connections. Additionally, it is
no longer necessary to setup a Java key store for TLS if a proxy is used.
* Auto-deletion of inactive (not activated) users and guest sessions
Minor features and changes:
* Caching improvements
* New use case including only comments
* Export of questions to arsnova.click format
* Export/import of flashcards to/from arsnova.cards format
* Flashcards are now handled separately from questions
Configuration changes:
* `socketio.ip` has been replaced by `socketio.bind-address`
* `security.ssl` has been removed. `security.keystore` and `security.storepass`
have been replaced by `socketio.ssl.jks-file` and `socketio.ssl.jks-password`.
* New setting: `socketio.proxy-path`
* The default port for WebSocket connections has been changed to `8090`
With this release we have completely overhauled our [documentation](README.md).
Additionally, we now provide
[Docker images](https://github.com/thm-projects/arsnova-docker/).
**This version is brought to you by:**
Project management: Klaus Quibeldey-Cirkel
Lead programming: Andreas Gärtner, Daniel Gerhardt, Tom "tekay" Käsler
Contributions: Robin Drangmeister, Dennis Schönhof
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.4.2
This release fixes a minor security vulnerability which allowed an attacker to
remove a MotD from a session without being the creator.
Additional changes:
* Libraries have been upgraded to fix potential bugs
## 2.3.4
This release fixes a minor security vulnerability which allowed an attacker to
remove a MotD from a session without being the creator.
Additional changes:
* Libraries have been upgraded to fix potential bugs
## 2.4.1
This release fixes a security vulnerability caused by the CORS implementation.
Origins allowed for CORS can now be set in the configuration via
`security.cors.origins`. (Reported by Rainer Rillke at Wikimedia)
Additionally, authentication via disabled services is now entirely blocked to
fix a security vulnerability allowing guest access despite the setting
`security.guest.enabled=false`. (Reported by Rainer Rillke at Wikimedia)
Additional changes:
* Libraries have been upgraded to fix potential bugs
## 2.3.3
This release fixes a security vulnerability caused by the CORS implementation.
Origins allowed for CORS can now be set in the configuration via
`security.cors.origins`. (Reported by Rainer Rillke at Wikimedia)
Additional changes:
* Libraries have been upgraded to fix potential bugs
## 2.2.2
This release fixes a security vulnerability caused by the CORS implementation.
Origins allowed for CORS can now be set in the configuration via
`security.cors.origins`. (Reported by Rainer Rillke at Wikimedia)
Additional changes:
* Libraries have been upgraded to fix potential bugs
## 2.1.2
This release fixes a security vulnerability caused by the CORS implementation.
Support for cross-origin requests has been removed. Use ARSnova version 2.2 or
newer for proper CORS. (Reported by Rainer Rillke at Wikimedia)
Additional changes:
* Libraries have been upgraded to fix potential bugs
## 2.0.4
This release fixes a security vulnerability caused by the CORS implementation.
Support for cross-origin requests has been removed. Use ARSnova version 2.2 or
newer for proper CORS. (Reported by Rainer Rillke at Wikimedia)
Additional changes:
* Libraries have been upgraded to fix potential bugs
## 2.4
Major features:
* Support for new use case and feature settings has been added.
Minor features and changes:
* User content is assigned to a single account regardless of case used at
login/registration for database authentication. For LDAP authentication the
UID attribute is requested from the server instead of relying on the user's
input to ensure correct assignment.
* New API endpoints have been added to reduce requests on session imports.
* Session use case and feature settings are now included in exports and imports.
* Authentication providers can now be enabled separately for students and
lecturers.
* A new suspended votes offset setting has been added.
* JSON export and import now include session info and feature settings.
Bug fixes:
* Deleted sessions are now correctly evicted from cache.
* Answer count calculation for free text questions has been fixed.
**This version is brought to you by:**
Project management: Klaus Quibeldey-Cirkel
Lead programming: Andreas Gärtner, Daniel Gerhardt, Tom "tekay" Käsler
Contributions: Paul-Christian Volkmer
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.3.2
This release fixes a security vulnerability in the account management API. It is
highly recommended to upgrade if you are using database authentication.
Additional changes:
* Libraries have been upgraded to fix potential bugs
## 2.2.1
This release fixes a security vulnerability in the account management API. It is
highly recommended to upgrade if you are using database authentication.
Additional bug fixes:
* The `security.authentication.login-try-limit` setting now works as intended.
## 2.1.1
This release fixes a security vulnerability in the account management API. It is
highly recommended to upgrade if you are using database authentication.
Additional changes:
* Libraries have been upgraded to fix potential bugs
## 2.0.3
This release fixes a security vulnerability in the account management API. It is
highly recommended to upgrade if you are using database authentication.
Additional changes:
* Libraries have been upgraded to fix potential bugs
* Some unnecessary log warnings for Websocket communication are filtered
## 2.3.1
Bug fixes:
* Case-insensitive user IDs are now correctly handled for LDAP authentication.
* LDAP authentication does no longer request unnecessary user attributes.
## 2.3
Major features:
* Improved LDAP authentication support: Additional settings for LDAP search and
a privileged LDAP user have been added.
* Usernames for admin accounts can now be set up in the configuration file.
These accounts are privileged to create global "Messages of the Day".
Additional privileges might be added for them in future releases.
* Splash screen settings have been added to override the frontend theme's
defaults.
* The API has been extended to support features introduced with ARSnova Mobile
2.3.
Minor features and changes:
* Markdown formatting, learning progress, student's own questions and the
question format flashcard are now active by default and can no longer be
disabled for the whole ARSnova installation.
Bug fixes:
* The `security.authentication.login-try-limit` setting now works as intended.
Changes for developers:
* API documentation is now exposed in Swagger format.
* Startup time of Jetty has been significantly reduced.
* Version information is now saved with builds and exposed by the API.
**This version is brought to you by:**
Project management: Klaus Quibeldey-Cirkel
Lead programming: Andreas Gärtner, Daniel Gerhardt, Tom "tekay" Käsler,
Christoph Thelen
Contributions: Eduard Ellert, Tjark Wilhelm Hoeck, Mohamed Sami Jarmoud, Stefan
Schmeißer, Paul-Christian Volkmer
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.2
This release massively improves performance of ARSnova and contains a critical
bugfix so it is highly recommended to upgrade. Because of the newly introduced
caching method, it might be necessary to increase the Java memory limit for
servlet containers.
Major features:
* Performance improvements: Database queries are now cached by the backend.
Answers are written to the database in batches.
* Pagination support: The range of results can now be limited.
* The API has been extended to support features introduced with ARSnova Mobile
2.2.
Bug fixes:
* User content consisting of JSON could not be loaded and rendered connected
data unloadable as well.
**This version is brought to you by:**
Project management: Klaus Quibeldey-Cirkel
Lead programming: Andreas Gärtner, Daniel Gerhardt, Christoph Thelen
Contributions: Dominik Hikade, Tom Käsler, Maximilian Klingelhöfer,
Michael Sann, Jan Sladek, Katharina Staden
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.1
Major features:
* Public Pool (experimental): It is now possible to share sessions with other
users in a pool of public sessions. Other users can create their own copies of
shared sessions. This feature can be enabled in the arsnova.properties
configuration.
Minor features and changes:
* Adjustments to correctly handle requests for imports from the frontend.
* Some communication between the frontend and backend has been optimized for
improved performance.
* Additional configuration parameters for tracking, session export and import, a
demo session and a blog URL have been introduced.
**This version is brought to you by:**
Project management: Klaus Quibeldey-Cirkel
Lead programming: Andreas Gärtner, Daniel Gerhardt, Christoph Thelen
Contributions: Felix Schmidt, Artjom Siebert, Daniel Vogel
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.0.2
This release updates dependencies. The updated library for Socket.IO support
fixes memory leaks and disables SSL 3.0 support (POODLE vulnerability).
## 2.0.1
This release introduces the following changes:
* Updates dependency for Socket.IO support to fix memory leaks
* Usernames for student's questions and free text answers are no longer exposed
by API responses
## 2.0.0
ARSnova 2.0 has been in development for more than two years. Further releases
can be expected much more frequently.
This is actually the first major release of ARSnova Backend. It is called 2.0 to
feature API compatibility with the simultaneously released ARSnova Mobile 2.0.
**This version is brought to you by:**
Project management: Klaus Quibeldey-Cirkel
Lead programming: Andreas Gärtner, Daniel Gerhardt, Christoph Thelen,
Paul-Christian Volkmer
Contributions: Sören Gutzeit, Julian Hochstetter, Jan Kammer, Daniel Knapp,
Felix Schmidt, Artjom Siebert, Daniel Vogel
Testing & Feedback: Kevin Atkins, Kathrin Jäger
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),
[@LLZ](http://llz.uni-halle.de/)
# Contributing
ARSnova needs you! If you are interested in helping, please review the guidelines found in our [mobile repository][mobile-repository].
[mobile-repository]: https://github.com/thm-projects/arsnova-mobile/blob/master/CONTRIBUTING.md
# ARSnova
ARSnova is a modern approach to Audience Response Systems (ARS). It is released under the GPLv3 license, and is offered as a Software as a Service free of charge. Head over to [arsnova.eu](https://arsnova.eu/) to see it in action.
---
The next major version of ARSnova Backend is being developed on the `master` branch which is not yet production ready.
If you are looking for the current stable code base, switch to branch `2.x`.
![ARSnova](src/site/resources/showcase.png)
ARSnova consists of two projects: the mobile client and the server. This repository contains the server code. You will find the client at thm-projects/arsnova-mobile. However, you do not need to download both repositories in order to get started.
[![Build Status](https://travis-ci.org/thm-projects/arsnova-war.svg?branch=master)](https://travis-ci.org/thm-projects/arsnova-war)
## Getting Started
The most convenient way to get started developing ARSnova is by using our [Vagrant](http://www.vagrantup.com/) environment, found at [thm-projects/arsnova-vagrant](https://github.com/thm-projects/arsnova-vagrant). Use your IDE on your host machine to make changes to ARSnova, while the build process is completely handled by the Vagrant box. You will not need to install any development tools.
[arsnova-vagrant](https://github.com/thm-projects/arsnova-vagrant) sets up a virtual machine for both development and production use. The basic usage is `vagrant up`, which will start the development environment. If you wish to start production as well, use `vagrant up production`.
Once any machine has been started, all required ARSnova repositories are automatically cloned from GitHub, so that you can start coding immediately.
To connect to your development machine, type `vagrant ssh`. After that, you can start ARSnova inside the machine by running `./start.sh`. You can then access ARSnova from your host machine by opening http://localhost:8080.
### QA Private Build
[arsnova-vagrant](https://github.com/thm-projects/arsnova-vagrant) also sets up the build environment we use internally at THM, which consists of [Jenkins](http://jenkins-ci.org/) and [SonarQube](http://www.sonarqube.org/). The former provides a QA pipeline that builds, tests, analyzes, and finally deploys ARSnova to the production environment. SonarQube is used for the analyzation phase and provides a drill-down into many quality aspects, including [technical debt](https://en.wikipedia.org/wiki/Technical_debt).
While the development environment is running, Jenkins and SonarQube are available at:
- http://localhost:9000 (SonarQube)
- http://localhost:9090 (Jenkins)
### QA Public Build
We also leverage the cloud provided by [Travis CI](https://travis-ci.org/) and [Sauce Labs](https://saucelabs.com/) to build and test ARSnova. Travis first builds and unit tests the software, then it instructs Sauce Labs to run smoke tests on different browsers and operating systems. This ensures that the basic features of ARSnova work across browsers and platforms. See [this example](https://saucelabs.com/tests/4beecf8c754f418da0b75259c039c077) to get an idea.
Our official build status provided by Travis CI:
- [![Build Status](https://travis-ci.org/thm-projects/arsnova-war.svg?branch=master)](https://travis-ci.org/thm-projects/arsnova-war) for ARSnova-war
- [![Build Status](https://travis-ci.org/thm-projects/arsnova-mobile.svg?branch=master)](https://travis-ci.org/thm-projects/arsnova-mobile) for ARSnova-mobile
## Development
This is ARSnova's main repository. Almost all dependencies (including the mobile client) are managed for you by Maven.
### Download
If you have no intention in contributing, you might want to consider downloading one of our pre-built WAR archives. You will find them in our [Maven repository](https://maven.mni.thm.de/content/repositories/snapshots/de/thm/arsnova/arsnova-war/2.0.0-SNAPSHOT/), but please do note that we are not officially offering these archives.
### Building
ARSnova consists of two main projects: arsnova-war (this repository) and arsnova-mobile. By building arsnova-war, you will automatically download the mobile client. If you do not plan to work on the client, you won't need to build it separately.
Because all dependencies are handled by Maven, a complete build is done with:
mvn install
*Note:* Java 1.7 JDK is required and must be installed prior to building ARSnova.
### Requirements
You need three things to get started developing ARSnova:
1. the configuration file,
2. a CouchDB database including several view documents,
3. and a development server.
We will cover all three in the following sections.
#### Configuration
You will need to do some configuration work upfront: add a new directory "arsnova" in `/etc`, and create a copy of [arsnova.properties.example](src/main/webapp/arsnova.properties.example) named `arsnova.properties` in this directory. Then change the settings to match your environment, e.g. you might want to change the URLs.
Also, don't forget to change all properties starting with `couchdb`, if you do not want to use our defaults. The properties are used in the next section.
---
*A note to Windows users*: our settings are based on Linux and Mac environments. We do not officially support Windows, so you have to do some extra steps. The property file's path is hard coded in [spring-main.xml](src/main/webapp/WEB-INF/spring/spring-main.xml) and in the "Setup Tool" (see next section). You want to change the paths to make them match your environment.
ARSnova is a modern approach to Audience Response Systems (ARS).
It is released under the GPLv3 license, and is offered as a Software as a Service free of charge.
Head over to [arsnova.eu](https://arsnova.eu/) to see it in action.
#### Database
We provide a Python script that will set up all database essentials. This "Setup Tool" is located at [thm-projects/setuptool](https://github.com/thm-projects/setuptool). Make sure you have configured your database credentials inside the ARSnova configuration file (see previous section): you will need to have the entries `couchdb.username` and `couchdb.password`.
To set up the database, run:
python tool.py
This will create the database along with all required view documents. Note that this script requires Python 2 and will not run with Python 3.
#### Developer Mode
The easiest way to deploy ARSnova is via Jetty:
mvn jetty:run -Dmobile.path=
This will work out of the box. ARSnova will be located at <http://localhost:8080/>.
If you're wondering what that `-Dmobile.path=` thing is doing, this is a special override property for Jetty. By default, this property points to a local version of ARSnova mobile located at `../arsnova-mobile` &mdash; relative to the location of this project. If you happen to have downloaded ARSnova mobile to this location, you may skip the override, and just use:
mvn jetty:run
## Production Use
If you intend to use ARSnova in productive environments, you will have to do some additional configuration work.
### Server
In order to build up a full featured server installation containing ARSnova and CouchDB you have to install at least the following services:
* Apache Tomcat 7.0.29 (or newer)
* Apache Webserver 2.2 or newer with builtin modules `mod_proxy`, `mod_proxy_ajp` and `mod_proxy_http`
* Apache CouchDB
Make sure all services are installed. Next step is to configure the Apache Webserver. Find the configuration file or create a new one for use with a virtual host. This depends on your needs. At least you should have a configuration containing these settings:
<Location />
ProxyPass ajp://127.0.0.1:8009/
ProxyPassReverse ajp://127.0.0.1:8009/
</Location>
All requests will be sent to your Apache Tomcat servlet container, using AJP running on port 8009.
To enable the required Apache Webserver modules simply type:
# a2enmod proxy
# a2enmod proxy_ajp
# a2enmod proxy_http
The configuration is ready for development usage. Finally, you should (re)start all services. ARSnova is now listening on HTTP port 80.
### Session Persistence
Look for your Tomcat configuration directory and change the file "context.xml" to match this example:
<Context>
<Manager pathname="/path/to/tomcat/sessions/arsnova.ser"/>
</Context>
This will enable session persistence across restarts as described [here](http://tomcat.apache.org/tomcat-7.0-doc/config/manager.html#Special_Features).
### HTTPS
To protect requests and responses you should use HTTPS and configure your Apache Webserver installation to redirect all traffic according to this
[example](http://wiki.apache.org/httpd/RedirectSSL).
Finally you should (re)start all services. ARSnova is now listening on HTTP port 80 and 443.
### Securing Your Web Socket Connection
To provide SSL websocket encryption, you have to provide the servers SSL key and certificate in a Java keystore. The following steps will guide you through this process.
![ARSnova](src/site/resources/showcase.png)
Use your webserver certificate, private key and certificate chain to create a PKCS12 keystore:
ARSnova consists of two projects: the mobile frontend and the backend.
This repository contains the backend code.
You will find the frontend at thm-projects/arsnova-mobile.
However, you do not need to download both repositories in order to get started.
openssl pkcs12 -export -in <servercert>.crt \
-inkey <serverkey>.key \
-out keystore.p12 -name 1 \
-certfile <your_cert_chain_file>
[![Build Status](https://travis-ci.org/thm-projects/arsnova-backend.svg?branch=master)](https://travis-ci.org/thm-projects/arsnova-backend)
You will be asked for a password for your PKCS12 keystore. This password must be used for importing this keystore into your java keystore. The import can be done using this command:
keytool -importkeystore \
-deststorepass <your_java_keystore_password> \
-destkeypass <your_java_keystore_password> \
-destkeystore arsnova.jks \
-srckeystore keystore.p12 \
-srcstoretype PKCS12 \
-srcstorepass <your_pkcs12_keystore_password> \
-alias 1
## Documentation
Be sure to provide the correct certificate and key file names and to use the correct passwords for your keystore.
We provide separate documentations for lectures and students, administrators and developers:
The last step is to find your ARSnova configuration file (see step "Configuration" above), setup the location of your Java keystore and its password.
* [For end-users](https://arsnova.thm.de/blog/en/arsnova-manual/)
* For admins
* [Installation](src/site/markdown/installation.md)
* [Upgrading](src/site/markdown/upgrade.md)
* [For developers](src/site/markdown/development.md)
security.ssl=true
security.keystore=<your keystore location>
security.storepass=<your keystore password>
## Credits
......
<?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>
This diff is collapsed.
package de.thm.arsnova;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import de.thm.arsnova.dao.IDatabaseDao;
import de.thm.arsnova.entities.Feedback;
import de.thm.arsnova.entities.User;
import de.thm.arsnova.exceptions.NotFoundException;
public class FeedbackStorage {
private static class FeedbackStorageObject {
private final int value;
private final Date timestamp;
private final User user;
public FeedbackStorageObject(final int initValue, final User u) {
value = initValue;
timestamp = new Date();
user = u;
}
public int getValue() {
return value;
}
public Date getTimestamp() {
return timestamp;
}
public boolean fromUser(final User u) {
return u.getUsername().equals(user.getUsername());
}
}
private final IDatabaseDao dao;
private final Map<String, Map<String, FeedbackStorageObject>> data;
public FeedbackStorage(final IDatabaseDao newDao) {
data = new ConcurrentHashMap<String, Map<String, FeedbackStorageObject>>();
dao = newDao;
}
public Feedback getFeedback(final String keyword) {
int a = 0;
int b = 0;
int c = 0;
int d = 0;
if (dao.getSession(keyword) == null) {
throw new NotFoundException();
}
if (data.get(keyword) == null) {
return new Feedback(0, 0, 0, 0);
}
for (final FeedbackStorageObject fso : data.get(keyword).values()) {
switch (fso.getValue()) {
case Feedback.FEEDBACK_FASTER:
a++;
break;
case Feedback.FEEDBACK_OK:
b++;
break;
case Feedback.FEEDBACK_SLOWER:
c++;
break;
case Feedback.FEEDBACK_AWAY:
d++;
break;
default:
break;
}
}
return new Feedback(a, b, c, d);
}
public Integer getMyFeedback(final String keyword, final User u) {
if (data.get(keyword) == null) {
return null;
}
for (final FeedbackStorageObject fso : data.get(keyword).values()) {
if (fso.fromUser(u)) {
return fso.getValue();
}
}
return null;
}
@Transactional(isolation = Isolation.READ_COMMITTED)
public boolean saveFeedback(final String keyword, final int value, final User user) {
if (dao.getSession(keyword) == null) {
throw new NotFoundException();
}
if (data.get(keyword) == null) {
data.put(keyword, new ConcurrentHashMap<String, FeedbackStorageObject>());
}
data.get(keyword).put(user.getUsername(), new FeedbackStorageObject(value, user));
return true;
}
@Transactional(isolation = Isolation.READ_COMMITTED)
public void cleanFeedbackVotes(final int cleanupFeedbackDelay) {
for (final String keyword : data.keySet()) {
cleanSessionFeedbackVotes(keyword, cleanupFeedbackDelay);
}
}
private void cleanSessionFeedbackVotes(final String keyword, final int cleanupFeedbackDelay) {
final long timelimitInMillis = 60000 * (long) cleanupFeedbackDelay;
final long maxAllowedTimeInMillis = System.currentTimeMillis() - timelimitInMillis;
final Map<String, FeedbackStorageObject> sessionFeedbacks = data.get(keyword);
for (final Map.Entry<String, FeedbackStorageObject> entry : sessionFeedbacks.entrySet()) {
if (
entry.getValue().getTimestamp().getTime() < maxAllowedTimeInMillis
) {
sessionFeedbacks.remove(entry.getKey());
}
}
}
}
/*
* Copyright (C) 2014 THM webMedia
*
* This file is part of ARSnova.
*
* ARSnova 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 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;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Util class for image operations.
*
* @author Daniel Vogel (daniel.vogel@mni.thm.de)
*
*/
public final class ImageUtils {
// Or whatever size you want to read in at a time.
private final static int CHUNK_SIZE = 4096;
private ImageUtils() {
}
public static final Logger LOGGER = LoggerFactory.getLogger(ImageUtils.class);
/**
* Converts an image to an Base64 String.
*
* @param imageUrl The image url as a {@link String}
* @return The Base64 {@link String} of the image on success, otherwise <code>null</code>.
*/
public static String encodeImageToString(final String imageUrl) {
final String[] urlParts = imageUrl.split("\\.");
final StringBuilder result = new StringBuilder();
// get format
//
// The format is read dynamically. We have to take control
// in the frontend that no unsupported formats are transmitted!
if (urlParts.length > 0) {
final String extension = urlParts[urlParts.length - 1];
result.append("data:image/" + extension + ";base64,");
result.append(Base64.encodeBase64String(convertFileToByteArray(imageUrl)));
return result.toString();
}
return null;
}
/**
* Gets the bytestream of an image url.
* s
* @param imageUrl The image url as a {@link String}
* @return The <code>byte[]</code> of the image on success, otherwise <code>null</code>.
*/
public static byte[] convertImageToByteArray(final String imageUrl, final String extension) {
try {
final URL url = new URL(imageUrl);
final BufferedImage image = ImageIO.read(url);
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, extension, baos);
baos.flush();
baos.close();
return baos.toByteArray();
} catch (final MalformedURLException e) {
LOGGER.error(e.getLocalizedMessage());
} catch (final IOException e) {
LOGGER.error(e.getLocalizedMessage());
}
return null;
}
/**
* Gets the bytestream of an image url.
*
* @param imageUrl The image url as a {@link String}
* @return The <code>byte[]</code> of the image on success, otherwise <code>null</code>.
*/
public static byte[] convertFileToByteArray(final String imageUrl) {
try {
final URL url = new URL(imageUrl);
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final InputStream is = url.openStream();
final byte[] byteChunk = new byte[CHUNK_SIZE];
int n;
while ((n = is.read(byteChunk)) > 0 ) {
baos.write(byteChunk, 0, n);
}
baos.flush();
baos.close();
return baos.toByteArray();
} catch (final MalformedURLException e) {
LOGGER.error(e.getLocalizedMessage());
} catch (final IOException e) {
LOGGER.error(e.getLocalizedMessage());
}
return null;
}
}
package de.thm.arsnova.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import de.thm.arsnova.entities.Session;
import de.thm.arsnova.services.UserSessionService;
@Aspect
public class UserSessionAspect {
@Autowired
private UserSessionService userSessionService;
/** Sets current user and ARSnova session in session scoped UserSessionService
*
* @param jp
* @param keyword
* @param session
*/
@AfterReturning(
pointcut="execution(public * de.thm.arsnova.services.SessionService.joinSession(..)) && args(keyword)",
returning="session"
)
public final void joinSessionAdvice(final JoinPoint jp, final String keyword, final Session session) {
userSessionService.setSession(session);
}
}
package de.thm.arsnova.aop;
/*
* 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.cache;
/**
* This interface is used as a tag to make Spring dependency injection happy...
*/
public interface CacheBuster {
}
/*
* 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.cache;
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 {
@CacheEvict(value = "statistics", allEntries = true)
@EventListener
public void handleAfterCommentCreation(final AfterCreationEvent<Comment> event) {
/* Implementation provided by caching aspect. */
}
@CacheEvict(value = "statistics", allEntries = true)
@EventListener
public void handleAfterCommentDeletion(final AfterDeletionEvent<Comment> event) {
/* Implementation provided by caching aspect. */
}
@CacheEvict(value = "answerlists", key = "#event.content.id")
@EventListener
public void handleAfterAnswerCreation(final AfterCreationEvent<Answer> event) {
/* Implementation provided by caching aspect. */
}
@CacheEvict(value = "statistics", allEntries = true)
@EventListener
public void handleChangeScore(final ChangeScoreEvent event) {
/* Implementation provided by caching aspect. */
}
@CacheEvict(value = "statistics", allEntries = true)
@EventListener
public void handleAfterRoomCreation(final AfterCreationEvent<Room> event) {
/* Implementation provided by caching aspect. */
}
@CacheEvict(value = "statistics", allEntries = true)
@EventListener
public void handleAfterRoomDeletion(final AfterDeletionEvent<Room> event) {
/* Implementation provided by caching aspect. */
}
}
/*
* 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.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.
*
* <p>Time intervals:
* <ul>
* <li><code>sessions</code>: 6h</li>
* <li><code>skillquestions</code>, <code>lecturequestions</code>, <code>preparationquestions</code>,
* <code>flashcardquestions</code>: 30min</li>
* <li><code>questions</code>: 30min</li>
* <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() {
/* Implementation provided by caching aspect. */
}
@CacheEvict(value = "contents", allEntries = true)
@Scheduled(initialDelay = 1000 * 50, fixedRate = 1000 * 60 * 30)
private void clearQuestionCache() {
/* Implementation provided by caching aspect. */
}
@CacheEvict(value = "contentlists", allEntries = true)
@Scheduled(initialDelay = 1000 * 75, fixedRate = 1000 * 60 * 30)
private void clearSkillQuestionCache() {
/* Implementation provided by caching aspect. */
}
@CacheEvict(value = "lecturecontentlists", allEntries = true)
@Scheduled(initialDelay = 1000 * 100, fixedRate = 1000 * 60 * 30)
private void clearLectureQuestionCache() {
/* Implementation provided by caching aspect. */
}
@CacheEvict(value = "preparationcontentlists", allEntries = true)
@Scheduled(initialDelay = 1000 * 125, fixedRate = 1000 * 60 * 30)
private void clearPreparationQuestionCache() {
/* Implementation provided by caching aspect. */
}
@CacheEvict(value = "flashcardcontentlists", allEntries = true)
@Scheduled(initialDelay = 1000 * 150, fixedRate = 1000 * 60 * 30)
private void clearFlashcardQuestionCache() {
/* Implementation provided by caching aspect. */
}
@CacheEvict(value = "answerlists", allEntries = true)
@Scheduled(initialDelay = 1000 * 175, fixedRate = 1000 * 60 * 15)
private void clearAnswerCache() {
/* Implementation provided by caching aspect. */
}
@CacheEvict(value = "score", allEntries = true)
@Scheduled(initialDelay = 1000 * 200, fixedRate = 1000 * 60 * 15)
private void clearLearningProgressCache() {
/* Implementation provided by caching aspect. */
}
}
/**
* Classes and interfaces related to caching.
*/
package de.thm.arsnova.cache;
/*
* 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 java.util.Arrays;
import java.util.List;
import org.springframework.boot.autoconfigure.AutoConfigurationImportFilter;
import org.springframework.boot.autoconfigure.AutoConfigurationMetadata;
/**
* An {@link AutoConfigurationImportFilter} that only selects AutoConfiguration
* classes needed for Spring Actuator.
*
* @author Daniel Gerhardt
*/
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 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-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 com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
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.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;
import org.springframework.context.annotation.AdviceMode;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.aspectj.EnableSpringConfigured;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
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.websocket.handler"})
@Configuration
@EnableAsync(mode = AdviceMode.ASPECTJ)
@EnableAutoConfiguration
@EnableCaching(mode = AdviceMode.ASPECTJ)
@EnableScheduling
@EnableSpringConfigured
@EnableWebMvc
@PropertySource(
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 = 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;
@Autowired
private SystemProperties systemProperties;
@Autowired
private SecurityProperties securityProperties;
@Autowired
private WebEndpointProperties webEndpointProperties;
@Override
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(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);
configurer.favorPathExtension(false);
//configurer.defaultContentType(API_V3_MEDIA_TYPE);
configurer.defaultContentTypeStrategy(strategy);
}
@Override
public void configurePathMatch(final PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(false);
}
@Override
public void configureViewResolvers(final ViewResolverRegistry registry) {
registry.viewResolver(new InternalResourceViewResolver());
}
@Override
public void addInterceptors(final InterceptorRegistry registry) {
registry.addInterceptor(cacheControlInterceptorHandler());
registry.addInterceptor(deprecatedApiInterceptorHandler());
registry.addInterceptor(responseInterceptorHandler());
}
@Override
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();
}
@Bean
public DeprecatedApiInterceptorHandler deprecatedApiInterceptorHandler() {
return new DeprecatedApiInterceptorHandler();
}
@Bean
public ResponseInterceptorHandler responseInterceptorHandler() {
return new ResponseInterceptorHandler();
}
@Bean
public StringHttpMessageConverter stringMessageConverter() {
final StringHttpMessageConverter messageConverter = new StringHttpMessageConverter();
messageConverter.setDefaultCharset(StandardCharsets.UTF_8);
messageConverter.setWriteAcceptCharset(false);
final List<MediaType> mediaTypes = new ArrayList<>();
mediaTypes.add(MediaType.TEXT_PLAIN);
mediaTypes.add(MediaType.APPLICATION_XML);
messageConverter.setSupportedMediaTypes(mediaTypes);
return messageConverter;
}
@Bean
public MappingJackson2HttpMessageConverter defaultJsonMessageConverter() {
final Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder
.serializationInclusion(JsonInclude.Include.NON_EMPTY)
.defaultViewInclusion(false)
.indentOutput(systemProperties.getApi().isIndentResponseBody())
.simpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
final ObjectMapper mapper = builder.build();
mapper.setConfig(mapper.getSerializationConfig().withView(View.Public.class));
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);
return converter;
}
@Bean
public MappingJackson2HttpMessageConverter apiV2JsonMessageConverter() {
final Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder
.serializationInclusion(JsonInclude.Include.NON_NULL)
.defaultViewInclusion(false)
.indentOutput(systemProperties.getApi().isIndentResponseBody())
.featuresToEnable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.featuresToEnable(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS)
.modules(new CouchDbDocumentModule());
final ObjectMapper mapper = builder.build();
mapper.setConfig(mapper.getSerializationConfig().withView(View.Public.class));
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);
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();
configurer.setIgnoreUnresolvablePlaceholders(false);
return configurer;
}
@Bean
public PropertiesFactoryBean versionInfoProperties() {
final PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("version.properties"));
return propertiesFactoryBean;
}
@Bean
public CorsFilter corsFilter() {
return new CorsFilter(securityProperties.getCorsOrigins());
}
@Bean(name = "connectorClient")
public ConnectorClient connectorClient() {
if (!systemProperties.getLmsConnector().isEnabled()) {
return null;
}
final ConnectorClientImpl connectorClient = new ConnectorClientImpl();
connectorClient.setServiceLocation(systemProperties.getLmsConnector().getHostUrl());
connectorClient.setUsername(systemProperties.getLmsConnector().getUsername());
connectorClient.setPassword(systemProperties.getLmsConnector().getPassword());
return connectorClient;
}
@Profile("!test")
@Bean(name = "socketServer", initMethod = "startServer", destroyMethod = "stopServer")
public ArsnovaSocketioServer socketServer() {
final ArsnovaSocketioServerImpl socketioServer = new ArsnovaSocketioServerImpl();
socketioServer.setHostIp(systemProperties.getSocketio().getBindAddress());
socketioServer.setPortNumber(systemProperties.getSocketio().getPort());
return socketioServer;
}
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager();
}
@Bean
public JavaMailSenderImpl mailSender() {
final JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
mailSender.setHost(systemProperties.getMail().getHost());
return mailSender;
}
@Bean
public ImageUtils imageUtils() {
return new ImageUtils();
}
@Bean
public FromV2Migrator fromV2Migrator() {
return new FromV2Migrator();
}
@Bean
public ToV2Migrator toV2Migrator() {
return new ToV2Migrator();
}
}