Rewrote most of the project. Changed Spock to JUnit
This commit is contained in:
parent
8210ac6724
commit
1acd2fa781
|
@ -0,0 +1,39 @@
|
||||||
|
plugins {
|
||||||
|
id 'org.springframework.boot' version '2.2.4.RELEASE'
|
||||||
|
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
|
||||||
|
id 'java'
|
||||||
|
}
|
||||||
|
|
||||||
|
group = 'pl.edu.amu.wmi'
|
||||||
|
version = '0.0.1-SNAPSHOT'
|
||||||
|
sourceCompatibility = '11'
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
compileOnly {
|
||||||
|
extendsFrom annotationProcessor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-actuator'
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-security'
|
||||||
|
implementation 'com.auth0:java-jwt:3.4.0'
|
||||||
|
implementation 'org.openpnp:opencv:3.2.0-0'
|
||||||
|
// developmentOnly 'org.springframework.boot:spring-boot-devtools'
|
||||||
|
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||||
|
testImplementation('org.junit.jupiter:junit-jupiter-api')
|
||||||
|
testRuntimeOnly('org.junit.jupiter:junit-jupiter-engine')
|
||||||
|
testCompile('org.junit.jupiter:junit-jupiter-params')
|
||||||
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
useJUnitPlatform{
|
||||||
|
includeEngines 'junit-jupiter'
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
|
@ -0,0 +1,5 @@
|
||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-bin.zip
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
|
@ -0,0 +1,172 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
##
|
||||||
|
## Gradle start up script for UN*X
|
||||||
|
##
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
PRG="$0"
|
||||||
|
# Need this for relative symlinks.
|
||||||
|
while [ -h "$PRG" ] ; do
|
||||||
|
ls=`ls -ld "$PRG"`
|
||||||
|
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||||
|
if expr "$link" : '/.*' > /dev/null; then
|
||||||
|
PRG="$link"
|
||||||
|
else
|
||||||
|
PRG=`dirname "$PRG"`"/$link"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
SAVED="`pwd`"
|
||||||
|
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||||
|
APP_HOME="`pwd -P`"
|
||||||
|
cd "$SAVED" >/dev/null
|
||||||
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
|
APP_BASE_NAME=`basename "$0"`
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS=""
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD="maximum"
|
||||||
|
|
||||||
|
warn () {
|
||||||
|
echo "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "`uname`" in
|
||||||
|
CYGWIN* )
|
||||||
|
cygwin=true
|
||||||
|
;;
|
||||||
|
Darwin* )
|
||||||
|
darwin=true
|
||||||
|
;;
|
||||||
|
MINGW* )
|
||||||
|
msys=true
|
||||||
|
;;
|
||||||
|
NONSTOP* )
|
||||||
|
nonstop=true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="java"
|
||||||
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||||
|
MAX_FD_LIMIT=`ulimit -H -n`
|
||||||
|
if [ $? -eq 0 ] ; then
|
||||||
|
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||||
|
MAX_FD="$MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
ulimit -n $MAX_FD
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Darwin, add options to specify how the application appears in the dock
|
||||||
|
if $darwin; then
|
||||||
|
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Cygwin, switch paths to Windows format before running java
|
||||||
|
if $cygwin ; then
|
||||||
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||||
|
|
||||||
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
|
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||||
|
SEP=""
|
||||||
|
for dir in $ROOTDIRSRAW ; do
|
||||||
|
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||||
|
SEP="|"
|
||||||
|
done
|
||||||
|
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||||
|
# Add a user-defined pattern to the cygpath arguments
|
||||||
|
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||||
|
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||||
|
fi
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
i=0
|
||||||
|
for arg in "$@" ; do
|
||||||
|
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||||
|
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||||
|
|
||||||
|
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||||
|
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||||
|
else
|
||||||
|
eval `echo args$i`="\"$arg\""
|
||||||
|
fi
|
||||||
|
i=$((i+1))
|
||||||
|
done
|
||||||
|
case $i in
|
||||||
|
(0) set -- ;;
|
||||||
|
(1) set -- "$args0" ;;
|
||||||
|
(2) set -- "$args0" "$args1" ;;
|
||||||
|
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||||
|
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||||
|
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||||
|
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||||
|
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||||
|
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||||
|
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Escape application args
|
||||||
|
save () {
|
||||||
|
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||||
|
echo " "
|
||||||
|
}
|
||||||
|
APP_ARGS=$(save "$@")
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||||
|
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||||
|
|
||||||
|
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||||
|
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
|
@ -0,0 +1,84 @@
|
||||||
|
@if "%DEBUG%" == "" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS=
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if "%ERRORLEVEL%" == "0" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:init
|
||||||
|
@rem Get command-line arguments, handling Windows variants
|
||||||
|
|
||||||
|
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||||
|
|
||||||
|
:win9xME_args
|
||||||
|
@rem Slurp the command line arguments.
|
||||||
|
set CMD_LINE_ARGS=
|
||||||
|
set _SKIP=2
|
||||||
|
|
||||||
|
:win9xME_args_slurp
|
||||||
|
if "x%~1" == "x" goto execute
|
||||||
|
|
||||||
|
set CMD_LINE_ARGS=%*
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
|
@ -0,0 +1 @@
|
||||||
|
rootProject.name = 'bookapi'
|
|
@ -0,0 +1,19 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.context.annotation.*;
|
||||||
|
import org.springframework.security.crypto.bcrypt.*;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class BookapiApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(BookapiApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public BCryptPasswordEncoder bCryptPasswordEncoder() {
|
||||||
|
return new BCryptPasswordEncoder();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.api;
|
||||||
|
|
||||||
|
import org.apache.coyote.Response;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import pl.edu.amu.wmi.bookapi.api.dto.BookDto;
|
||||||
|
import pl.edu.amu.wmi.bookapi.service.BookService;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/books")
|
||||||
|
public class BookController {
|
||||||
|
|
||||||
|
BookService bookService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public BookController(BookService bookService) {
|
||||||
|
this.bookService = bookService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public ResponseEntity getBooks() {
|
||||||
|
return ResponseEntity.ok().body(bookService.findAllForUser(
|
||||||
|
getUserName()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/public")
|
||||||
|
public ResponseEntity getAllBooks() {
|
||||||
|
return ResponseEntity.ok().body(
|
||||||
|
bookService.findAll()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PatchMapping("/{bookId}")
|
||||||
|
public ResponseEntity updateBook(@RequestBody BookDto bookDto, @PathVariable String bookId) {
|
||||||
|
String username = getUserName();
|
||||||
|
return ResponseEntity.ok(
|
||||||
|
bookService.updateBook(bookId ,username, bookDto)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{bookId}")
|
||||||
|
public ResponseEntity deleteBook(@PathVariable String bookId) {
|
||||||
|
bookService.deleteBook(
|
||||||
|
getUserName(),
|
||||||
|
bookId
|
||||||
|
);
|
||||||
|
|
||||||
|
return ResponseEntity.ok().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
public ResponseEntity addBook(@RequestBody BookDto bookDto) {
|
||||||
|
System.out.println("Save book");
|
||||||
|
bookService.saveBook(getUserName(), bookDto);
|
||||||
|
return ResponseEntity.ok().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/image")
|
||||||
|
public ResponseEntity addBookAsImage(
|
||||||
|
@RequestParam("file") MultipartFile imageFile,
|
||||||
|
@RequestParam("author") String author,
|
||||||
|
@RequestParam("title") String title) throws Exception {
|
||||||
|
bookService.handleImageUpload(imageFile, author, title);
|
||||||
|
return ResponseEntity.ok().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getUserName() {
|
||||||
|
return "admin";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.api;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import pl.edu.amu.wmi.bookapi.api.dto.MessageDto;
|
||||||
|
import pl.edu.amu.wmi.bookapi.service.MessageService;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/messages")
|
||||||
|
public class MessageController {
|
||||||
|
|
||||||
|
private MessageService messageService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public MessageController(MessageService messageService) {
|
||||||
|
this.messageService = messageService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public ResponseEntity listThreads() {
|
||||||
|
return ResponseEntity.ok(
|
||||||
|
messageService.getThreads(
|
||||||
|
getUserId()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
public ResponseEntity createMessage(@RequestBody MessageDto messageDto) {
|
||||||
|
messageService.createMessage(
|
||||||
|
messageDto.getContent(),
|
||||||
|
messageDto.getAuthor(),
|
||||||
|
messageDto.getRecipient()
|
||||||
|
);
|
||||||
|
|
||||||
|
return ResponseEntity.ok().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{threadId}")
|
||||||
|
public ResponseEntity getMessagesInThread(@PathVariable String threadId) {
|
||||||
|
return ResponseEntity.ok(messageService.getMessagesInThread(threadId, getUserId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private String getUserId() {
|
||||||
|
return "admin";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.api;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class SecurityInterceptor implements HandlerInterceptor {
|
||||||
|
@Override
|
||||||
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.api;
|
||||||
|
|
||||||
|
import org.springframework.dao.DuplicateKeyException;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.crypto.bcrypt.*;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import pl.edu.amu.wmi.bookapi.exceptions.RegisterException;
|
||||||
|
import pl.edu.amu.wmi.bookapi.models.*;
|
||||||
|
import pl.edu.amu.wmi.bookapi.repositories.*;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/users")
|
||||||
|
public class UserController {
|
||||||
|
|
||||||
|
private UserRepository userRepository;
|
||||||
|
private BCryptPasswordEncoder bCryptPasswordEncoder;
|
||||||
|
|
||||||
|
public UserController(UserRepository userRepository,
|
||||||
|
BCryptPasswordEncoder bCryptPasswordEncoder) {
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/sign-up")
|
||||||
|
public void signUp(@RequestBody UserDocument user) throws RegisterException {
|
||||||
|
user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
|
||||||
|
try {
|
||||||
|
userRepository.save(user);
|
||||||
|
} catch (DuplicateKeyException e) {
|
||||||
|
throw new RegisterException("Login already in use");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.api.dto;
|
||||||
|
|
||||||
|
public class BookDto {
|
||||||
|
private String ean;
|
||||||
|
private String author;
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
public BookDto(String ean, String author, String title) {
|
||||||
|
this.ean = ean;
|
||||||
|
this.author = author;
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEan() {
|
||||||
|
return ean;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEan(String ean) {
|
||||||
|
this.ean = ean;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAuthor() {
|
||||||
|
return author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthor(String author) {
|
||||||
|
this.author = author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.api.dto;
|
||||||
|
|
||||||
|
public class MessageDto {
|
||||||
|
private String content;
|
||||||
|
private String author;
|
||||||
|
private String recipient;
|
||||||
|
|
||||||
|
public MessageDto(String content, String author, String recipient) {
|
||||||
|
this.content = content;
|
||||||
|
this.author = author;
|
||||||
|
this.recipient = recipient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(String content) {
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAuthor() {
|
||||||
|
return author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthor(String author) {
|
||||||
|
this.author = author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRecipient() {
|
||||||
|
return recipient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRecipient(String recipient) {
|
||||||
|
this.recipient = recipient;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.api.dto;
|
||||||
|
|
||||||
|
public class PatchBookRequest {
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import java.time.Clock;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class DateTimeProvider {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Instant time() {
|
||||||
|
return Instant.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.exceptions;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
|
||||||
|
@ControllerAdvice
|
||||||
|
public class ExceptionHandlerFilter {
|
||||||
|
@ExceptionHandler(RegisterException.class) public ResponseEntity handleDuplicateUserName() {
|
||||||
|
return ResponseEntity
|
||||||
|
.status(HttpStatus.BAD_REQUEST)
|
||||||
|
.body("Cannot use this username");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.exceptions;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
|
||||||
|
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||||
|
public class RegisterException extends Throwable {
|
||||||
|
public RegisterException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.models;
|
||||||
|
|
||||||
|
import org.springframework.data.annotation.Id;
|
||||||
|
import org.springframework.data.mongodb.core.mapping.Document;
|
||||||
|
import pl.edu.amu.wmi.bookapi.api.dto.BookDto;
|
||||||
|
|
||||||
|
@Document
|
||||||
|
public class BookDocument {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
private String ownerUsername;
|
||||||
|
private String ean;
|
||||||
|
private String author;
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
public BookDocument() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public BookDocument(String ownerUsername, String ean, String author, String title) {
|
||||||
|
this.ownerUsername = ownerUsername;
|
||||||
|
this.ean = ean;
|
||||||
|
this.author = author;
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOwnerUsername() {
|
||||||
|
return ownerUsername;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOwnerUsername(String ownerUsername) {
|
||||||
|
this.ownerUsername = ownerUsername;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEan() {
|
||||||
|
return ean;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEan(String ean) {
|
||||||
|
this.ean = ean;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAuthor() {
|
||||||
|
return author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthor(String author) {
|
||||||
|
this.author = author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BookDocument from(String userName, BookDto bookDto) {
|
||||||
|
return new BookDocument(
|
||||||
|
userName,
|
||||||
|
bookDto.getEan(),
|
||||||
|
bookDto.getAuthor(),
|
||||||
|
bookDto.getTitle()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.models;
|
||||||
|
|
||||||
|
public enum BookGenre {
|
||||||
|
DRAMA,
|
||||||
|
SCIFI,
|
||||||
|
HORROR
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.models;
|
||||||
|
|
||||||
|
import org.springframework.data.annotation.Id;
|
||||||
|
import org.springframework.data.mongodb.core.mapping.Document;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Document
|
||||||
|
public class MessageDocument {
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
private String author;
|
||||||
|
private String recipient;
|
||||||
|
private Date createdAt;
|
||||||
|
private String content;
|
||||||
|
private String threadId;
|
||||||
|
|
||||||
|
public MessageDocument(String author, String recipient, Date createdAt, String content, String threadId) {
|
||||||
|
this.author = author;
|
||||||
|
this.recipient = recipient;
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
this.content = content;
|
||||||
|
this.threadId = threadId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAuthor() {
|
||||||
|
return author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthor(String author) {
|
||||||
|
this.author = author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRecipient() {
|
||||||
|
return recipient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRecipient(String recipient) {
|
||||||
|
this.recipient = recipient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreatedAt() {
|
||||||
|
return createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreatedAt(Date createdAt) {
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(String content) {
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getThreadId() {
|
||||||
|
return threadId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setThreadId(String threadId) {
|
||||||
|
this.threadId = threadId;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.models;
|
||||||
|
|
||||||
|
import org.springframework.data.annotation.Id;
|
||||||
|
import org.springframework.data.mongodb.core.mapping.Document;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Document
|
||||||
|
public class ThreadDocument {
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
private List<String> participantsIds;
|
||||||
|
|
||||||
|
public ThreadDocument(List<String> participantsIds) {
|
||||||
|
this.participantsIds = participantsIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getParticipantsIds() {
|
||||||
|
return participantsIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParticipantsIds(List<String> participantsIds) {
|
||||||
|
this.participantsIds = participantsIds;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.models;
|
||||||
|
|
||||||
|
import org.springframework.data.annotation.*;
|
||||||
|
import org.springframework.data.mongodb.core.index.Indexed;
|
||||||
|
import org.springframework.data.mongodb.core.mapping.*;
|
||||||
|
|
||||||
|
@Document
|
||||||
|
public class UserDocument {
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
@Indexed(unique = true)
|
||||||
|
private String username;
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
public UserDocument() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserDocument(String username, String password) {
|
||||||
|
this.username = username;
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "UserDocument{" +
|
||||||
|
"id='" + id + '\'' +
|
||||||
|
", username='" + username + '\'' +
|
||||||
|
", password='" + password + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.repositories;
|
||||||
|
|
||||||
|
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||||
|
import pl.edu.amu.wmi.bookapi.api.dto.BookDto;
|
||||||
|
import pl.edu.amu.wmi.bookapi.models.BookDocument;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface BookRepository extends MongoRepository<BookDocument, String>, BookRepositoryCustom {
|
||||||
|
List<BookDocument> findAllByOwnerUsername(String ownerUsername);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.repositories;
|
||||||
|
|
||||||
|
import pl.edu.amu.wmi.bookapi.api.dto.BookDto;
|
||||||
|
import pl.edu.amu.wmi.bookapi.models.BookDocument;
|
||||||
|
|
||||||
|
public interface BookRepositoryCustom {
|
||||||
|
BookDocument updateBook(String bookId, String userId, BookDto bookDto);
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.repositories;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.mongodb.core.FindAndModifyOptions;
|
||||||
|
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||||
|
import org.springframework.data.mongodb.core.query.Criteria;
|
||||||
|
import org.springframework.data.mongodb.core.query.Query;
|
||||||
|
import org.springframework.data.mongodb.core.query.Update;
|
||||||
|
import pl.edu.amu.wmi.bookapi.api.dto.BookDto;
|
||||||
|
import pl.edu.amu.wmi.bookapi.models.BookDocument;
|
||||||
|
|
||||||
|
public class BookRepositoryCustomImpl implements BookRepositoryCustom {
|
||||||
|
@Autowired
|
||||||
|
MongoTemplate mongoTemplate;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BookDocument updateBook(String bookId, String userId, BookDto bookDto) {
|
||||||
|
Update update = new Update();
|
||||||
|
if(bookDto.getAuthor() != null) update.set("author", bookDto.getAuthor());
|
||||||
|
if(bookDto.getEan() != null) update.set("ean", bookDto.getEan());
|
||||||
|
if(bookDto.getTitle() != null) update.set("title", bookDto.getTitle());
|
||||||
|
|
||||||
|
return mongoTemplate.findAndModify(
|
||||||
|
new Query(
|
||||||
|
Criteria
|
||||||
|
.where("ownerUsername").is(userId)
|
||||||
|
.and("id").is(bookId)
|
||||||
|
), update, FindAndModifyOptions.options().returnNew(true), BookDocument.class
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.repositories;
|
||||||
|
|
||||||
|
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||||
|
import org.springframework.data.mongodb.repository.Query;
|
||||||
|
import pl.edu.amu.wmi.bookapi.models.MessageDocument;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface MessageRepository extends MongoRepository<MessageDocument, String> {
|
||||||
|
@Query("{ $and: [$or: [{ 'recipient' : ?1}, { 'author': ?1}], {'threadId' : ?0} ]}")
|
||||||
|
List<MessageDocument> findByUserAndThreadId(String threadId, String user);
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.repositories;
|
||||||
|
|
||||||
|
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||||
|
import org.springframework.data.mongodb.repository.Query;
|
||||||
|
import pl.edu.amu.wmi.bookapi.models.ThreadDocument;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface ThreadRepository extends MongoRepository<ThreadDocument, String>, ThreadRepositoryCustom {
|
||||||
|
// @Query("'participantsIds': { $in: [?0, ?1]}")
|
||||||
|
// List<ThreadDocument> findByParticipants(String participantId1, String participantId2);
|
||||||
|
@Query("{'participantsIds': {$in: [?0]}}")
|
||||||
|
List<ThreadDocument> findByParticipant(String participant);
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.repositories;
|
||||||
|
|
||||||
|
import pl.edu.amu.wmi.bookapi.models.ThreadDocument;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface ThreadRepositoryCustom {
|
||||||
|
List<ThreadDocument> findByParticipants(String participantId1, String participantId2);
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.repositories;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||||
|
import org.springframework.data.mongodb.core.query.Criteria;
|
||||||
|
import org.springframework.data.mongodb.core.query.Query;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import pl.edu.amu.wmi.bookapi.models.ThreadDocument;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class ThreadRepositoryCustomImpl implements ThreadRepositoryCustom {
|
||||||
|
|
||||||
|
MongoTemplate mongoTemplate;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public ThreadRepositoryCustomImpl(MongoTemplate mongoTemplate) {
|
||||||
|
this.mongoTemplate = mongoTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ThreadDocument> findByParticipants(String participantId1, String participantId2) {
|
||||||
|
Query query = new Query();
|
||||||
|
query.addCriteria(
|
||||||
|
Criteria.where("participantsIds").all(List.of(participantId1, participantId2))
|
||||||
|
);
|
||||||
|
|
||||||
|
return mongoTemplate.find(query, ThreadDocument.class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.repositories;
|
||||||
|
|
||||||
|
import org.springframework.data.mongodb.repository.*;
|
||||||
|
import pl.edu.amu.wmi.bookapi.models.*;
|
||||||
|
|
||||||
|
public interface UserRepository extends MongoRepository<UserDocument, String> {
|
||||||
|
UserDocument findByUsername(String username);
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.security;
|
||||||
|
|
||||||
|
import com.auth0.jwt.*;
|
||||||
|
import com.fasterxml.jackson.databind.*;
|
||||||
|
import org.springframework.security.authentication.*;
|
||||||
|
import org.springframework.security.core.*;
|
||||||
|
import org.springframework.security.core.userdetails.*;
|
||||||
|
import org.springframework.security.web.authentication.*;
|
||||||
|
import pl.edu.amu.wmi.bookapi.models.*;
|
||||||
|
|
||||||
|
import javax.servlet.*;
|
||||||
|
import javax.servlet.http.*;
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static com.auth0.jwt.algorithms.Algorithm.*;
|
||||||
|
|
||||||
|
public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
|
||||||
|
private AuthenticationManager authenticationManager;
|
||||||
|
|
||||||
|
public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
|
||||||
|
this.authenticationManager = authenticationManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final String SECRET = "SecretKeyToGenJWTs";
|
||||||
|
public static final long EXPIRATION_TIME = 864_000_000; // 10 days
|
||||||
|
public static final String TOKEN_PREFIX = "Bearer ";
|
||||||
|
public static final String HEADER_STRING = "Authorization";
|
||||||
|
public static final String SIGN_UP_URL = "/users/sign-up";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Authentication attemptAuthentication(HttpServletRequest req,
|
||||||
|
HttpServletResponse res) throws AuthenticationException {
|
||||||
|
try {
|
||||||
|
UserDocument creds = new ObjectMapper()
|
||||||
|
.readValue(req.getInputStream(), UserDocument.class);
|
||||||
|
|
||||||
|
return authenticationManager.authenticate(
|
||||||
|
new UsernamePasswordAuthenticationToken(
|
||||||
|
creds.getUsername(),
|
||||||
|
creds.getPassword(),
|
||||||
|
new ArrayList<>())
|
||||||
|
);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void successfulAuthentication(HttpServletRequest req,
|
||||||
|
HttpServletResponse res,
|
||||||
|
FilterChain chain,
|
||||||
|
Authentication auth) throws IOException, ServletException {
|
||||||
|
|
||||||
|
String token = JWT.create()
|
||||||
|
.withSubject(((User) auth.getPrincipal()).getUsername())
|
||||||
|
.withExpiresAt(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
|
||||||
|
.sign(HMAC512(SECRET.getBytes()));
|
||||||
|
|
||||||
|
res.addHeader(HEADER_STRING, TOKEN_PREFIX + token);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.security;
|
||||||
|
|
||||||
|
import com.auth0.jwt.*;
|
||||||
|
import com.auth0.jwt.algorithms.*;
|
||||||
|
import org.springframework.security.authentication.*;
|
||||||
|
import org.springframework.security.core.context.*;
|
||||||
|
import org.springframework.security.web.authentication.www.*;
|
||||||
|
|
||||||
|
import javax.servlet.*;
|
||||||
|
import javax.servlet.http.*;
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static pl.edu.amu.wmi.bookapi.security.JWTAuthenticationFilter.*;
|
||||||
|
|
||||||
|
public class JWTAuthorizationFilter extends BasicAuthenticationFilter {
|
||||||
|
|
||||||
|
public JWTAuthorizationFilter(AuthenticationManager authManager) {
|
||||||
|
super(authManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(HttpServletRequest req,
|
||||||
|
HttpServletResponse res,
|
||||||
|
FilterChain chain) throws IOException, ServletException {
|
||||||
|
String header = req.getHeader(HEADER_STRING);
|
||||||
|
|
||||||
|
if (header == null || !header.startsWith(TOKEN_PREFIX)) {
|
||||||
|
chain.doFilter(req, res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UsernamePasswordAuthenticationToken authentication = getAuthentication(req);
|
||||||
|
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||||
|
chain.doFilter(req, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
|
||||||
|
String token = request.getHeader(HEADER_STRING);
|
||||||
|
if (token != null) {
|
||||||
|
String user = JWT.require(Algorithm.HMAC512(SECRET.getBytes()))
|
||||||
|
.build()
|
||||||
|
.verify(token.replace(TOKEN_PREFIX, ""))
|
||||||
|
.getSubject();
|
||||||
|
|
||||||
|
System.out.println();
|
||||||
|
if (user != null) {
|
||||||
|
return new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.security;
|
||||||
|
|
||||||
|
import org.springframework.security.core.userdetails.*;
|
||||||
|
import org.springframework.stereotype.*;
|
||||||
|
import pl.edu.amu.wmi.bookapi.models.*;
|
||||||
|
import pl.edu.amu.wmi.bookapi.repositories.*;
|
||||||
|
|
||||||
|
import static java.util.Collections.*;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class UserDetailsSecurityServiceImpl implements UserDetailsService {
|
||||||
|
private UserRepository userRepository;
|
||||||
|
|
||||||
|
public UserDetailsSecurityServiceImpl(UserRepository userRepository) {
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||||
|
UserDocument applicationUser = userRepository.findByUsername(username);
|
||||||
|
if (applicationUser == null) {
|
||||||
|
throw new UsernameNotFoundException(username);
|
||||||
|
}
|
||||||
|
return new User(applicationUser.getUsername(), applicationUser.getPassword(), emptyList());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.security;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.*;
|
||||||
|
import org.springframework.http.*;
|
||||||
|
import org.springframework.security.config.annotation.authentication.builders.*;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.*;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.*;
|
||||||
|
import org.springframework.security.config.http.*;
|
||||||
|
import org.springframework.security.crypto.bcrypt.*;
|
||||||
|
import org.springframework.web.cors.*;
|
||||||
|
|
||||||
|
import static pl.edu.amu.wmi.bookapi.security.JWTAuthenticationFilter.*;
|
||||||
|
|
||||||
|
@EnableWebSecurity
|
||||||
|
public class WebSecurity extends WebSecurityConfigurerAdapter {
|
||||||
|
private UserDetailsSecurityServiceImpl userDetailsService;
|
||||||
|
private BCryptPasswordEncoder bCryptPasswordEncoder;
|
||||||
|
|
||||||
|
public WebSecurity(UserDetailsSecurityServiceImpl userDetailsService, BCryptPasswordEncoder bCryptPasswordEncoder) {
|
||||||
|
this.userDetailsService = userDetailsService;
|
||||||
|
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
|
http.cors().and().csrf().disable()
|
||||||
|
.authorizeRequests()
|
||||||
|
.antMatchers(HttpMethod.GET, "/api/books", "/api/messages/", "/api/messages/*", "/api/books/public").permitAll()
|
||||||
|
.antMatchers(HttpMethod.DELETE, "/api/books/*").permitAll()
|
||||||
|
.antMatchers(HttpMethod.PATCH, "/api/books/*").permitAll()
|
||||||
|
.antMatchers(HttpMethod.POST,
|
||||||
|
SIGN_UP_URL,
|
||||||
|
"/api/books",
|
||||||
|
"/api/books/image",
|
||||||
|
"/api/messages").permitAll()
|
||||||
|
.anyRequest().authenticated()
|
||||||
|
.and()
|
||||||
|
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
|
||||||
|
.addFilter(new JWTAuthorizationFilter(authenticationManager()))
|
||||||
|
// this disables session creation on Spring Security
|
||||||
|
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||||
|
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
CorsConfigurationSource corsConfigurationSource() {
|
||||||
|
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||||
|
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.service;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import pl.edu.amu.wmi.bookapi.api.dto.BookDto;
|
||||||
|
import pl.edu.amu.wmi.bookapi.models.BookDocument;
|
||||||
|
import pl.edu.amu.wmi.bookapi.repositories.BookRepository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class BookService {
|
||||||
|
|
||||||
|
BookRepository bookRepository;
|
||||||
|
ImageProcessingService imageProcessingService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public BookService(BookRepository bookRepository, ImageProcessingService imageProcessingService) {
|
||||||
|
this.imageProcessingService = imageProcessingService;
|
||||||
|
this.bookRepository = bookRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteBook(String userName, String bookId) {
|
||||||
|
bookRepository.deleteById(bookId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<BookDocument> findAllForUser(String userName) {
|
||||||
|
return bookRepository.findAllByOwnerUsername(userName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveBook(String userName, BookDto bookDto) {
|
||||||
|
System.out.println("saving");
|
||||||
|
System.out.println(bookRepository.save(BookDocument.from(userName, bookDto)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleImageUpload(MultipartFile imageFile, String author, String title) throws Exception {
|
||||||
|
String detectedEan = imageProcessingService.getDecodedEan(imageFile);
|
||||||
|
if (detectedEan == null) detectedEan = "Test";
|
||||||
|
saveBook("admin", new BookDto(detectedEan, author, title));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<BookDocument> findAll() {
|
||||||
|
return bookRepository.findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BookDocument updateBook(String bookId, String userId, BookDto bookDto) {
|
||||||
|
return bookRepository.updateBook(bookId, userId, bookDto);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.service;
|
||||||
|
|
||||||
|
import org.opencv.core.Core;
|
||||||
|
import org.opencv.core.Mat;
|
||||||
|
import org.opencv.core.MatOfByte;
|
||||||
|
import org.opencv.imgcodecs.Imgcodecs;
|
||||||
|
import org.opencv.imgproc.Imgproc;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static java.lang.System.loadLibrary;
|
||||||
|
import static org.opencv.imgproc.Imgproc.COLOR_BGR2GRAY;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ImageProcessingService {
|
||||||
|
|
||||||
|
public ImageProcessingService() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDecodedEan(MultipartFile imageFile) throws Exception {
|
||||||
|
|
||||||
|
String fileId = UUID.randomUUID().toString();
|
||||||
|
Path path = Path.of(new File(".").getCanonicalPath());
|
||||||
|
|
||||||
|
byte[] starting = imageFile.getBytes();
|
||||||
|
|
||||||
|
saveImg(starting, path, fileId, 1);
|
||||||
|
|
||||||
|
Mat mat = Imgcodecs.imdecode(new MatOfByte(starting), Imgcodecs.CV_LOAD_IMAGE_UNCHANGED);
|
||||||
|
|
||||||
|
Mat gray = new Mat();
|
||||||
|
Imgproc.cvtColor(mat, gray, COLOR_BGR2GRAY);
|
||||||
|
|
||||||
|
byte[] grayed = mat2byteArr(gray);
|
||||||
|
|
||||||
|
saveImg(grayed, path, fileId, 2);
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] mat2byteArr(Mat mat) {
|
||||||
|
byte[] bytes = new byte[0];
|
||||||
|
mat.get(0, 0, bytes);
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveImg(byte[] bytes, Path path, String imageName, Integer version) throws IOException {
|
||||||
|
Files.write(Path.of(path.toString(), "/" + imageName + "__v" + version + ".png"), bytes);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.service;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import pl.edu.amu.wmi.bookapi.config.DateTimeProvider;
|
||||||
|
import pl.edu.amu.wmi.bookapi.models.MessageDocument;
|
||||||
|
import pl.edu.amu.wmi.bookapi.models.ThreadDocument;
|
||||||
|
import pl.edu.amu.wmi.bookapi.repositories.MessageRepository;
|
||||||
|
import pl.edu.amu.wmi.bookapi.repositories.ThreadRepository;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class MessageService {
|
||||||
|
|
||||||
|
DateTimeProvider dateTimeProvider;
|
||||||
|
ThreadRepository threadRepository;
|
||||||
|
MessageRepository messageRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public MessageService(ThreadRepository threadRepository,
|
||||||
|
MessageRepository messageRepository,
|
||||||
|
DateTimeProvider dateTimeProvider) {
|
||||||
|
this.dateTimeProvider = dateTimeProvider;
|
||||||
|
this.threadRepository = threadRepository;
|
||||||
|
this.messageRepository = messageRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ThreadDocument> getThreads(String user) {
|
||||||
|
return threadRepository.findByParticipant(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<MessageDocument> getMessagesInThread(String threadId, String userId) {
|
||||||
|
return messageRepository.findByUserAndThreadId(threadId, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createMessage(String content, String author, String recipient) {
|
||||||
|
String threadId = null;
|
||||||
|
List<ThreadDocument> foundThreads = threadRepository.findByParticipants(author, recipient);
|
||||||
|
|
||||||
|
if(foundThreads.size() == 0) {threadId = createThread(author, recipient);} else {
|
||||||
|
threadId = foundThreads.get(0).getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
createMessageInThread(
|
||||||
|
threadId,
|
||||||
|
author,
|
||||||
|
recipient,
|
||||||
|
content,
|
||||||
|
Date.from(dateTimeProvider.time())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String createThread(String author, String recipient) {
|
||||||
|
ThreadDocument savedThread = threadRepository.save(new ThreadDocument(List.of(author, recipient)));
|
||||||
|
return savedThread.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createMessageInThread(
|
||||||
|
String threadId,
|
||||||
|
String author,
|
||||||
|
String recipient,
|
||||||
|
String content,
|
||||||
|
Date date) {
|
||||||
|
messageRepository.save(
|
||||||
|
new MessageDocument(
|
||||||
|
author,
|
||||||
|
recipient,
|
||||||
|
date,
|
||||||
|
content,
|
||||||
|
threadId
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.*;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.data.mongodb.core.*;
|
||||||
|
import pl.edu.amu.wmi.bookapi.models.*;
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
class BookapiApplicationTests {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
MongoTemplate mongoTemplate;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void contextLoads() {
|
||||||
|
mongoTemplate.save(new UserDocument("test", "test"));
|
||||||
|
System.out.println(mongoTemplate.findAll(UserDocument.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.Integration;
|
||||||
|
|
||||||
|
import com.mongodb.*;
|
||||||
|
import org.junit.jupiter.api.*;
|
||||||
|
import org.springframework.beans.factory.annotation.*;
|
||||||
|
import org.springframework.boot.test.context.*;
|
||||||
|
import org.springframework.data.mongodb.core.*;
|
||||||
|
import org.springframework.data.mongodb.core.query.*;
|
||||||
|
import pl.edu.amu.wmi.bookapi.models.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class BaseInt {
|
||||||
|
public MongoTemplate mongoTemplate;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public BaseInt(MongoTemplate mongoTemplate) {
|
||||||
|
this.mongoTemplate = mongoTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
public void cleanUp() {
|
||||||
|
List.of(
|
||||||
|
UserDocument.class
|
||||||
|
).forEach(it -> this.mongoTemplate.remove(it));
|
||||||
|
|
||||||
|
System.out.println("Removing classes in cleanUp method");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,123 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.Integration.api;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.TestInstance;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
import pl.edu.amu.wmi.bookapi.fixtures.IntegrationTestUtil;
|
||||||
|
import pl.edu.amu.wmi.bookapi.fixtures.api.BookControllerRequest;
|
||||||
|
import pl.edu.amu.wmi.bookapi.models.BookDocument;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
@AutoConfigureMockMvc
|
||||||
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
|
@EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class })
|
||||||
|
public class BookControllerInt {
|
||||||
|
@Autowired
|
||||||
|
MongoTemplate mongoTemplate;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
MockMvc mvc;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
IntegrationTestUtil testUtil;
|
||||||
|
|
||||||
|
private BookControllerRequest bookRequests;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void cleanCollections() {
|
||||||
|
this.bookRequests = new BookControllerRequest(mvc, new ObjectMapper());
|
||||||
|
testUtil.cleanCollections();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void should_add_a_book() throws Exception {
|
||||||
|
this.bookRequests.addBook("admin", "12345", "auth", "title")
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
assertEquals(mongoTemplate.findAll(BookDocument.class).get(0).getEan(), "12345");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void should_list_books_for_user() throws Exception {
|
||||||
|
this.bookRequests.addBook("admin", "12345", "auth", "title")
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
this.bookRequests.addBook("admin", "12345", "auth", "title")
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
bookRequests.getBooksForUser("admin")
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.*.ownerUsername", equalTo(List.of("admin", "admin"))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void should_delete_a_book() throws Exception {
|
||||||
|
this.bookRequests.addBook("admin", "12345", "auth", "title")
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
BookDocument foundBook = mongoTemplate.findAll(BookDocument.class).get(0);
|
||||||
|
assertEquals(foundBook.getEan(), "12345");
|
||||||
|
this.bookRequests.deleteBook("admin", foundBook.getId());
|
||||||
|
assertEquals(0, mongoTemplate.findAll(BookDocument.class).size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void should_list_all_books() throws Exception {
|
||||||
|
this.bookRequests.addBook("admin1", "123451", "auth1", "title1")
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
this.bookRequests.addBook("admin2", "123452", "auth2", "title2")
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
this.bookRequests.addBook("admin3", "123453", "auth3", "title3")
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
|
||||||
|
this.bookRequests.getAllBooks()
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$").isArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void should_update_a_book() throws Exception {
|
||||||
|
this.bookRequests.addBook("admin", "12345", "1", "2")
|
||||||
|
.andDo(print());
|
||||||
|
BookDocument foundBook = mongoTemplate.findAll(BookDocument.class).get(0);
|
||||||
|
String bookId = foundBook.getId();
|
||||||
|
|
||||||
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
this.bookRequests.updateBook(bookId, "admin",
|
||||||
|
"{\n" +
|
||||||
|
" \"ean\": " + objectMapper.writeValueAsString("ean") + ",\n" +
|
||||||
|
" \"author\": " + objectMapper.writeValueAsString("author") + ",\n" +
|
||||||
|
" \"title\": " + objectMapper.writeValueAsString("title") + "\n" +
|
||||||
|
"}").andExpect(status().isOk());
|
||||||
|
|
||||||
|
BookDocument foundBookAfterUpdate = mongoTemplate.findAll(BookDocument.class).get(0);
|
||||||
|
|
||||||
|
assertEquals("ean", foundBookAfterUpdate.getEan());
|
||||||
|
assertEquals("author", foundBookAfterUpdate.getAuthor());
|
||||||
|
assertEquals("title", foundBookAfterUpdate.getTitle());
|
||||||
|
|
||||||
|
// And should allow for partial update
|
||||||
|
this.bookRequests.updateBook(bookId, "admin",
|
||||||
|
"{\n" +
|
||||||
|
" \"ean\": " + objectMapper.writeValueAsString("ean-1-modified") + "\n" +
|
||||||
|
"}").andExpect(status().isOk());
|
||||||
|
|
||||||
|
BookDocument foundBookAfterPartialUpdate = mongoTemplate.findAll(BookDocument.class).get(0);
|
||||||
|
|
||||||
|
assertEquals("ean-1-modified", foundBookAfterPartialUpdate.getEan());
|
||||||
|
assertEquals("author", foundBookAfterPartialUpdate.getAuthor());
|
||||||
|
assertEquals("title", foundBookAfterPartialUpdate.getTitle());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.Integration.api;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.TestInstance;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
import pl.edu.amu.wmi.bookapi.fixtures.IntegrationTestUtil;
|
||||||
|
import pl.edu.amu.wmi.bookapi.fixtures.api.BookControllerRequest;
|
||||||
|
import pl.edu.amu.wmi.bookapi.fixtures.api.MessageControllerRequests;
|
||||||
|
import pl.edu.amu.wmi.bookapi.models.MessageDocument;
|
||||||
|
import pl.edu.amu.wmi.bookapi.models.ThreadDocument;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
@AutoConfigureMockMvc
|
||||||
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
|
@EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class })
|
||||||
|
public class MessageControllerInt {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
MongoTemplate mongoTemplate;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
MockMvc mvc;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
IntegrationTestUtil testUtil;
|
||||||
|
|
||||||
|
private MessageControllerRequests messageControllerRequests;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void cleanCollections() {
|
||||||
|
this.messageControllerRequests = new MessageControllerRequests(mvc, new ObjectMapper());
|
||||||
|
testUtil.cleanCollections();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void should_start_new_thread_if_does_not_exist() throws Exception {
|
||||||
|
messageControllerRequests.postMessage(
|
||||||
|
"content",
|
||||||
|
"id-1",
|
||||||
|
"id-2"
|
||||||
|
).andExpect(status().isOk());;
|
||||||
|
assertEquals(1, mongoTemplate.findAll(ThreadDocument.class).size());
|
||||||
|
assertEquals(1, mongoTemplate.findAll(MessageDocument.class).size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void if_thread_exists_it_should_not_create_new() throws Exception {
|
||||||
|
messageControllerRequests.postMessage(
|
||||||
|
"content",
|
||||||
|
"id-1",
|
||||||
|
"id-2"
|
||||||
|
).andExpect(status().isOk());
|
||||||
|
assertEquals(1, mongoTemplate.findAll(ThreadDocument.class).size());
|
||||||
|
assertEquals(1, mongoTemplate.findAll(MessageDocument.class).size());
|
||||||
|
|
||||||
|
messageControllerRequests.postMessage(
|
||||||
|
"content",
|
||||||
|
"id-1",
|
||||||
|
"id-2"
|
||||||
|
).andExpect(status().isOk());;
|
||||||
|
|
||||||
|
assertEquals(1, mongoTemplate.findAll(ThreadDocument.class).size());
|
||||||
|
assertEquals(2, mongoTemplate.findAll(MessageDocument.class).size());
|
||||||
|
|
||||||
|
messageControllerRequests.postMessage(
|
||||||
|
"content",
|
||||||
|
"id-1",
|
||||||
|
"id-5"
|
||||||
|
).andExpect(status().isOk());
|
||||||
|
|
||||||
|
assertEquals(2, mongoTemplate.findAll(ThreadDocument.class).size());
|
||||||
|
assertEquals(3, mongoTemplate.findAll(MessageDocument.class).size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void it_should_allow_to_send_a_message() throws Exception {
|
||||||
|
messageControllerRequests.postMessage(
|
||||||
|
"content",
|
||||||
|
"id-1",
|
||||||
|
"id-5"
|
||||||
|
).andExpect(status().isOk());
|
||||||
|
|
||||||
|
assertEquals(1, mongoTemplate.findAll(ThreadDocument.class).size());
|
||||||
|
assertEquals(1, mongoTemplate.findAll(MessageDocument.class).size());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.Integration.api;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.*;
|
||||||
|
import org.junit.*;
|
||||||
|
import org.junit.jupiter.api.*;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.*;
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.*;
|
||||||
|
import org.springframework.boot.test.context.*;
|
||||||
|
import org.springframework.data.mongodb.core.*;
|
||||||
|
import org.springframework.test.web.servlet.*;
|
||||||
|
import pl.edu.amu.wmi.bookapi.fixtures.*;
|
||||||
|
import pl.edu.amu.wmi.bookapi.fixtures.api.*;
|
||||||
|
import pl.edu.amu.wmi.bookapi.models.UserDocument;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
@AutoConfigureMockMvc
|
||||||
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
|
public class UserControllerInt{
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
MongoTemplate mongoTemplate;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
MockMvc mvc;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
IntegrationTestUtil testUtil;
|
||||||
|
|
||||||
|
private UserControllerRequests userRequests;
|
||||||
|
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void cleanCollections() {
|
||||||
|
this.userRequests = new UserControllerRequests(mvc, new ObjectMapper());
|
||||||
|
testUtil.cleanCollections();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void should_register_new_user() throws Exception {
|
||||||
|
userRequests.registerUser("Abc", "def")
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
assertEquals(mongoTemplate.findAll(UserDocument.class).size(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void user_should_not_be_able_to_create_account_with_already_existing_login() throws Exception {
|
||||||
|
userRequests.registerUser("a", "def")
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
userRequests.registerUser("a", "fed")
|
||||||
|
.andExpect(status().is4xxClientError());
|
||||||
|
assertEquals(mongoTemplate.findAll(UserDocument.class).size(), 1);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.fixtures;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.*;
|
||||||
|
import org.springframework.data.mongodb.core.*;
|
||||||
|
import org.springframework.data.mongodb.core.query.*;
|
||||||
|
import org.springframework.stereotype.*;
|
||||||
|
import pl.edu.amu.wmi.bookapi.models.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class IntegrationTestUtil {
|
||||||
|
@Autowired
|
||||||
|
MongoTemplate mongoTemplate;
|
||||||
|
|
||||||
|
public void cleanCollections() {
|
||||||
|
List.of(
|
||||||
|
UserDocument.class,
|
||||||
|
BookDocument.class,
|
||||||
|
MessageDocument.class,
|
||||||
|
ThreadDocument.class
|
||||||
|
).forEach(it -> mongoTemplate.remove(new Query(), it));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.fixtures.api;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
import org.springframework.test.web.servlet.ResultActions;
|
||||||
|
import pl.edu.amu.wmi.bookapi.models.BookDocument;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||||
|
|
||||||
|
public class BookControllerRequest {
|
||||||
|
private final MockMvc mvc;
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
public BookControllerRequest(MockMvc mvc, ObjectMapper objectMapper) {
|
||||||
|
this.mvc = mvc;
|
||||||
|
this.objectMapper = objectMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResultActions getBooksForUser(String userName) throws Exception {
|
||||||
|
return mvc.perform(get("/api/books"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResultActions getAllBooks() throws Exception {
|
||||||
|
return mvc.perform(get("/api/books/public"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResultActions updateBook(String bookId, String userId, String jsonBody) throws Exception {
|
||||||
|
return mvc.perform(patch("/api/books/" + bookId)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content(jsonBody));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResultActions deleteBook(String userName, String bookId) throws Exception {
|
||||||
|
return mvc.perform(delete("/api/books/" + bookId));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResultActions addBook(
|
||||||
|
String userName,
|
||||||
|
String ean,
|
||||||
|
String author,
|
||||||
|
String title
|
||||||
|
) throws Exception {
|
||||||
|
return mvc.perform(post(URI.create("/api/books"))
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content("{\n" +
|
||||||
|
" \"ean\": " + objectMapper.writeValueAsString(ean) + ",\n" +
|
||||||
|
" \"author\": " + objectMapper.writeValueAsString(author) + ",\n" +
|
||||||
|
" \"title\": " + objectMapper.writeValueAsString(title) + "\n" +
|
||||||
|
"}"));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.fixtures.api;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
import org.springframework.test.web.servlet.ResultActions;
|
||||||
|
import pl.edu.amu.wmi.bookapi.api.dto.MessageDto;
|
||||||
|
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||||
|
|
||||||
|
public class MessageControllerRequests {
|
||||||
|
private final MockMvc mvc;
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
public MessageControllerRequests(MockMvc mvc, ObjectMapper objectMapper) {
|
||||||
|
this.mvc = mvc;
|
||||||
|
this.objectMapper = objectMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResultActions getThreads(String userId) throws Exception {
|
||||||
|
return mvc.perform(get("/api/messages"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResultActions getMessages(String userId, String threadId) throws Exception {
|
||||||
|
return mvc.perform(get("/api/messages" + threadId));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResultActions postMessage(String content, String author, String recipient) throws Exception {
|
||||||
|
System.out.println("Content");
|
||||||
|
System.out.println("{\n" +
|
||||||
|
"\"content\": " + objectMapper.writeValueAsString(content) + ",\n" +
|
||||||
|
"\"author\": " + objectMapper.writeValueAsString(author) + ",\n" +
|
||||||
|
"\"recipient\": " + objectMapper.writeValueAsString(recipient) + "\n" +
|
||||||
|
"}");
|
||||||
|
|
||||||
|
return mvc.perform(post("/api/messages")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content("{\n" +
|
||||||
|
"\"content\": " + objectMapper.writeValueAsString(content) + ",\n" +
|
||||||
|
"\"author\": " + objectMapper.writeValueAsString(author) + ",\n" +
|
||||||
|
"\"recipient\": " + objectMapper.writeValueAsString(recipient) + "\n" +
|
||||||
|
"}")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package pl.edu.amu.wmi.bookapi.fixtures.api;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
import org.springframework.test.web.servlet.ResultActions;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||||
|
|
||||||
|
public class UserControllerRequests {
|
||||||
|
|
||||||
|
private final MockMvc mvc;
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
public UserControllerRequests(MockMvc mvc, ObjectMapper objectMapper) {
|
||||||
|
this.mvc = mvc;
|
||||||
|
this.objectMapper = objectMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResultActions registerUser(String userName, String password) throws Exception {
|
||||||
|
return mvc.perform(post(URI.create("/users/sign-up"))
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content("{\n" +
|
||||||
|
" \"username\": " + objectMapper.writeValueAsString(userName) + ",\n" +
|
||||||
|
" \"password\": " + objectMapper.writeValueAsString(password) + "\n" +
|
||||||
|
"}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue