Added project
This commit is contained in:
52
.gitignore
vendored
52
.gitignore
vendored
@@ -1,26 +1,36 @@
|
|||||||
# ---> Java
|
HELP.md
|
||||||
# Compiled class file
|
target/
|
||||||
*.class
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
!**/src/main/**/target/
|
||||||
# Log file
|
!**/src/test/**/target/
|
||||||
|
.idea/
|
||||||
|
*.gz
|
||||||
*.log
|
*.log
|
||||||
|
|
||||||
# BlueJ files
|
### STS ###
|
||||||
*.ctxt
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
# Mobile Tools for Java (J2ME)
|
### IntelliJ IDEA ###
|
||||||
.mtj.tmp/
|
.idea
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
# Package Files #
|
### NetBeans ###
|
||||||
*.jar
|
/nbproject/private/
|
||||||
*.war
|
/nbbuild/
|
||||||
*.nar
|
/dist/
|
||||||
*.ear
|
/nbdist/
|
||||||
*.zip
|
/.nb-gradle/
|
||||||
*.tar.gz
|
build/
|
||||||
*.rar
|
!**/src/main/**/build/
|
||||||
|
!**/src/test/**/build/
|
||||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
|
||||||
hs_err_pid*
|
|
||||||
replay_pid*
|
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
||||||
|
|||||||
234
README.md
234
README.md
@@ -1,3 +1,233 @@
|
|||||||
# profile-rest-service
|
# Тестовое задание
|
||||||
|
|
||||||
Тестовое задание. В качестве тестового задания необходимо реализовать RESTfull приложение.
|
## Общее описание
|
||||||
|
|
||||||
|
В качестве тестового задания необходимо реализовать RESTfull приложение
|
||||||
|
|
||||||
|
1. При разработке использовать spring boot остальное на ваше усмотрение, желательно придерживаться экосистемы spring.
|
||||||
|
1. При разработке использовать в качестве базы Postgres
|
||||||
|
1. cross-origin должно быть отключено.
|
||||||
|
1. доступ к сервису возможен только при наличии токена ‘secret’ во всех остальных случаях кроме “GET /exit” возвращать 401 название и реализация на ваше усмотрение, инструкция для передачи токена должна прилагаться в месте с тестовым заданием.
|
||||||
|
1. сервис должен запускаться на 8010 порту
|
||||||
|
1. name и email должны быть регистронезависимые
|
||||||
|
1. Добавить фильтр при регистрации на проверку уникальности поля email в случае если Email есть в базе возвращать 409 статус
|
||||||
|
1. к исходникам должен прилагаться артефакт приложения
|
||||||
|
1. Для данного приложения реализуйте и подключил OpenApi (swagger)
|
||||||
|
1. Версия java не выше 11
|
||||||
|
1. Сборщик Maven
|
||||||
|
|
||||||
|
## Описание endpoints
|
||||||
|
|
||||||
|
### POST /profiles/set
|
||||||
|
|
||||||
|
Создает запись профиля и присваивает ему id
|
||||||
|
|
||||||
|
**Request**:
|
||||||
|
|
||||||
|
принимает json следующей структурой:
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"name": string
|
||||||
|
"email": string
|
||||||
|
"age": int
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Responses**:
|
||||||
|
|
||||||
|
в случае успеха возвращает id записи пользователя
|
||||||
|
|
||||||
|
**_status 200_**
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"idUser": int
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
В случае не корректного email
|
||||||
|
|
||||||
|
**_status 400_**
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"msg": string
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
В случае если email уже передавался (реализовать через фильтр)
|
||||||
|
|
||||||
|
**_status 403_**
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
“msg”: string
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### GET /profiles/last
|
||||||
|
|
||||||
|
Возвращает последний созданный профиль
|
||||||
|
|
||||||
|
**Responses**:
|
||||||
|
|
||||||
|
**_status 200_**
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"id": int
|
||||||
|
"name": string
|
||||||
|
"email": string
|
||||||
|
"age": int
|
||||||
|
"created": timestamp
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### GET /profiles
|
||||||
|
|
||||||
|
Возвращает все созданные профили
|
||||||
|
|
||||||
|
**Responses**:
|
||||||
|
|
||||||
|
**_status 200_**
|
||||||
|
|
||||||
|
```
|
||||||
|
[{
|
||||||
|
"id": int
|
||||||
|
"name": string
|
||||||
|
"email": string
|
||||||
|
"age": int
|
||||||
|
"created": timestamp
|
||||||
|
}...]
|
||||||
|
```
|
||||||
|
|
||||||
|
###GET /profiles/{ID}
|
||||||
|
|
||||||
|
Возвращает профиль по его ID
|
||||||
|
|
||||||
|
Responses:
|
||||||
|
|
||||||
|
**_status 200_**
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"id": int
|
||||||
|
"name": string
|
||||||
|
"email": string
|
||||||
|
"age": int
|
||||||
|
"created": timestamp
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**_status 404_**
|
||||||
|
|
||||||
|
в случае если запись не найдена
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"msg": string
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### POST /profiles/get
|
||||||
|
|
||||||
|
Возвращает профиль по email
|
||||||
|
|
||||||
|
**Request**:
|
||||||
|
|
||||||
|
принимает json следующей структурой:
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"email": string
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Responses**:
|
||||||
|
|
||||||
|
**_status 200_**
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
'id": int
|
||||||
|
"name": string
|
||||||
|
"email": string
|
||||||
|
"age": int
|
||||||
|
"created": timestamp
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**_status 404_**
|
||||||
|
|
||||||
|
в случае если запись не найдена
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"msg": string
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### GET /error/last
|
||||||
|
|
||||||
|
Возвращает сообщение последней ошибки
|
||||||
|
|
||||||
|
**Responses**:
|
||||||
|
|
||||||
|
**_status 200_**
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"msg": string
|
||||||
|
"created": timestamp
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Не обязательная часть задания:
|
||||||
|
|
||||||
|
**GET /exit**
|
||||||
|
|
||||||
|
Производит закрытия приложение с редиректом на страницу /exit-success (название вариативно) с надписью ‘приложение закрыто’ допускаются и другие варианты информирования о закрытие.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Комментарий к выполненной работе
|
||||||
|
|
||||||
|
Программу можно запустить в нескольких режимах используя профили spring boot
|
||||||
|
|
||||||
|
1. **DEFAULT** - в данном режиме используется база данных postgresql с настройками по умолчанию, а именно `url:jdbc:postgresql://localhost/test, username: test, password: test`. Для запуска используем следующие параметры `java -jar restsrv.jar`
|
||||||
|
1. **DEMO** - в данном режиме используется база данных H2 DB. Для запуска используем следующие параметры `java -jar restsrv.jar --spring.profiles.active=demo`
|
||||||
|
1. **PRODUCTION** - в данном режиме используется база данных postgresql c альтернативными настройками прописанными в файле `application-prod.properties`, данный файл должен находиться в том же каталоге где и запускаемый jar-файл программы. Для запуска используем следующие параметры `java -jar restsrv.jar --spring.profiles.active=prod`
|
||||||
|
|
||||||
|
Пример содержимого файла `application-prod.properties`
|
||||||
|
|
||||||
|
```
|
||||||
|
RESTSRV_PGSQL_DB_HOST=jdbc:postgresql://localhost
|
||||||
|
RESTSRV_PGSQL_DB_PORT=5432
|
||||||
|
RESTSRV_PGSQL_DB_NAME=test
|
||||||
|
RESTSRV_PGSQL_DB_USER=test
|
||||||
|
RESTSRV_PGSQL_DB_PASSWORD=test
|
||||||
|
```
|
||||||
|
|
||||||
|
Так же для запуска программы в linux, можно воспользоваться скриптом `restsrv_linux.sh` , при этом запускаемый jar-файл должен называться `restsrv.jar` и находиться в том же каталоге, где и скрипт. Выполните `restsrv_linux.sh --help` для получения помощи. При запуске в режиме `PRODUCTION` будет выполнена проверка на наличие файла `application-prod.properties`, если он не найден, то запустится интерактивный режим, где будет предложено заполнить необходимые данные.
|
||||||
|
|
||||||
|
## Работа с программой
|
||||||
|
|
||||||
|
### Инициализация БД
|
||||||
|
|
||||||
|
Если работа ведётся с postgresql воспользуйтесь файлами `ddl-postgresql.sql` и `schema-postgresql.sql` см. каталог `init_postgresql_db`
|
||||||
|
|
||||||
|
### Работа с токеном безопасности.
|
||||||
|
|
||||||
|
По условию задания, доступ к эндпоинтам сервиса осуществляется при помощи токена `secret` . В каждом звпросе, в заголовке запроса, должна присутствовать следующая строка `Authorization: Bearer secret` , без данной записи в заголовке, при обращении к защищенным эндпоинтам будет возвращаться код 401.
|
||||||
|
|
||||||
|
### Прочее
|
||||||
|
|
||||||
|
В программе используется OpenApi c ui, для доступа к ui используем http://localhost:8010/swagger-ui/index.html , в представлении json используем http://localhost:8010/v3/api-docs
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Тестовое задание выполнил
|
||||||
|
|
||||||
|
Александров А.А. (alexandrov@resprojects.ru)
|
||||||
|
|
||||||
|
ссылка на профиль hh.ru - https://hh.ru/resume/7cdada75ff015e78530039ed1f366c4b4a5273
|
||||||
322
mvnw
vendored
Executable file
322
mvnw
vendored
Executable file
@@ -0,0 +1,322 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
# or more contributor license agreements. See the NOTICE file
|
||||||
|
# distributed with this work for additional information
|
||||||
|
# regarding copyright ownership. The ASF licenses this file
|
||||||
|
# to you under the Apache License, Version 2.0 (the
|
||||||
|
# "License"); you may not use this file except in compliance
|
||||||
|
# with the License. You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing,
|
||||||
|
# software distributed under the License is distributed on an
|
||||||
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
# KIND, either express or implied. See the License for the
|
||||||
|
# specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Maven Start Up Batch script
|
||||||
|
#
|
||||||
|
# Required ENV vars:
|
||||||
|
# ------------------
|
||||||
|
# JAVA_HOME - location of a JDK home dir
|
||||||
|
#
|
||||||
|
# Optional ENV vars
|
||||||
|
# -----------------
|
||||||
|
# M2_HOME - location of maven2's installed home dir
|
||||||
|
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||||
|
# e.g. to debug Maven itself, use
|
||||||
|
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||||
|
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
if [ -z "$MAVEN_SKIP_RC" ]; then
|
||||||
|
|
||||||
|
if [ -f /etc/mavenrc ]; then
|
||||||
|
. /etc/mavenrc
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$HOME/.mavenrc" ]; then
|
||||||
|
. "$HOME/.mavenrc"
|
||||||
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
# OS specific support. $var _must_ be set to either true or false.
|
||||||
|
cygwin=false
|
||||||
|
darwin=false
|
||||||
|
mingw=false
|
||||||
|
case "$(uname)" in
|
||||||
|
CYGWIN*) cygwin=true ;;
|
||||||
|
MINGW*) mingw=true ;;
|
||||||
|
Darwin*)
|
||||||
|
darwin=true
|
||||||
|
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
|
||||||
|
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
|
||||||
|
if [ -z "$JAVA_HOME" ]; then
|
||||||
|
if [ -x "/usr/libexec/java_home" ]; then
|
||||||
|
export JAVA_HOME="$(/usr/libexec/java_home)"
|
||||||
|
else
|
||||||
|
export JAVA_HOME="/Library/Java/Home"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -z "$JAVA_HOME" ]; then
|
||||||
|
if [ -r /etc/gentoo-release ]; then
|
||||||
|
JAVA_HOME=$(java-config --jre-home)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$M2_HOME" ]; then
|
||||||
|
## resolve links - $0 may be a link to maven's home
|
||||||
|
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
|
||||||
|
|
||||||
|
saveddir=$(pwd)
|
||||||
|
|
||||||
|
M2_HOME=$(dirname "$PRG")/..
|
||||||
|
|
||||||
|
# make it fully qualified
|
||||||
|
M2_HOME=$(cd "$M2_HOME" && pwd)
|
||||||
|
|
||||||
|
cd "$saveddir"
|
||||||
|
# echo Using m2 at $M2_HOME
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Cygwin, ensure paths are in UNIX format before anything is touched
|
||||||
|
if $cygwin; then
|
||||||
|
[ -n "$M2_HOME" ] &&
|
||||||
|
M2_HOME=$(cygpath --unix "$M2_HOME")
|
||||||
|
[ -n "$JAVA_HOME" ] &&
|
||||||
|
JAVA_HOME=$(cygpath --unix "$JAVA_HOME")
|
||||||
|
[ -n "$CLASSPATH" ] &&
|
||||||
|
CLASSPATH=$(cygpath --path --unix "$CLASSPATH")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Mingw, ensure paths are in UNIX format before anything is touched
|
||||||
|
if $mingw; then
|
||||||
|
[ -n "$M2_HOME" ] &&
|
||||||
|
M2_HOME="$( (
|
||||||
|
cd "$M2_HOME"
|
||||||
|
pwd
|
||||||
|
))"
|
||||||
|
[ -n "$JAVA_HOME" ] &&
|
||||||
|
JAVA_HOME="$( (
|
||||||
|
cd "$JAVA_HOME"
|
||||||
|
pwd
|
||||||
|
))"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$JAVA_HOME" ]; then
|
||||||
|
javaExecutable="$(which javac)"
|
||||||
|
if [ -n "$javaExecutable" ] && ! [ "$(expr \"$javaExecutable\" : '\([^ ]*\)')" = "no" ]; then
|
||||||
|
# readlink(1) is not available as standard on Solaris 10.
|
||||||
|
readLink=$(which readlink)
|
||||||
|
if [ ! $(expr "$readLink" : '\([^ ]*\)') = "no" ]; then
|
||||||
|
if $darwin; then
|
||||||
|
javaHome="$(dirname \"$javaExecutable\")"
|
||||||
|
javaExecutable="$(cd \"$javaHome\" && pwd -P)/javac"
|
||||||
|
else
|
||||||
|
javaExecutable="$(readlink -f \"$javaExecutable\")"
|
||||||
|
fi
|
||||||
|
javaHome="$(dirname \"$javaExecutable\")"
|
||||||
|
javaHome=$(expr "$javaHome" : '\(.*\)/bin')
|
||||||
|
JAVA_HOME="$javaHome"
|
||||||
|
export JAVA_HOME
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$JAVACMD" ]; then
|
||||||
|
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
|
||||||
|
else
|
||||||
|
JAVACMD="$(which java)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -x "$JAVACMD" ]; then
|
||||||
|
echo "Error: JAVA_HOME is not defined correctly." >&2
|
||||||
|
echo " We cannot execute $JAVACMD" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$JAVA_HOME" ]; then
|
||||||
|
echo "Warning: JAVA_HOME environment variable is not set."
|
||||||
|
fi
|
||||||
|
|
||||||
|
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
|
||||||
|
|
||||||
|
# traverses directory structure from process work directory to filesystem root
|
||||||
|
# first directory with .mvn subdirectory is considered project base directory
|
||||||
|
find_maven_basedir() {
|
||||||
|
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
echo "Path not specified to find_maven_basedir"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
basedir="$1"
|
||||||
|
wdir="$1"
|
||||||
|
while [ "$wdir" != '/' ]; do
|
||||||
|
if [ -d "$wdir"/.mvn ]; then
|
||||||
|
basedir=$wdir
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
|
||||||
|
if [ -d "${wdir}" ]; then
|
||||||
|
wdir=$(
|
||||||
|
cd "$wdir/.."
|
||||||
|
pwd
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
# end of workaround
|
||||||
|
done
|
||||||
|
echo "${basedir}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# concatenates all lines of a file
|
||||||
|
concat_lines() {
|
||||||
|
if [ -f "$1" ]; then
|
||||||
|
echo "$(tr -s '\n' ' ' <"$1")"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
BASE_DIR=$(find_maven_basedir "$(pwd)")
|
||||||
|
if [ -z "$BASE_DIR" ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
##########################################################################################
|
||||||
|
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||||
|
# This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||||
|
##########################################################################################
|
||||||
|
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo "Found .mvn/wrapper/maven-wrapper.jar"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
|
||||||
|
fi
|
||||||
|
if [ -n "$MVNW_REPOURL" ]; then
|
||||||
|
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
|
||||||
|
else
|
||||||
|
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
|
||||||
|
fi
|
||||||
|
while IFS="=" read key value; do
|
||||||
|
case "$key" in wrapperUrl)
|
||||||
|
jarUrl="$value"
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done <"$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo "Downloading from: $jarUrl"
|
||||||
|
fi
|
||||||
|
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
|
||||||
|
if $cygwin; then
|
||||||
|
wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v wget >/dev/null; then
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo "Found wget ... using wget"
|
||||||
|
fi
|
||||||
|
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||||
|
wget "$jarUrl" -O "$wrapperJarPath"
|
||||||
|
else
|
||||||
|
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
|
||||||
|
fi
|
||||||
|
elif command -v curl >/dev/null; then
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo "Found curl ... using curl"
|
||||||
|
fi
|
||||||
|
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||||
|
curl -o "$wrapperJarPath" "$jarUrl" -f
|
||||||
|
else
|
||||||
|
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
|
||||||
|
fi
|
||||||
|
|
||||||
|
else
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo "Falling back to using Java to download"
|
||||||
|
fi
|
||||||
|
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
|
||||||
|
# For Cygwin, switch paths to Windows format before running javac
|
||||||
|
if $cygwin; then
|
||||||
|
javaClass=$(cygpath --path --windows "$javaClass")
|
||||||
|
fi
|
||||||
|
if [ -e "$javaClass" ]; then
|
||||||
|
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo " - Compiling MavenWrapperDownloader.java ..."
|
||||||
|
fi
|
||||||
|
# Compiling the Java class
|
||||||
|
("$JAVA_HOME/bin/javac" "$javaClass")
|
||||||
|
fi
|
||||||
|
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||||
|
# Running the downloader
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo " - Running MavenWrapperDownloader.java ..."
|
||||||
|
fi
|
||||||
|
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
##########################################################################################
|
||||||
|
# End of extension
|
||||||
|
##########################################################################################
|
||||||
|
|
||||||
|
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
|
||||||
|
if [ "$MVNW_VERBOSE" = true ]; then
|
||||||
|
echo $MAVEN_PROJECTBASEDIR
|
||||||
|
fi
|
||||||
|
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||||
|
|
||||||
|
# For Cygwin, switch paths to Windows format before running java
|
||||||
|
if $cygwin; then
|
||||||
|
[ -n "$M2_HOME" ] &&
|
||||||
|
M2_HOME=$(cygpath --path --windows "$M2_HOME")
|
||||||
|
[ -n "$JAVA_HOME" ] &&
|
||||||
|
JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME")
|
||||||
|
[ -n "$CLASSPATH" ] &&
|
||||||
|
CLASSPATH=$(cygpath --path --windows "$CLASSPATH")
|
||||||
|
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
|
||||||
|
MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Provide a "standardized" way to retrieve the CLI args that will
|
||||||
|
# work with both Windows and non-Windows executions.
|
||||||
|
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
|
||||||
|
export MAVEN_CMD_LINE_ARGS
|
||||||
|
|
||||||
|
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||||
|
|
||||||
|
exec "$JAVACMD" \
|
||||||
|
$MAVEN_OPTS \
|
||||||
|
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||||
|
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||||
|
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
|
||||||
182
mvnw.cmd
vendored
Normal file
182
mvnw.cmd
vendored
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
@REM or more contributor license agreements. See the NOTICE file
|
||||||
|
@REM distributed with this work for additional information
|
||||||
|
@REM regarding copyright ownership. The ASF licenses this file
|
||||||
|
@REM to you under the Apache License, Version 2.0 (the
|
||||||
|
@REM "License"); you may not use this file except in compliance
|
||||||
|
@REM with the License. You may obtain a copy of the License at
|
||||||
|
@REM
|
||||||
|
@REM https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@REM
|
||||||
|
@REM Unless required by applicable law or agreed to in writing,
|
||||||
|
@REM software distributed under the License is distributed on an
|
||||||
|
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
@REM KIND, either express or implied. See the License for the
|
||||||
|
@REM specific language governing permissions and limitations
|
||||||
|
@REM under the License.
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
@REM Maven Start Up Batch script
|
||||||
|
@REM
|
||||||
|
@REM Required ENV vars:
|
||||||
|
@REM JAVA_HOME - location of a JDK home dir
|
||||||
|
@REM
|
||||||
|
@REM Optional ENV vars
|
||||||
|
@REM M2_HOME - location of maven2's installed home dir
|
||||||
|
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
|
||||||
|
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
|
||||||
|
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||||
|
@REM e.g. to debug Maven itself, use
|
||||||
|
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||||
|
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
|
||||||
|
@echo off
|
||||||
|
@REM set title of command window
|
||||||
|
title %0
|
||||||
|
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
|
||||||
|
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
|
||||||
|
|
||||||
|
@REM set %HOME% to equivalent of $HOME
|
||||||
|
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
|
||||||
|
|
||||||
|
@REM Execute a user defined script before this one
|
||||||
|
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
|
||||||
|
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
|
||||||
|
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
|
||||||
|
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
|
||||||
|
:skipRcPre
|
||||||
|
|
||||||
|
@setlocal
|
||||||
|
|
||||||
|
set ERROR_CODE=0
|
||||||
|
|
||||||
|
@REM To isolate internal variables from possible post scripts, we use another setlocal
|
||||||
|
@setlocal
|
||||||
|
|
||||||
|
@REM ==== START VALIDATION ====
|
||||||
|
if not "%JAVA_HOME%" == "" goto OkJHome
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo Error: JAVA_HOME not found in your environment. >&2
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||||
|
echo location of your Java installation. >&2
|
||||||
|
echo.
|
||||||
|
goto error
|
||||||
|
|
||||||
|
:OkJHome
|
||||||
|
if exist "%JAVA_HOME%\bin\java.exe" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo Error: JAVA_HOME is set to an invalid directory. >&2
|
||||||
|
echo JAVA_HOME = "%JAVA_HOME%" >&2
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||||
|
echo location of your Java installation. >&2
|
||||||
|
echo.
|
||||||
|
goto error
|
||||||
|
|
||||||
|
@REM ==== END VALIDATION ====
|
||||||
|
|
||||||
|
:init
|
||||||
|
|
||||||
|
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
|
||||||
|
@REM Fallback to current working directory if not found.
|
||||||
|
|
||||||
|
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
|
||||||
|
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
|
||||||
|
|
||||||
|
set EXEC_DIR=%CD%
|
||||||
|
set WDIR=%EXEC_DIR%
|
||||||
|
:findBaseDir
|
||||||
|
IF EXIST "%WDIR%"\.mvn goto baseDirFound
|
||||||
|
cd ..
|
||||||
|
IF "%WDIR%"=="%CD%" goto baseDirNotFound
|
||||||
|
set WDIR=%CD%
|
||||||
|
goto findBaseDir
|
||||||
|
|
||||||
|
:baseDirFound
|
||||||
|
set MAVEN_PROJECTBASEDIR=%WDIR%
|
||||||
|
cd "%EXEC_DIR%"
|
||||||
|
goto endDetectBaseDir
|
||||||
|
|
||||||
|
:baseDirNotFound
|
||||||
|
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
|
||||||
|
cd "%EXEC_DIR%"
|
||||||
|
|
||||||
|
:endDetectBaseDir
|
||||||
|
|
||||||
|
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
|
||||||
|
|
||||||
|
@setlocal EnableExtensions EnableDelayedExpansion
|
||||||
|
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
|
||||||
|
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
|
||||||
|
|
||||||
|
:endReadAdditionalConfig
|
||||||
|
|
||||||
|
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
||||||
|
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
|
||||||
|
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||||
|
|
||||||
|
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
|
||||||
|
|
||||||
|
FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
|
||||||
|
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
|
||||||
|
)
|
||||||
|
|
||||||
|
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||||
|
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||||
|
if exist %WRAPPER_JAR% (
|
||||||
|
if "%MVNW_VERBOSE%" == "true" (
|
||||||
|
echo Found %WRAPPER_JAR%
|
||||||
|
)
|
||||||
|
) else (
|
||||||
|
if not "%MVNW_REPOURL%" == "" (
|
||||||
|
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
|
||||||
|
)
|
||||||
|
if "%MVNW_VERBOSE%" == "true" (
|
||||||
|
echo Couldn't find %WRAPPER_JAR%, downloading it ...
|
||||||
|
echo Downloading from: %DOWNLOAD_URL%
|
||||||
|
)
|
||||||
|
|
||||||
|
powershell -Command "&{"^
|
||||||
|
"$webclient = new-object System.Net.WebClient;"^
|
||||||
|
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
|
||||||
|
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
|
||||||
|
"}"^
|
||||||
|
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
|
||||||
|
"}"
|
||||||
|
if "%MVNW_VERBOSE%" == "true" (
|
||||||
|
echo Finished downloading %WRAPPER_JAR%
|
||||||
|
)
|
||||||
|
)
|
||||||
|
@REM End of extension
|
||||||
|
|
||||||
|
@REM Provide a "standardized" way to retrieve the CLI args that will
|
||||||
|
@REM work with both Windows and non-Windows executions.
|
||||||
|
set MAVEN_CMD_LINE_ARGS=%*
|
||||||
|
|
||||||
|
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
|
||||||
|
if ERRORLEVEL 1 goto error
|
||||||
|
goto end
|
||||||
|
|
||||||
|
:error
|
||||||
|
set ERROR_CODE=1
|
||||||
|
|
||||||
|
:end
|
||||||
|
@endlocal & set ERROR_CODE=%ERROR_CODE%
|
||||||
|
|
||||||
|
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
|
||||||
|
@REM check for post script, once with legacy .bat ending and once with .cmd ending
|
||||||
|
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
|
||||||
|
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
|
||||||
|
:skipRcPost
|
||||||
|
|
||||||
|
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
|
||||||
|
if "%MAVEN_BATCH_PAUSE%" == "on" pause
|
||||||
|
|
||||||
|
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
|
||||||
|
|
||||||
|
exit /B %ERROR_CODE%
|
||||||
93
pom.xml
Normal file
93
pom.xml
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>2.3.3.RELEASE</version>
|
||||||
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
|
</parent>
|
||||||
|
<groupId>ru.resprojects</groupId>
|
||||||
|
<artifactId>restsrv</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<name>restsrv</name>
|
||||||
|
<description>Test task project for Mesh group</description>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<java.version>11</java.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-security</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Databases-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.postgresql</groupId>
|
||||||
|
<artifactId>postgresql</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.h2database</groupId>
|
||||||
|
<artifactId>h2</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hibernate.validator</groupId>
|
||||||
|
<artifactId>hibernate-validator</artifactId>
|
||||||
|
<version>6.1.5.Final</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- OpenApi -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springdoc</groupId>
|
||||||
|
<artifactId>springdoc-openapi-ui</artifactId>
|
||||||
|
<version>1.4.4</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springdoc</groupId>
|
||||||
|
<artifactId>springdoc-openapi-security</artifactId>
|
||||||
|
<version>1.4.4</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<finalName>restsrv</finalName>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
101
restsrv_linux.sh
Executable file
101
restsrv_linux.sh
Executable file
@@ -0,0 +1,101 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
EXECUTABLE_FILE=restsrv.jar
|
||||||
|
PROPERTIES_FILE=application-prod.properties
|
||||||
|
|
||||||
|
HELP="Usage: restsrv_linux [KEY]
|
||||||
|
|
||||||
|
Script without key is run program in DEFAULT mode.
|
||||||
|
|
||||||
|
DEFAULT mode uses postgresql with next parameters:
|
||||||
|
|
||||||
|
url: jdbc:postgresql://localhost/test
|
||||||
|
username: test
|
||||||
|
password: test
|
||||||
|
|
||||||
|
Also available next switches:
|
||||||
|
|
||||||
|
--prod - running program in PRODUCTION mode. For running in this mode needed additional
|
||||||
|
file application-prod.properties with PostgreSQL dataset information.
|
||||||
|
|
||||||
|
--demo - running program in DEMO mode. In this mode uses H2 database (in-memory) instead postgresql.
|
||||||
|
|
||||||
|
--help - display this is message
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
restsrv_linux - run program in DEFAULT mode
|
||||||
|
|
||||||
|
restsrv_linux --demo - run program in DEMO mode.
|
||||||
|
|
||||||
|
restsrv_linux --prod - run program in PRODUCTION mode.
|
||||||
|
"
|
||||||
|
|
||||||
|
PROPERTIES_FILE_NOT_FOUND="
|
||||||
|
WARNING!
|
||||||
|
|
||||||
|
You try run program in PRODUCTION mode. For this mode need PostgreSQL but file
|
||||||
|
$PROPERTIES_FILE with dataset information is not found. Please fill next information and run program again!
|
||||||
|
|
||||||
|
"
|
||||||
|
|
||||||
|
if [ -f "$EXECUTABLE_FILE" ]; then
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
echo "Running program in DEFAULT mode"
|
||||||
|
java -jar "$EXECUTABLE_FILE"
|
||||||
|
else
|
||||||
|
case "$1" in
|
||||||
|
--help)
|
||||||
|
echo "$HELP"
|
||||||
|
;;
|
||||||
|
--demo)
|
||||||
|
echo "Running program in DEMO mode with H2 DB (in-memory)"
|
||||||
|
java -jar "$EXECUTABLE_FILE" --spring.profiles.active=demo
|
||||||
|
;;
|
||||||
|
--prod)
|
||||||
|
if [ -f "$PROPERTIES_FILE" ]; then
|
||||||
|
echo "Running program in PRODUCTION mode with PostgreSQL DB"
|
||||||
|
java -jar "$EXECUTABLE_FILE" --spring.profiles.active=prod
|
||||||
|
else
|
||||||
|
echo "$PROPERTIES_FILE_NOT_FOUND"
|
||||||
|
printf 'PostgreSQL database host name or IP address (default localhost): '
|
||||||
|
read -r RESTSRV_PGSQL_DB_HOST
|
||||||
|
if [ -z "$RESTSRV_PGSQL_DB_HOST" ]; then
|
||||||
|
RESTSRV_PGSQL_DB_HOST="jdbc:postgresql://localhost"
|
||||||
|
else
|
||||||
|
RESTSRV_PGSQL_DB_HOST="jdbc:postgresql://$RESTSRV_PGSQL_DB_HOST"
|
||||||
|
fi
|
||||||
|
printf 'PostgreSQL database port (default 5432): '
|
||||||
|
read -r RESTSRV_PGSQL_DB_PORT
|
||||||
|
if [ -z "$RESTSRV_PGSQL_DB_PORT" ]; then
|
||||||
|
RESTSRV_PGSQL_DB_PORT=5432
|
||||||
|
fi
|
||||||
|
printf 'PostgreSQL database name (default test): '
|
||||||
|
read -r RESTSRV_PGSQL_DB_NAME
|
||||||
|
if [ -z "$RESTSRV_PGSQL_DB_NAME" ]; then
|
||||||
|
RESTSRV_PGSQL_DB_NAME="test"
|
||||||
|
fi
|
||||||
|
printf 'PostgreSQL database user name: '
|
||||||
|
read -r RESTSRV_PGSQL_DB_USER
|
||||||
|
printf 'PostgreSQL database password: '
|
||||||
|
read -r -s RESTSRV_PGSQL_DB_PASSWORD
|
||||||
|
echo
|
||||||
|
touch "$PROPERTIES_FILE"
|
||||||
|
{
|
||||||
|
echo "RESTSRV_PGSQL_DB_HOST=$RESTSRV_PGSQL_DB_HOST"
|
||||||
|
echo "RESTSRV_PGSQL_DB_PORT=$RESTSRV_PGSQL_DB_PORT"
|
||||||
|
echo "RESTSRV_PGSQL_DB_NAME=$RESTSRV_PGSQL_DB_NAME"
|
||||||
|
echo "RESTSRV_PGSQL_DB_USER=$RESTSRV_PGSQL_DB_USER"
|
||||||
|
echo "RESTSRV_PGSQL_DB_PASSWORD=$RESTSRV_PGSQL_DB_PASSWORD"
|
||||||
|
} > "$PROPERTIES_FILE"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "restsrv_linux: unknown option $1"
|
||||||
|
echo "Try 'restsrv_linux --help' for more information."
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Executable file restsrv.jar is not found!"
|
||||||
|
fi
|
||||||
13
src/main/java/ru/resprojects/restsrv/RestsrvApplication.java
Normal file
13
src/main/java/ru/resprojects/restsrv/RestsrvApplication.java
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package ru.resprojects.restsrv;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class RestsrvApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(RestsrvApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
17
src/main/java/ru/resprojects/restsrv/config/AppConfig.java
Normal file
17
src/main/java/ru/resprojects/restsrv/config/AppConfig.java
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package ru.resprojects.restsrv.config;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import ru.resprojects.restsrv.token.TokenResourceDetails;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class AppConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConfigurationProperties("auth")
|
||||||
|
public TokenResourceDetails tokenResourceDetails() {
|
||||||
|
return new TokenResourceDetails();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package ru.resprojects.restsrv.config;
|
||||||
|
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class TokenAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 7782026919358529193L;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void commence(HttpServletRequest request, HttpServletResponse response,
|
||||||
|
AuthenticationException authException) throws IOException, ServletException {
|
||||||
|
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package ru.resprojects.restsrv.config;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
import ru.resprojects.restsrv.service.AuthDetailsService;
|
||||||
|
import ru.resprojects.restsrv.token.TokenResourceDetails;
|
||||||
|
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class TokenRequestsFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
|
public static final String SECURITY_SCHEME = "Bearer";
|
||||||
|
private final AuthDetailsService authDetailsService;
|
||||||
|
private final TokenResourceDetails tokenResourceDetails;
|
||||||
|
|
||||||
|
public TokenRequestsFilter(AuthDetailsService authDetailsService, TokenResourceDetails tokenResourceDetails) {
|
||||||
|
this.authDetailsService = authDetailsService;
|
||||||
|
this.tokenResourceDetails = tokenResourceDetails;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(HttpServletRequest request,
|
||||||
|
HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||||
|
final String requestHeader = request.getHeader("Authorization");
|
||||||
|
String token = null;
|
||||||
|
if (requestHeader != null && requestHeader.startsWith(SECURITY_SCHEME + " ")) {
|
||||||
|
token = requestHeader.substring(SECURITY_SCHEME.length() + 1);
|
||||||
|
}
|
||||||
|
if (token != null && SecurityContextHolder.getContext().getAuthentication() == null) {
|
||||||
|
UserDetails userDetails = authDetailsService.loadUserByUsername(tokenResourceDetails.getUserByToken(token));
|
||||||
|
UsernamePasswordAuthenticationToken usernameAuthToken = new UsernamePasswordAuthenticationToken(
|
||||||
|
userDetails, null, userDetails.getAuthorities());
|
||||||
|
usernameAuthToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(usernameAuthToken);
|
||||||
|
}
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package ru.resprojects.restsrv.config;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||||
|
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||||
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
|
import ru.resprojects.restsrv.service.AuthDetailsService;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
|
||||||
|
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
|
private static final String[] AUTH_WHITELIST = {
|
||||||
|
// swagger ui
|
||||||
|
"/v3/api-docs/**",
|
||||||
|
"/swagger-ui.html",
|
||||||
|
"/swagger-ui/**"
|
||||||
|
};
|
||||||
|
|
||||||
|
private final TokenRequestsFilter tokenRequestsFilter;
|
||||||
|
private final AuthDetailsService authDetailsService;
|
||||||
|
private final TokenAuthenticationEntryPoint tokenAuthenticationEntryPoint;
|
||||||
|
|
||||||
|
public WebSecurityConfig(
|
||||||
|
TokenRequestsFilter tokenRequestsFilter,
|
||||||
|
AuthDetailsService authDetailsService, TokenAuthenticationEntryPoint tokenAuthenticationEntryPoint) {
|
||||||
|
this.tokenRequestsFilter = tokenRequestsFilter;
|
||||||
|
this.authDetailsService = authDetailsService;
|
||||||
|
this.tokenAuthenticationEntryPoint = tokenAuthenticationEntryPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
|
||||||
|
auth.userDetailsService(authDetailsService).passwordEncoder(passwordEncoder());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public PasswordEncoder passwordEncoder() {
|
||||||
|
return new BCryptPasswordEncoder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Override
|
||||||
|
public AuthenticationManager authenticationManagerBean() throws Exception {
|
||||||
|
return super.authenticationManagerBean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
|
http.cors().and().csrf().disable()
|
||||||
|
.authorizeRequests()
|
||||||
|
.antMatchers(AUTH_WHITELIST)
|
||||||
|
.permitAll()
|
||||||
|
.antMatchers("/**")
|
||||||
|
.authenticated()
|
||||||
|
.and()
|
||||||
|
.exceptionHandling().authenticationEntryPoint(tokenAuthenticationEntryPoint)
|
||||||
|
.and()
|
||||||
|
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
|
||||||
|
http.addFilterBefore(tokenRequestsFilter, UsernamePasswordAuthenticationFilter.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package ru.resprojects.restsrv.controller;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.enums.SecuritySchemeIn;
|
||||||
|
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Content;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
|
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||||
|
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||||
|
import io.swagger.v3.oas.annotations.security.SecurityScheme;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import ru.resprojects.restsrv.exception.LastException;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/error")
|
||||||
|
@Schema(name = "/error")
|
||||||
|
@Tag(name ="Profiles", description = "the profiles API with documentation annotations")
|
||||||
|
@SecurityScheme(
|
||||||
|
name = "customTokenAuth",
|
||||||
|
type = SecuritySchemeType.HTTP,
|
||||||
|
in = SecuritySchemeIn.HEADER,
|
||||||
|
scheme = "bearer",
|
||||||
|
description = "Авторизация при помощи токена доступа. В HEADER запроса должна присутствовать строка вида Authorization: Bearer "
|
||||||
|
)
|
||||||
|
public class ErrorController {
|
||||||
|
|
||||||
|
@Operation(
|
||||||
|
summary = "Получить последнюю ошибку",
|
||||||
|
description = "Возвращает информацию о последней ошибке.",
|
||||||
|
security = @SecurityRequirement(name = "customTokenAuth"),
|
||||||
|
tags = { "profile" }
|
||||||
|
)
|
||||||
|
@ApiResponses(value = {
|
||||||
|
@ApiResponse(
|
||||||
|
responseCode = "200",
|
||||||
|
description = "успешная операция",
|
||||||
|
content = @Content(schema = @Schema(implementation = LastException.class), mediaType = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
@GetMapping(value = "/last", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
public ResponseEntity<LastException> getLastException() {
|
||||||
|
return ResponseEntity.ok(RestExceptionHandler.getLastException());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
package ru.resprojects.restsrv.controller;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.enums.SecuritySchemeIn;
|
||||||
|
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
|
||||||
|
import io.swagger.v3.oas.annotations.media.ArraySchema;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Content;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
|
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||||
|
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||||
|
import io.swagger.v3.oas.annotations.security.SecurityScheme;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import ru.resprojects.restsrv.dto.ProfileDto;
|
||||||
|
import ru.resprojects.restsrv.dto.ProfileIdDto;
|
||||||
|
import ru.resprojects.restsrv.dto.EmailDto;
|
||||||
|
import ru.resprojects.restsrv.exception.ErrorMessage;
|
||||||
|
import ru.resprojects.restsrv.model.Profile;
|
||||||
|
import ru.resprojects.restsrv.service.ProfileService;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/profiles")
|
||||||
|
@Schema(name = "/profiles")
|
||||||
|
@Tag(name ="Profiles", description = "the profiles API with documentation annotations")
|
||||||
|
@SecurityScheme(
|
||||||
|
name = "customTokenAuth",
|
||||||
|
type = SecuritySchemeType.HTTP,
|
||||||
|
in = SecuritySchemeIn.HEADER,
|
||||||
|
scheme = "bearer",
|
||||||
|
description = "Авторизация при помощи токена доступа. В HEADER запроса должна присутствовать строка вида Authorization: Bearer "
|
||||||
|
)
|
||||||
|
public class ProfileController {
|
||||||
|
|
||||||
|
private final ProfileService profileService;
|
||||||
|
|
||||||
|
public ProfileController(ProfileService profileService) {
|
||||||
|
this.profileService = profileService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(
|
||||||
|
summary = "Получить список профилей",
|
||||||
|
description = "Возвращает все созданные профили",
|
||||||
|
security = @SecurityRequirement(name = "customTokenAuth"),
|
||||||
|
tags = { "profile" }
|
||||||
|
)
|
||||||
|
@ApiResponses(value = {
|
||||||
|
@ApiResponse(
|
||||||
|
responseCode = "200",
|
||||||
|
description = "успешная операция",
|
||||||
|
content = @Content(
|
||||||
|
array = @ArraySchema(schema = @Schema(implementation = Profile.class)),
|
||||||
|
mediaType = MediaType.APPLICATION_JSON_VALUE
|
||||||
|
)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
public ResponseEntity<List<Profile>> finaAll() {
|
||||||
|
return ResponseEntity.ok(profileService.findAll());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(
|
||||||
|
summary = "Поиск профиля по ID",
|
||||||
|
description = "Возвращает профиль с заданным ID",
|
||||||
|
security = @SecurityRequirement(name = "customTokenAuth"),
|
||||||
|
tags = { "profile" }
|
||||||
|
)
|
||||||
|
@ApiResponses(value = {
|
||||||
|
@ApiResponse(responseCode = "200", description = "Успешная операция",
|
||||||
|
content = @Content(schema = @Schema(implementation = Profile.class), mediaType = MediaType.APPLICATION_JSON_VALUE)),
|
||||||
|
@ApiResponse(responseCode = "404", description = "Профиль не найден",
|
||||||
|
content = @Content(schema = @Schema(implementation = ErrorMessage.class), mediaType = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
) })
|
||||||
|
@GetMapping(value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
public ResponseEntity<Profile> findById(
|
||||||
|
@Parameter(description="Id профиля.", required=true)
|
||||||
|
@PathVariable("id") Integer id) {
|
||||||
|
Profile profile = profileService.findById(id);
|
||||||
|
return ResponseEntity.ok(profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(
|
||||||
|
summary = "Поиск профиля по email",
|
||||||
|
description = "Возвращает профиль по указанному email",
|
||||||
|
security = @SecurityRequirement(name = "customTokenAuth"),
|
||||||
|
tags = { "profile" }
|
||||||
|
)
|
||||||
|
@ApiResponses(value = {
|
||||||
|
@ApiResponse(responseCode = "200", description = "Успешная операция",
|
||||||
|
content = @Content(schema = @Schema(implementation = Profile.class), mediaType = MediaType.APPLICATION_JSON_VALUE)),
|
||||||
|
@ApiResponse(responseCode = "404", description = "Профиль не найден",
|
||||||
|
content = @Content(schema = @Schema(implementation = ErrorMessage.class), mediaType = MediaType.APPLICATION_JSON_VALUE))
|
||||||
|
})
|
||||||
|
@PostMapping(value = "/get", consumes = {MediaType.APPLICATION_JSON_VALUE})
|
||||||
|
public ResponseEntity<Profile> findByEmail(
|
||||||
|
@Parameter(description="Email по которому необходимо произвести поиск.",
|
||||||
|
required=true, schema=@Schema(implementation = EmailDto.class))
|
||||||
|
@RequestBody EmailDto emailDto) {
|
||||||
|
Profile profile = profileService.findByEmail(emailDto.getEmail());
|
||||||
|
return ResponseEntity.ok(profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(
|
||||||
|
summary = "Получить последний созданный профиль",
|
||||||
|
description = "Возвращает последний созданный профиль",
|
||||||
|
security = @SecurityRequirement(name = "customTokenAuth"),
|
||||||
|
tags = { "profile" }
|
||||||
|
)
|
||||||
|
@ApiResponses(value = {
|
||||||
|
@ApiResponse(
|
||||||
|
responseCode = "200",
|
||||||
|
description = "успешная операция",
|
||||||
|
content = @Content(schema = @Schema(implementation = Profile.class), mediaType = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
@GetMapping(value = "/last", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
public ResponseEntity<Profile> getLastProfile() {
|
||||||
|
Profile profile = profileService.getLastCreatedProfile();
|
||||||
|
return ResponseEntity.ok(profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(
|
||||||
|
summary = "Создание нового профиля",
|
||||||
|
description = "Создает профиль и возвращается его id",
|
||||||
|
security = @SecurityRequirement(name = "customTokenAuth"),
|
||||||
|
tags = { "profile" }
|
||||||
|
)
|
||||||
|
@ApiResponses(value = {
|
||||||
|
@ApiResponse(responseCode = "200", description = "Успешная операция",
|
||||||
|
content = @Content(schema = @Schema(implementation = ProfileIdDto.class), mediaType = MediaType.APPLICATION_JSON_VALUE)),
|
||||||
|
@ApiResponse(responseCode = "400", description = "Передан некорректный email добавляемого профиля",
|
||||||
|
content = @Content(schema = @Schema(implementation = ErrorMessage.class), mediaType = MediaType.APPLICATION_JSON_VALUE)),
|
||||||
|
@ApiResponse(responseCode = "403", description = "Email добавляемого профиля уже существует",
|
||||||
|
content = @Content(schema = @Schema(implementation = ErrorMessage.class), mediaType = MediaType.APPLICATION_JSON_VALUE))
|
||||||
|
})
|
||||||
|
@PostMapping(value = "/set", consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
public ResponseEntity<ProfileIdDto> save(
|
||||||
|
@Parameter(description="Данные нового профиля",
|
||||||
|
required=true, schema=@Schema(implementation = ProfileDto.class))
|
||||||
|
@RequestBody ProfileDto profileDto) {
|
||||||
|
Profile profile = new Profile();
|
||||||
|
profile.setName(profileDto.getName());
|
||||||
|
profile.setAge(profileDto.getAge());
|
||||||
|
profile.setEmail(profileDto.getEmail());
|
||||||
|
Profile newProfile = profileService.save(profile);
|
||||||
|
ProfileIdDto profileIdDto = new ProfileIdDto(newProfile.getId());
|
||||||
|
return ResponseEntity.ok(profileIdDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package ru.resprojects.restsrv.controller;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
import ru.resprojects.restsrv.exception.BadResourceException;
|
||||||
|
import ru.resprojects.restsrv.exception.ErrorMessage;
|
||||||
|
import ru.resprojects.restsrv.exception.LastException;
|
||||||
|
import ru.resprojects.restsrv.exception.ResourceAlreadyExistsException;
|
||||||
|
import ru.resprojects.restsrv.exception.ResourceNotFoundException;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
|
||||||
|
@RestControllerAdvice
|
||||||
|
public class RestExceptionHandler {
|
||||||
|
|
||||||
|
private static LastException lastException;
|
||||||
|
|
||||||
|
@ExceptionHandler(value = {ResourceNotFoundException.class})
|
||||||
|
public ResponseEntity<ErrorMessage> resourceNotFound(HttpServletRequest request, ResourceNotFoundException exception) {
|
||||||
|
setLastException(exception.getErrorMessage());
|
||||||
|
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(exception.getErrorMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(value = {BadResourceException.class})
|
||||||
|
public ResponseEntity<ErrorMessage> badResource(HttpServletRequest request, BadResourceException exception) {
|
||||||
|
setLastException(exception.getErrorMessage());
|
||||||
|
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(exception.getErrorMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(value = {ResourceAlreadyExistsException.class})
|
||||||
|
public ResponseEntity<ErrorMessage> alreadyExistResource(HttpServletRequest request, ResourceAlreadyExistsException exception) {
|
||||||
|
setLastException(exception.getErrorMessage());
|
||||||
|
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(exception.getErrorMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setLastException(ErrorMessage errorMessage) {
|
||||||
|
lastException = new LastException(errorMessage.getMessage(), new Timestamp(System.currentTimeMillis()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LastException getLastException() {
|
||||||
|
return lastException;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
20
src/main/java/ru/resprojects/restsrv/dto/EmailDto.java
Normal file
20
src/main/java/ru/resprojects/restsrv/dto/EmailDto.java
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package ru.resprojects.restsrv.dto;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class EmailDto implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -5708728999488347598L;
|
||||||
|
|
||||||
|
@Schema(description = "Email для поиска профиля")
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
public EmailDto() {
|
||||||
|
}
|
||||||
|
}
|
||||||
33
src/main/java/ru/resprojects/restsrv/dto/ProfileDto.java
Normal file
33
src/main/java/ru/resprojects/restsrv/dto/ProfileDto.java
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package ru.resprojects.restsrv.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class ProfileDto implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 8315646868618789737L;
|
||||||
|
|
||||||
|
@Schema(description = "Имя пользователя",
|
||||||
|
example = "Alex", required = false)
|
||||||
|
@JsonProperty("name")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Schema(description = "E-mail пользователя",
|
||||||
|
example = "user@example.com", required = true)
|
||||||
|
@JsonProperty("email")
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@Schema(description = "Возраст пользователя",
|
||||||
|
example = "30", required = false)
|
||||||
|
@JsonProperty("age")
|
||||||
|
private Integer age;
|
||||||
|
|
||||||
|
public ProfileDto() {
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/main/java/ru/resprojects/restsrv/dto/ProfileIdDto.java
Normal file
24
src/main/java/ru/resprojects/restsrv/dto/ProfileIdDto.java
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package ru.resprojects.restsrv.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ProfileIdDto implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -7924116702230840180L;
|
||||||
|
|
||||||
|
@Schema(description = "ID созданного профиля")
|
||||||
|
@JsonProperty("idUser")
|
||||||
|
private Integer userId;
|
||||||
|
|
||||||
|
public ProfileIdDto() {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package ru.resprojects.restsrv.exception;
|
||||||
|
|
||||||
|
public class BadResourceException extends RuntimeException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 5658497082104293714L;
|
||||||
|
|
||||||
|
public BadResourceException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public BadResourceException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ErrorMessage getErrorMessage() {
|
||||||
|
return new ErrorMessage(this.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package ru.resprojects.restsrv.exception;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ErrorMessage implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -814379271893846783L;
|
||||||
|
|
||||||
|
@Schema(description = "Сообщение о ошибке")
|
||||||
|
@JsonProperty("msg")
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
public ErrorMessage() {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package ru.resprojects.restsrv.exception;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class LastException implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -1153271692647620929L;
|
||||||
|
|
||||||
|
@Schema(description = "Сообщение о ошибки")
|
||||||
|
@JsonProperty("msg")
|
||||||
|
private String message;
|
||||||
|
@Schema(description = "Дата и время возникновения ошибки")
|
||||||
|
@JsonProperty("created")
|
||||||
|
private Timestamp created;
|
||||||
|
|
||||||
|
public LastException() {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package ru.resprojects.restsrv.exception;
|
||||||
|
|
||||||
|
public class ResourceAlreadyExistsException extends RuntimeException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -2318810158739700082L;
|
||||||
|
|
||||||
|
public ResourceAlreadyExistsException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceAlreadyExistsException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ErrorMessage getErrorMessage() {
|
||||||
|
return new ErrorMessage(this.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package ru.resprojects.restsrv.exception;
|
||||||
|
|
||||||
|
public class ResourceNotFoundException extends RuntimeException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -4368442279968350909L;
|
||||||
|
|
||||||
|
public ResourceNotFoundException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceNotFoundException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ErrorMessage getErrorMessage() {
|
||||||
|
return new ErrorMessage(this.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
79
src/main/java/ru/resprojects/restsrv/model/Profile.java
Normal file
79
src/main/java/ru/resprojects/restsrv/model/Profile.java
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
package ru.resprojects.restsrv.model;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import org.hibernate.annotations.Cache;
|
||||||
|
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.PrePersist;
|
||||||
|
import javax.persistence.SequenceGenerator;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "profile")
|
||||||
|
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
public class Profile implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 4048798961366546485L;
|
||||||
|
private static final int START_SEQ = 5000;
|
||||||
|
|
||||||
|
@Schema(description = "Unique identifier of the Profile.",
|
||||||
|
example = "1", required = true)
|
||||||
|
@Id
|
||||||
|
@SequenceGenerator(name = "global_seq", sequenceName = "global_seq",
|
||||||
|
allocationSize = 1, initialValue = START_SEQ)
|
||||||
|
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "global_seq")
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@Schema(description = "Имя пользователя",
|
||||||
|
example = "Alex", required = false)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Schema(description = "E-mail пользователя",
|
||||||
|
example = "user@example.com", required = true)
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@Schema(description = "Возраст пользователя",
|
||||||
|
example = "30", required = false)
|
||||||
|
private Integer age;
|
||||||
|
|
||||||
|
@Schema(description = "Дата и время создания профиля",
|
||||||
|
example = "2020-08-24T10:16:17.929+00:00", required = false)
|
||||||
|
private Timestamp created;
|
||||||
|
|
||||||
|
public Profile() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@PrePersist
|
||||||
|
public void prePersist() {
|
||||||
|
if (created == null) {
|
||||||
|
created = new Timestamp(System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
Profile profile = (Profile) o;
|
||||||
|
|
||||||
|
return id.equals(profile.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return id.hashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package ru.resprojects.restsrv.repository;
|
||||||
|
|
||||||
|
import org.springframework.data.repository.CrudRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
import ru.resprojects.restsrv.model.Profile;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface ProfileRepository extends CrudRepository<Profile, Integer> {
|
||||||
|
|
||||||
|
List<Profile> findByEmailContainingIgnoreCase(String email);
|
||||||
|
|
||||||
|
Boolean existsByEmailContainingIgnoreCase(String email);
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package ru.resprojects.restsrv.service;
|
||||||
|
|
||||||
|
import org.springframework.security.core.userdetails.User;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class AuthDetailsService implements UserDetailsService {
|
||||||
|
|
||||||
|
private static final String INMEMORY_USER = "user";
|
||||||
|
private static final String INMEMORY_PASSWORD = "$2y$12$jj9Q40qh3NOokcPjIg2cFuFK/7jBZlZ/RcrEbXkOALRv88hcuLF5a";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||||
|
if (INMEMORY_USER.equals(username)) {
|
||||||
|
return new User(INMEMORY_USER, INMEMORY_PASSWORD, new ArrayList<>());
|
||||||
|
} else {
|
||||||
|
throw new UsernameNotFoundException("Authorization error! User " + username + " not found!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package ru.resprojects.restsrv.service;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import ru.resprojects.restsrv.exception.BadResourceException;
|
||||||
|
import ru.resprojects.restsrv.exception.ResourceAlreadyExistsException;
|
||||||
|
import ru.resprojects.restsrv.exception.ResourceNotFoundException;
|
||||||
|
import ru.resprojects.restsrv.model.Profile;
|
||||||
|
import ru.resprojects.restsrv.repository.ProfileRepository;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static ru.resprojects.restsrv.util.ValidationUtil.isEmailValid;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ProfileService {
|
||||||
|
|
||||||
|
private final ProfileRepository repository;
|
||||||
|
private Profile lastCreatedProfile;
|
||||||
|
|
||||||
|
public ProfileService(ProfileRepository repository) {
|
||||||
|
this.repository = repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Profile findById(Integer id) throws ResourceNotFoundException {
|
||||||
|
return repository.findById(id)
|
||||||
|
.orElseThrow(() -> new ResourceNotFoundException("Cannot find profile with id: " + id));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Profile> findAll() {
|
||||||
|
List<Profile> profiles = new ArrayList<>();
|
||||||
|
repository.findAll().forEach(profiles::add);
|
||||||
|
return profiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Profile findByEmail(String email) throws ResourceNotFoundException {
|
||||||
|
List<Profile> profiles = repository.findByEmailContainingIgnoreCase(email);
|
||||||
|
if (!profiles.isEmpty()) {
|
||||||
|
return profiles.get(0);
|
||||||
|
} else {
|
||||||
|
throw new ResourceNotFoundException("Cannot find profile with email: " + email);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Profile save(Profile profile) throws BadResourceException, ResourceAlreadyExistsException {
|
||||||
|
if (profile == null) {
|
||||||
|
throw new BadResourceException("Failed to save profile. Profile is null.");
|
||||||
|
}
|
||||||
|
String email = profile.getEmail();
|
||||||
|
if (!isEmailValid(email)) {
|
||||||
|
throw new BadResourceException("Failed to save profile. Email " + email + " is not valid.");
|
||||||
|
}
|
||||||
|
if (repository.existsByEmailContainingIgnoreCase(email)) {
|
||||||
|
throw new ResourceAlreadyExistsException("Profile with email: " + profile.getEmail() + " already exists.");
|
||||||
|
}
|
||||||
|
lastCreatedProfile = repository.save(profile);
|
||||||
|
return lastCreatedProfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Profile getLastCreatedProfile() {
|
||||||
|
return lastCreatedProfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package ru.resprojects.restsrv.token;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class TokenResourceDetails {
|
||||||
|
|
||||||
|
private String token;
|
||||||
|
private String user;
|
||||||
|
|
||||||
|
public String getUserByToken(String token) {
|
||||||
|
if (!this.token.equals(token)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package ru.resprojects.restsrv.util;
|
||||||
|
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public final class ValidationUtil {
|
||||||
|
|
||||||
|
private ValidationUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://stackoverflow.com/a/48725527
|
||||||
|
public static boolean isEmailValid(String email) {
|
||||||
|
final Pattern EMAIL_REGEX = Pattern.compile(
|
||||||
|
"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?",
|
||||||
|
Pattern.CASE_INSENSITIVE
|
||||||
|
);
|
||||||
|
return EMAIL_REGEX.matcher(email).matches();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
65
src/main/resources/application.yml
Normal file
65
src/main/resources/application.yml
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
server:
|
||||||
|
port: 8010
|
||||||
|
|
||||||
|
spring:
|
||||||
|
profiles:
|
||||||
|
active: pgsql
|
||||||
|
---
|
||||||
|
spring:
|
||||||
|
profiles: pgsql, prod
|
||||||
|
jpa:
|
||||||
|
database: postgresql
|
||||||
|
generate-ddl: true
|
||||||
|
properties:
|
||||||
|
hibernate:
|
||||||
|
jdbc:
|
||||||
|
lob:
|
||||||
|
non_contextual_creation: true
|
||||||
|
database-platform: org.hibernate.dialect.PostgreSQL9Dialect
|
||||||
|
open-in-view: false
|
||||||
|
datasource:
|
||||||
|
platform: postgresql
|
||||||
|
initialization-mode: never
|
||||||
|
---
|
||||||
|
spring:
|
||||||
|
profiles: pgsql
|
||||||
|
datasource:
|
||||||
|
url: jdbc:postgresql://localhost/test
|
||||||
|
username: test
|
||||||
|
password: test
|
||||||
|
---
|
||||||
|
spring:
|
||||||
|
profiles: prod
|
||||||
|
datasource:
|
||||||
|
url: ${RESTSRV_PGSQL_DB_HOST}:${RESTSRV_PGSQL_DB_PORT}/${RESTSRV_PGSQL_DB_NAME}
|
||||||
|
username: ${RESTSRV_PGSQL_DB_USER}
|
||||||
|
password: ${RESTSRV_PGSQL_DB_PASSWORD}
|
||||||
|
---
|
||||||
|
spring:
|
||||||
|
profiles: test, demo
|
||||||
|
jpa:
|
||||||
|
database: h2
|
||||||
|
open-in-view: false
|
||||||
|
hibernate:
|
||||||
|
ddl-auto: none
|
||||||
|
database-platform: org.hibernate.dialect.H2Dialect
|
||||||
|
datasource:
|
||||||
|
url: jdbc:h2:mem:restsrv;DB_CLOSE_ON_EXIT=FALSE
|
||||||
|
initialization-mode: always
|
||||||
|
platform: h2
|
||||||
|
---
|
||||||
|
logging:
|
||||||
|
level:
|
||||||
|
ru.resprojects: debug
|
||||||
|
org.springframework.transaction: debug
|
||||||
|
org.springframework: error
|
||||||
|
pattern:
|
||||||
|
file: "%d %p %c{1.} [%t] %m%n"
|
||||||
|
console: "%clr(%d{HH:mm:ss.SSS}){yellow} %clr(%-5p) %clr(---){faint} %clr([%t]){cyan} %clr(%logger{36}){blue} %clr(:){red} %clr(%msg){faint}%n"
|
||||||
|
file:
|
||||||
|
name: restsrv.log
|
||||||
|
max-size: 5MB
|
||||||
|
|
||||||
|
auth:
|
||||||
|
token: secret
|
||||||
|
user: user
|
||||||
6
src/main/resources/data-h2.sql
Normal file
6
src/main/resources/data-h2.sql
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
DELETE FROM profile;
|
||||||
|
ALTER SEQUENCE global_seq RESTART WITH 5000;
|
||||||
|
|
||||||
|
INSERT INTO profile (name, email, age, created) VALUES
|
||||||
|
('h2user1', 'h2user1@example.com', 10, now()),
|
||||||
|
('h2user2', 'h2user2@example.com', 20, now());
|
||||||
6
src/main/resources/data-postgresql.sql
Normal file
6
src/main/resources/data-postgresql.sql
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
DELETE FROM profile;
|
||||||
|
ALTER SEQUENCE global_seq RESTART WITH 5000;
|
||||||
|
|
||||||
|
INSERT INTO profile (name, email, age) VALUES
|
||||||
|
('user1', 'user1@example.com', 20),
|
||||||
|
('user2', 'user2@example.com', 30);
|
||||||
13
src/main/resources/schema-h2.sql
Normal file
13
src/main/resources/schema-h2.sql
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
DROP TABLE IF EXISTS profile;
|
||||||
|
DROP SEQUENCE IF EXISTS global_seq;
|
||||||
|
|
||||||
|
CREATE SEQUENCE global_seq MINVALUE 5000;
|
||||||
|
|
||||||
|
CREATE TABLE profile (
|
||||||
|
id INT DEFAULT global_seq.nextval PRIMARY KEY,
|
||||||
|
name VARCHAR NOT NULL,
|
||||||
|
email VARCHAR NOT NULL,
|
||||||
|
age INT DEFAULT 0 NOT NULL,
|
||||||
|
created TIMESTAMP
|
||||||
|
);
|
||||||
|
CREATE UNIQUE INDEX profile_unique_email_idx ON profile(email);
|
||||||
13
src/main/resources/schema-postgresql.sql
Normal file
13
src/main/resources/schema-postgresql.sql
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
DROP TABLE IF EXISTS profile;
|
||||||
|
DROP SEQUENCE IF EXISTS global_seq CASCADE;
|
||||||
|
|
||||||
|
CREATE SEQUENCE global_seq START 5000;
|
||||||
|
|
||||||
|
CREATE TABLE profile (
|
||||||
|
id INTEGER PRIMARY KEY DEFAULT nextval('global_seq'),
|
||||||
|
name VARCHAR NOT NULL,
|
||||||
|
email VARCHAR NOT NULL,
|
||||||
|
age INTEGER DEFAULT 0 NOT NULL,
|
||||||
|
created TIMESTAMP DEFAULT now()::timestamp
|
||||||
|
);
|
||||||
|
CREATE UNIQUE INDEX profile_unique_email_idx ON profile(email);
|
||||||
44
src/test/java/ru/resprojects/restsrv/ValidationUtilTest.java
Normal file
44
src/test/java/ru/resprojects/restsrv/ValidationUtilTest.java
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package ru.resprojects.restsrv;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import ru.resprojects.restsrv.util.ValidationUtil;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
public class ValidationUtilTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenPassCorrectEmailToValidatorThenReturnTrue() {
|
||||||
|
List<String> emails = List.of(
|
||||||
|
"john@somewhere.com",
|
||||||
|
"john.foo@somewhere.com",
|
||||||
|
"john.foo+label@somewhere.com",
|
||||||
|
"john@192.168.1.10",
|
||||||
|
"john+label@192.168.1.10",
|
||||||
|
"john.foo@someserver",
|
||||||
|
"JOHN.FOO@somewhere.com"
|
||||||
|
);
|
||||||
|
|
||||||
|
for (String email : emails) {
|
||||||
|
assertThat(ValidationUtil.isEmailValid(email)).isTrue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenPassIncorrectEmailToValidatorThenReturnFalse() {
|
||||||
|
List<String> emails = List.of(
|
||||||
|
"@someserver",
|
||||||
|
"@someserver.com",
|
||||||
|
"john@.",
|
||||||
|
".@somewhere.com",
|
||||||
|
".@.somewhere.com"
|
||||||
|
);
|
||||||
|
|
||||||
|
for (String email : emails) {
|
||||||
|
assertThat(ValidationUtil.isEmailValid(email)).isFalse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,196 @@
|
|||||||
|
package ru.resprojects.restsrv.controller;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||||
|
import org.springframework.http.HttpEntity;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
import org.springframework.test.context.jdbc.Sql;
|
||||||
|
import org.springframework.test.context.jdbc.SqlConfig;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import ru.resprojects.restsrv.config.TokenRequestsFilter;
|
||||||
|
import ru.resprojects.restsrv.dto.EmailDto;
|
||||||
|
import ru.resprojects.restsrv.dto.ProfileDto;
|
||||||
|
import ru.resprojects.restsrv.dto.ProfileIdDto;
|
||||||
|
import ru.resprojects.restsrv.exception.ErrorMessage;
|
||||||
|
import ru.resprojects.restsrv.exception.LastException;
|
||||||
|
import ru.resprojects.restsrv.model.Profile;
|
||||||
|
import ru.resprojects.restsrv.repository.ProfileRepository;
|
||||||
|
import ru.resprojects.restsrv.token.TokenResourceDetails;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||||
|
@ActiveProfiles(profiles = {"test"})
|
||||||
|
@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
|
||||||
|
scripts = {"classpath:schema-h2.sql"},
|
||||||
|
config = @SqlConfig(encoding = "UTF-8"))
|
||||||
|
public class ProfileControllerTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TestRestTemplate restTemplate;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ProfileRepository repository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TokenResourceDetails tokenResourceDetails;
|
||||||
|
|
||||||
|
private Profile exampleProfile;
|
||||||
|
private final HttpHeaders headers = new HttpHeaders();
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() {
|
||||||
|
headers.add("Authorization", TokenRequestsFilter.SECURITY_SCHEME + " " + tokenResourceDetails.getToken());
|
||||||
|
Profile profile = new Profile();
|
||||||
|
profile.setName("Alex");
|
||||||
|
profile.setEmail("alex@example.com");
|
||||||
|
profile.setAge(10);
|
||||||
|
exampleProfile = repository.save(profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenFindByExistentIdThenStatus200AndReturnProfile() {
|
||||||
|
HttpEntity<String> entity = new HttpEntity<>(null, headers);
|
||||||
|
|
||||||
|
ResponseEntity<Profile> profile = restTemplate.exchange("/profiles/5000", HttpMethod.GET, entity, Profile.class);
|
||||||
|
|
||||||
|
assertThat(profile.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||||
|
assertThat(profile.getBody()).isNotNull();
|
||||||
|
assertThat(profile.getBody().getName()).isEqualTo(exampleProfile.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenRequestAllProfilesThenStatus200AndReturnListOfProfiles() {
|
||||||
|
HttpEntity<String> entity = new HttpEntity<>(null, headers);
|
||||||
|
|
||||||
|
ResponseEntity<Profile[]> profiles = restTemplate.exchange("/profiles", HttpMethod.GET, entity, Profile[].class);
|
||||||
|
|
||||||
|
assertThat(profiles.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||||
|
assertThat(profiles.getBody()).isNotNull();
|
||||||
|
assertThat(profiles.getBody()).isNotEmpty();
|
||||||
|
assertThat(profiles.getBody()[0].getName()).isEqualTo(exampleProfile.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenFindProfileByEmailThenStatus200AndReturnProfile() {
|
||||||
|
EmailDto emailDto = new EmailDto();
|
||||||
|
emailDto.setEmail("alex@example.com");
|
||||||
|
HttpEntity<EmailDto> entity = new HttpEntity<>(emailDto, headers);
|
||||||
|
|
||||||
|
ResponseEntity<Profile> profile = restTemplate.exchange("/profiles/get", HttpMethod.POST, entity, Profile.class);
|
||||||
|
|
||||||
|
assertThat(profile.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||||
|
assertThat(profile.getBody()).isNotNull();
|
||||||
|
assertThat(profile.getBody().getName()).isEqualTo(exampleProfile.getName());
|
||||||
|
assertThat(profile.getBody().getCreated()).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenCreateProfileThenStatus200AndReturnIdSavedProfile() {
|
||||||
|
ProfileDto profileDto = new ProfileDto();
|
||||||
|
profileDto.setName("John");
|
||||||
|
profileDto.setAge(10);
|
||||||
|
profileDto.setEmail("john@gmail.com");
|
||||||
|
HttpEntity<ProfileDto> entity = new HttpEntity<>(profileDto, headers);
|
||||||
|
|
||||||
|
ResponseEntity<ProfileIdDto> newProfileId = restTemplate.exchange("/profiles/set", HttpMethod.POST, entity, ProfileIdDto.class);
|
||||||
|
|
||||||
|
assertThat(newProfileId.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||||
|
assertThat(newProfileId.getBody()).isNotNull();
|
||||||
|
assertThat(newProfileId.getBody().getUserId()).isEqualTo(5001);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenRequestLastCreatedProfileThenStatus200AndReturnLastSavedProfile() {
|
||||||
|
ProfileDto profileDto = new ProfileDto();
|
||||||
|
profileDto.setName("John");
|
||||||
|
profileDto.setAge(10);
|
||||||
|
profileDto.setEmail("john@gmail.com");
|
||||||
|
HttpEntity<ProfileDto> entity = new HttpEntity<>(profileDto, headers);
|
||||||
|
|
||||||
|
ResponseEntity<ProfileIdDto> newProfileId = restTemplate.exchange("/profiles/set", HttpMethod.POST, entity, ProfileIdDto.class);
|
||||||
|
assertThat(newProfileId.getBody()).isNotNull();
|
||||||
|
|
||||||
|
HttpEntity<Void> newEntity = new HttpEntity<>(null, headers);
|
||||||
|
ResponseEntity<Profile> profile = restTemplate.exchange("/profiles/last", HttpMethod.GET, newEntity, Profile.class);
|
||||||
|
|
||||||
|
assertThat(profile.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||||
|
assertThat(profile.getBody()).isNotNull();
|
||||||
|
assertThat(profile.getBody().getId()).isEqualTo(newProfileId.getBody().getUserId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenRequestProfileWithNonexistentIdThenStatus404AndReturnErrorMessage() {
|
||||||
|
HttpEntity<String> entity = new HttpEntity<>(null, headers);
|
||||||
|
|
||||||
|
ResponseEntity<ErrorMessage> errorMessage = restTemplate.exchange("/profiles/5010", HttpMethod.GET, entity, ErrorMessage.class);
|
||||||
|
|
||||||
|
assertThat(errorMessage.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
|
||||||
|
assertThat(errorMessage.getBody()).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenRequestProfileWithNonexistentEmailThenStatus404AndReturnErrorMessage() {
|
||||||
|
EmailDto emailDto = new EmailDto();
|
||||||
|
emailDto.setEmail("test@example.com");
|
||||||
|
HttpEntity<EmailDto> entity = new HttpEntity<>(emailDto, headers);
|
||||||
|
|
||||||
|
ResponseEntity<ErrorMessage> errorMessage = restTemplate.exchange("/profiles/get", HttpMethod.POST, entity, ErrorMessage.class);
|
||||||
|
|
||||||
|
assertThat(errorMessage.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
|
||||||
|
assertThat(errorMessage.getBody()).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenCreatProfileWithIncorrectEmailThenReturnStatus400AndErrorMessage() {
|
||||||
|
ProfileDto profileDto = new ProfileDto();
|
||||||
|
profileDto.setName("John");
|
||||||
|
profileDto.setAge(10);
|
||||||
|
profileDto.setEmail(".@gmail.com");
|
||||||
|
HttpEntity<ProfileDto> entity = new HttpEntity<>(profileDto, headers);
|
||||||
|
|
||||||
|
ResponseEntity<ErrorMessage> errorMessage = restTemplate.exchange("/profiles/set", HttpMethod.POST, entity, ErrorMessage.class);
|
||||||
|
|
||||||
|
assertThat(errorMessage.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST);
|
||||||
|
assertThat(errorMessage.getBody()).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenCreatProfileWithExistentEmailThenReturnStatus403AndErrorMessage() {
|
||||||
|
ProfileDto profileDto = new ProfileDto();
|
||||||
|
profileDto.setName("John");
|
||||||
|
profileDto.setAge(10);
|
||||||
|
profileDto.setEmail("alex@example.com");
|
||||||
|
HttpEntity<ProfileDto> entity = new HttpEntity<>(profileDto, headers);
|
||||||
|
|
||||||
|
ResponseEntity<ErrorMessage> errorMessage = restTemplate.exchange("/profiles/set", HttpMethod.POST, entity, ErrorMessage.class);
|
||||||
|
|
||||||
|
assertThat(errorMessage.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||||
|
assertThat(errorMessage.getBody()).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenRequestLastErrorThenStatus200AndReturnMessageWithLastError() {
|
||||||
|
HttpEntity<String> entity = new HttpEntity<>(null, headers);
|
||||||
|
ResponseEntity<ErrorMessage> errorMessage = restTemplate.exchange("/profiles/5010", HttpMethod.GET, entity, ErrorMessage.class);
|
||||||
|
assertThat(errorMessage.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
|
||||||
|
assertThat(errorMessage.getBody()).isNotNull();
|
||||||
|
|
||||||
|
ResponseEntity<LastException> lastErrorMessage = restTemplate.exchange("/error/last", HttpMethod.GET, entity, LastException.class);
|
||||||
|
assertThat(lastErrorMessage.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||||
|
assertThat(lastErrorMessage.getBody()).isNotNull();
|
||||||
|
assertThat(lastErrorMessage.getBody().getMessage()).isEqualTo(errorMessage.getBody().getMessage());
|
||||||
|
assertThat(lastErrorMessage.getBody().getCreated()).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
package ru.resprojects.restsrv.service;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
import org.springframework.test.context.jdbc.Sql;
|
||||||
|
import org.springframework.test.context.jdbc.SqlConfig;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import ru.resprojects.restsrv.RestsrvApplication;
|
||||||
|
import ru.resprojects.restsrv.exception.BadResourceException;
|
||||||
|
import ru.resprojects.restsrv.exception.ResourceAlreadyExistsException;
|
||||||
|
import ru.resprojects.restsrv.exception.ResourceNotFoundException;
|
||||||
|
import ru.resprojects.restsrv.model.Profile;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest(classes = RestsrvApplication.class)
|
||||||
|
@ActiveProfiles(profiles = {"test"})
|
||||||
|
@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
|
||||||
|
scripts = {"classpath:schema-h2.sql"},
|
||||||
|
config = @SqlConfig(encoding = "UTF-8"))
|
||||||
|
public class ProfileServiceTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ProfileService profileService;
|
||||||
|
|
||||||
|
private Profile exampleProfile;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() {
|
||||||
|
Profile profile = new Profile();
|
||||||
|
profile.setName("h2user1");
|
||||||
|
profile.setEmail("h2user1@example.com");
|
||||||
|
profile.setAge(20);
|
||||||
|
exampleProfile = profileService.save(profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenSaveNewProfileThenReturnedProfileWithId() {
|
||||||
|
Profile exampleProfile = new Profile();
|
||||||
|
exampleProfile.setName("Alex");
|
||||||
|
exampleProfile.setEmail("alex@example.com");
|
||||||
|
exampleProfile.setAge(20);
|
||||||
|
|
||||||
|
Profile newProfile = profileService.save(exampleProfile);
|
||||||
|
|
||||||
|
assertThat(newProfile).isNotNull();
|
||||||
|
assertThat(newProfile.getId()).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenFindByIdThenReturnedProfile() {
|
||||||
|
Profile profile = profileService.findById(5000);
|
||||||
|
|
||||||
|
assertThat(profile).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenFindByEmailThenReturnedProfile() {
|
||||||
|
Profile profile = profileService.findByEmail("h2user1@example.com");
|
||||||
|
|
||||||
|
assertThat(profile).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenFindByEmailCaseInsensitiveThenReturnedProfile() {
|
||||||
|
Profile profile = profileService.findByEmail("H2uSer1@eXAmple.com");
|
||||||
|
|
||||||
|
assertThat(profile).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenGetLastCreatedProfileThenReturnedLastSavedProfile() {
|
||||||
|
Profile profile = profileService.getLastCreatedProfile();
|
||||||
|
|
||||||
|
assertThat(profile).isNotNull();
|
||||||
|
assertThat(profile).isEqualTo(exampleProfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenFindAllThenReturnedAllProfiles() {
|
||||||
|
List<Profile> profiles = profileService.findAll();
|
||||||
|
|
||||||
|
assertThat(profiles).isNotEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = ResourceNotFoundException.class)
|
||||||
|
public void whenFindByNonexistentIdWhenException() {
|
||||||
|
profileService.findById(5010);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = ResourceNotFoundException.class)
|
||||||
|
public void whenFindByNonexistentEmailThenException() {
|
||||||
|
profileService.findByEmail("test@test.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = BadResourceException.class)
|
||||||
|
public void whenSaveProfileWithIncorrectEmailThenException() {
|
||||||
|
Profile exampleProfile = new Profile();
|
||||||
|
exampleProfile.setName("Alex");
|
||||||
|
exampleProfile.setEmail(".@example.com");
|
||||||
|
exampleProfile.setAge(20);
|
||||||
|
|
||||||
|
profileService.save(exampleProfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = ResourceAlreadyExistsException.class)
|
||||||
|
public void whenSaveProfileWithExistEmailThenException() {
|
||||||
|
Profile exampleProfile = new Profile();
|
||||||
|
exampleProfile.setName("Alex");
|
||||||
|
exampleProfile.setEmail("h2user1@example.com");
|
||||||
|
exampleProfile.setAge(20);
|
||||||
|
|
||||||
|
profileService.save(exampleProfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = ResourceAlreadyExistsException.class)
|
||||||
|
public void whenSaveProfileWithExistEmailCaseInsensitiveThenException() {
|
||||||
|
Profile exampleProfile = new Profile();
|
||||||
|
exampleProfile.setName("Alex");
|
||||||
|
exampleProfile.setEmail("H2user1@example.com");
|
||||||
|
exampleProfile.setAge(20);
|
||||||
|
|
||||||
|
profileService.save(exampleProfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user