diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000..c101ecc
Binary files /dev/null and b/.DS_Store differ
diff --git a/ebuka-ngene/.DS_Store b/ebuka-ngene/.DS_Store
new file mode 100644
index 0000000..07fef44
Binary files /dev/null and b/ebuka-ngene/.DS_Store differ
diff --git a/ebuka-ngene/user-service/HELP.md b/ebuka-ngene/user-service/HELP.md
new file mode 100644
index 0000000..9f7574c
--- /dev/null
+++ b/ebuka-ngene/user-service/HELP.md
@@ -0,0 +1,19 @@
+# Getting Started
+
+### Reference Documentation
+For further reference, please consider the following sections:
+
+* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html)
+* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.5.6/maven-plugin/reference/html/)
+* [Create an OCI image](https://docs.spring.io/spring-boot/docs/2.5.6/maven-plugin/reference/html/#build-image)
+* [Spring Web](https://docs.spring.io/spring-boot/docs/2.5.6/reference/htmlsingle/#boot-features-developing-web-applications)
+* [Spring Data JPA](https://docs.spring.io/spring-boot/docs/2.5.6/reference/htmlsingle/#boot-features-jpa-and-spring-data)
+
+### Guides
+The following guides illustrate how to use some features concretely:
+
+* [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/)
+* [Serving Web Content with Spring MVC](https://spring.io/guides/gs/serving-web-content/)
+* [Building REST services with Spring](https://spring.io/guides/tutorials/bookmarks/)
+* [Accessing Data with JPA](https://spring.io/guides/gs/accessing-data-jpa/)
+
diff --git a/ebuka-ngene/user-service/mvnw b/ebuka-ngene/user-service/mvnw
new file mode 100755
index 0000000..a16b543
--- /dev/null
+++ b/ebuka-ngene/user-service/mvnw
@@ -0,0 +1,310 @@
+#!/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 "$@"
diff --git a/ebuka-ngene/user-service/mvnw.cmd b/ebuka-ngene/user-service/mvnw.cmd
new file mode 100644
index 0000000..c8d4337
--- /dev/null
+++ b/ebuka-ngene/user-service/mvnw.cmd
@@ -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%
diff --git a/ebuka-ngene/user-service/pom.xml b/ebuka-ngene/user-service/pom.xml
new file mode 100644
index 0000000..aa1f058
--- /dev/null
+++ b/ebuka-ngene/user-service/pom.xml
@@ -0,0 +1,97 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.5.6
+
+
+ com.exquis.app
+ user-service
+ 0.0.1-SNAPSHOT
+ user-service
+ user-service
+
+ 1.8
+ 2020.0.4
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ com.h2database
+ h2
+ runtime
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-client
+
+
+ jakarta.platform
+ jakarta.jakartaee-api
+ 8.0.0
+
+
+ org.springframework.security
+ spring-security-core
+ 5.3.4.RELEASE
+
+
+ io.jsonwebtoken
+ jjwt
+ 0.9.1
+
+
+ io.swagger
+ swagger-annotations
+ 1.5.22
+
+
+ org.springframework.security
+ spring-security-config
+ 5.3.4.RELEASE
+
+
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-dependencies
+ ${spring-cloud.version}
+ pom
+ import
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/UserServiceApplication.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/UserServiceApplication.java
new file mode 100644
index 0000000..32fb76e
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/UserServiceApplication.java
@@ -0,0 +1,43 @@
+package com.exquis.app.user;
+
+import com.exquis.app.user.entity.RecordStatus;
+import com.exquis.app.user.entity.Role;
+import com.exquis.app.user.enums.RoleType;
+import com.exquis.app.user.enums.StatusType;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.web.client.RestTemplate;
+
+import java.time.LocalDateTime;
+
+@SpringBootApplication
+public class UserServiceApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(UserServiceApplication.class, args);
+ }
+
+ @Bean
+ public RestTemplate restTemplate()
+ {
+ return new RestTemplate();
+ }
+
+ private void seedRole()
+ {
+ Role role = new Role();
+ role.setRole(RoleType.ADMIN);
+ role.setDescription("admin role");
+ }
+
+ private void seedRecordStatus()
+ {
+ RecordStatus recordStatus = new RecordStatus();
+ recordStatus.setStatus(StatusType.ACTIVE);
+ recordStatus.setCreatedAt(LocalDateTime.now());
+ recordStatus.setCreatedBy("ebuka@test1.com");
+
+ }
+
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/config/WebConfig.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/config/WebConfig.java
new file mode 100644
index 0000000..12d75aa
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/config/WebConfig.java
@@ -0,0 +1,12 @@
+package com.exquis.app.user.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+/**
+ *
+ * @author chukwuebuka
+ */
+@Configuration
+public class WebConfig extends WebSecurityConfigurerAdapter {
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/constant/Generic.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/constant/Generic.java
new file mode 100644
index 0000000..3c087a0
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/constant/Generic.java
@@ -0,0 +1,18 @@
+package com.exquis.app.user.constant;
+
+public interface Generic {
+ static String ISSUER = "exquifactory";
+ // reg expression
+ String DIGITS_REG_EXT = "\\d+";
+ String PHONE_REG_EX = "\\A[0-9]{11}\\z"; //"^\\+?\\d{1,3}?\\s?[0-9]{6,18}";
+ String EMAIL_REG_EX = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.(?:[a-zA-Z]{2,6})$";
+ public static final String SIGNING_KEY = "abjfoijefli2o3ur2839ru02h03f0904j4of0490j094775i75i5ki5";
+ public static final String AUTHORITIES_KEY = "scopes";
+ public static final String TOKEN_PREFIX = "Bearer ";
+ public static final String HEADER_STRING = "Authorization";
+ static int PASSWORD_LENGTH = 7;
+ static int PHONENUMBER_LENGTH = 11;
+ static String ALL_ALPHANUMERIC = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+ static String ALL_NUMERIC = "1234567890";
+ static String ALL_LOWER_ALPHABETS = "abcdefghijklmnopqrstuvwxyz";
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/controller/AuthController.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/controller/AuthController.java
new file mode 100644
index 0000000..15a4fb4
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/controller/AuthController.java
@@ -0,0 +1,69 @@
+package com.exquis.app.user.controller;
+
+import com.exquis.app.user.dto.HttpResponseDto;
+import com.exquis.app.user.dto.LoginRequestDto;
+import com.exquis.app.user.dto.RegisterUserRequestDto;
+import com.exquis.app.user.service.contract.AuthServiceContract;
+import com.exquis.app.user.service.contract.UserServiceContract;
+import com.exquis.app.user.utility.Helper;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.CrossOrigin;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.validation.Valid;
+
+@CrossOrigin
+@RestController
+public class AuthController {
+ @Autowired
+ private AuthServiceContract authService;
+
+ @ApiOperation("Users registration endpoint.")
+ @PostMapping(
+ value = "register",
+ consumes = MediaType.APPLICATION_JSON_VALUE,
+ produces = MediaType.APPLICATION_JSON_VALUE)
+ public ResponseEntity> registerUser(@Valid @RequestBody RegisterUserRequestDto requestDto)
+ {
+ HttpResponseDto httpResponseDto = authService.register(requestDto);
+
+ return new ResponseEntity<>(httpResponseDto, httpResponseDto.getStatusCode()); // return bad request
+ }
+
+ @PostMapping(
+ value = "login",
+ consumes = MediaType.APPLICATION_JSON_VALUE,
+ produces = MediaType.APPLICATION_JSON_VALUE)
+ @ApiOperation("User Login endpoint.")
+ public ResponseEntity> loginUser(@Valid @RequestBody LoginRequestDto requestDto) throws Exception
+ {
+ HttpResponseDto successResponse = new HttpResponseDto();
+ successResponse.setEntity("User Authentication"); // set entity string
+
+ try{
+ successResponse = authService.login(requestDto); // call login process
+ if(Helper.isNotEmpty(successResponse.getData()))
+ {
+
+ successResponse.setStatusCode(HttpStatus.OK);
+ successResponse.setMessage("Successful user login");
+ successResponse.setData(successResponse.getData());
+
+ return new ResponseEntity<>(successResponse, HttpStatus.OK);
+ }
+ }
+ catch(Exception ex) // catch exception and return error message
+ {
+ successResponse.setStatusCode(HttpStatus.BAD_REQUEST);
+ successResponse.setMessage("Something went wrong or Invalid credentials provided.");
+ }
+
+ return new ResponseEntity<>(successResponse, HttpStatus.BAD_REQUEST); // return bad request with object
+ }
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/controller/UserController.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/controller/UserController.java
new file mode 100644
index 0000000..c951698
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/controller/UserController.java
@@ -0,0 +1,36 @@
+package com.exquis.app.user.controller;
+
+import com.exquis.app.user.entity.User;
+import com.exquis.app.user.service.contract.UserServiceContract;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.UUID;
+
+@CrossOrigin
+@RestController
+@RequestMapping("users")
+public class UserController {
+ @Autowired private UserServiceContract userService;
+
+ @GetMapping("/")
+ public List users()
+ {
+ return userService.getAll();
+ }
+
+ @PutMapping("/")
+ public User update(@RequestBody User user)
+ {
+ return userService.saveOrUpdate(user);
+ }
+
+ @GetMapping(value = "/{id}")
+ public User getUserById(@PathVariable("id") String userId)
+ {
+ UUID uuid = UUID.fromString(userId);
+ return userService.findById(uuid);
+ }
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/dto/HttpResponseDto.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/dto/HttpResponseDto.java
new file mode 100644
index 0000000..89c7903
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/dto/HttpResponseDto.java
@@ -0,0 +1,32 @@
+package com.exquis.app.user.dto;
+
+import com.exquis.app.user.utility.Dto;
+import lombok.Data;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+
+@Data
+public class HttpResponseDto implements Dto {
+ private String message;
+ private HttpStatus statusCode;
+ private String entity;
+ private Object object;
+ private ResponseEntity> data;
+
+ public HttpResponseDto(){}
+
+ public HttpResponseDto(String message, HttpStatus statusCode, String entity, ResponseEntity> data, Object object) {
+ this.message = message;
+ this.statusCode = statusCode;
+ this.entity = entity;
+ this.data = data;
+ this.object = object;
+ }
+
+ public HttpResponseDto(String message, HttpStatus statusCode, String entity, ResponseEntity> data) {
+ this.message = message;
+ this.statusCode = statusCode;
+ this.entity = entity;
+ this.data = data;
+ }
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/dto/LoginRequestDto.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/dto/LoginRequestDto.java
new file mode 100644
index 0000000..f520d14
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/dto/LoginRequestDto.java
@@ -0,0 +1,15 @@
+package com.exquis.app.user.dto;
+
+import com.exquis.app.user.utility.Dto;
+import lombok.Data;
+
+import javax.validation.constraints.Email;
+import javax.validation.constraints.NotEmpty;
+
+@Data
+public class LoginRequestDto implements Dto {
+ @Email(message = "Email is required")
+ private String email;
+ @NotEmpty(message = "Password is required")
+ private String password;
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/dto/LoginResponseDto.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/dto/LoginResponseDto.java
new file mode 100644
index 0000000..340d8a5
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/dto/LoginResponseDto.java
@@ -0,0 +1,20 @@
+package com.exquis.app.user.dto;
+
+import com.exquis.app.user.entity.Role;
+import com.exquis.app.user.utility.Dto;
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.Set;
+import java.util.UUID;
+
+@Builder
+@Data
+public class LoginResponseDto implements Dto {
+ private UUID id;
+ private String fullName;
+ private String phone;
+ private String email;
+ private Set role; //RoleDto
+ private String accessToken;
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/dto/RegisterUserRequestDto.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/dto/RegisterUserRequestDto.java
new file mode 100644
index 0000000..9efb54c
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/dto/RegisterUserRequestDto.java
@@ -0,0 +1,25 @@
+package com.exquis.app.user.dto;
+
+import com.exquis.app.user.utility.Dto;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Enumerated;
+import javax.validation.constraints.NotEmpty;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class RegisterUserRequestDto implements Dto {
+ @NotEmpty
+ private String lastName;
+ @NotEmpty
+ private String firstName;
+ @NotEmpty
+ private String password;
+ @NotEmpty
+ private String email;
+ @NotEmpty
+ private String contactPhone;
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/dto/UserWalletResponseDto.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/dto/UserWalletResponseDto.java
new file mode 100644
index 0000000..c0c13a3
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/dto/UserWalletResponseDto.java
@@ -0,0 +1,15 @@
+package com.exquis.app.user.dto;
+
+import com.exquis.app.user.utility.Dto;
+import lombok.Builder;
+import lombok.Data;
+
+@Builder
+@Data
+public class UserWalletResponseDto implements Dto {
+ private String userId;
+ private String email;
+ private String contactPhone;
+ private String walletNumber;
+ private Double walletAmount;
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/dto/Wallet.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/dto/Wallet.java
new file mode 100644
index 0000000..d4b7b0a
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/dto/Wallet.java
@@ -0,0 +1,14 @@
+package com.exquis.app.user.dto;
+
+import com.exquis.app.user.utility.Dto;
+import lombok.Data;
+
+import java.util.UUID;
+
+@Data
+public class Wallet implements Dto {
+ private String number;
+ private Double amount;
+ private UUID userId;
+ private Long recordId;
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/entity/RecordStatus.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/entity/RecordStatus.java
new file mode 100644
index 0000000..dc5ad10
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/entity/RecordStatus.java
@@ -0,0 +1,42 @@
+package com.exquis.app.user.entity;
+
+import com.exquis.app.user.enums.StatusType;
+import lombok.Data;
+import org.hibernate.annotations.CreationTimestamp;
+
+import javax.persistence.*;
+import java.time.LocalDateTime;
+
+@Data
+@Entity
+@Table(name = "record_status")
+public class RecordStatus {
+ @Id
+ @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "record_status_generator")
+ @SequenceGenerator(name="record_status_generator", sequenceName = "record_status_seq", allocationSize=50, initialValue = 300)
+ @Column(name = "id", updatable = false, nullable = false)
+ private long id;
+
+ @Column(name = "created_by")
+ private String createdBy;
+
+ @Column(name = "created_at", nullable = false)
+ @CreationTimestamp
+ private LocalDateTime createdAt = LocalDateTime.now();
+
+ @Column(name = "updated_by")
+ private String updatedBy;
+
+ @Column(name = "updated_at")
+ private LocalDateTime updatedAt;
+
+ @Column(name = "deleted_by")
+ private String deletedBy;
+
+ @Column(name = "deleted_at")
+ private LocalDateTime deletedAt;
+
+ @Enumerated(EnumType.STRING)
+ @Column(name = "status", nullable = false)
+ private StatusType status;
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/entity/Role.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/entity/Role.java
new file mode 100644
index 0000000..520898a
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/entity/Role.java
@@ -0,0 +1,24 @@
+package com.exquis.app.user.entity;
+
+import com.exquis.app.user.enums.RoleType;
+import lombok.Data;
+
+import javax.persistence.*;
+
+@Data
+@Entity
+public class Role {
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private Long id;
+ @Column(unique = true, nullable = false)
+ @Enumerated(EnumType.STRING)
+ private RoleType role;
+
+ @Column(length = 250)
+ private String description;
+
+ @OneToOne(fetch = FetchType.EAGER)
+ @JoinColumn(name = "record_status", referencedColumnName = "id", nullable = false, unique = true)
+ private RecordStatus recordStatus;
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/entity/User.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/entity/User.java
new file mode 100644
index 0000000..ac5b4f7
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/entity/User.java
@@ -0,0 +1,43 @@
+package com.exquis.app.user.entity;
+
+import com.exquis.app.user.enums.Gender;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.*;
+import java.util.Date;
+import java.util.Set;
+import java.util.UUID;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Entity
+@Table(name = "user_account")
+public class User {
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ private UUID id;
+ @Column(nullable = false, unique = true)
+ private String email;
+ @Column(nullable = false)
+ private String password;
+ @Column(nullable = false, unique = true)
+ private String contactPhone;
+ private String lastName;
+ private String firstName;
+
+ @ManyToMany(
+ fetch = FetchType.EAGER,
+ cascade = {CascadeType.ALL})
+ @JoinTable(
+ name = "user_roles",
+ joinColumns = @JoinColumn(name = "user_id"),
+ inverseJoinColumns = @JoinColumn(name = "role_id"))
+ private Set roles;
+
+ @OneToOne(fetch = FetchType.EAGER)
+ @JoinColumn(name = "record_status", referencedColumnName = "id", nullable = false, unique = true)
+ private RecordStatus recordStatus;
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/enums/Gender.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/enums/Gender.java
new file mode 100644
index 0000000..a4e0de1
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/enums/Gender.java
@@ -0,0 +1,27 @@
+package com.exquis.app.user.enums;
+
+import com.exquis.app.user.utility.Dto;
+
+public enum Gender implements Dto {
+ M("Male"),
+ F("Female"),
+ OTHER("Other");
+
+ private final String description;
+
+ Gender(String description) {
+ this.description = description;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public static Gender fromName(String name) {
+ if (name == null || name.isEmpty()) {
+ return null;
+ }
+
+ return Gender.valueOf(name);
+ }
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/enums/RoleType.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/enums/RoleType.java
new file mode 100644
index 0000000..16efbd2
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/enums/RoleType.java
@@ -0,0 +1,8 @@
+package com.exquis.app.user.enums;
+
+import com.exquis.app.user.utility.Dto;
+
+public enum RoleType implements Dto {
+ ADMIN,
+ USER
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/enums/StatusType.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/enums/StatusType.java
new file mode 100644
index 0000000..8d068c7
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/enums/StatusType.java
@@ -0,0 +1,7 @@
+package com.exquis.app.user.enums;
+
+public enum StatusType {
+ ACTIVE,
+ SUSPENDED,
+ DELETED
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/exception/HttpBadGatewayException.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/exception/HttpBadGatewayException.java
new file mode 100644
index 0000000..e92f181
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/exception/HttpBadGatewayException.java
@@ -0,0 +1,10 @@
+package com.exquis.app.user.exception;
+
+public class HttpBadGatewayException extends RuntimeException{
+ public HttpBadGatewayException(){
+ super("Gateway Error");
+ }
+ public HttpBadGatewayException(String message){
+ super(message);
+ }
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/exception/HttpBadRequestException.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/exception/HttpBadRequestException.java
new file mode 100644
index 0000000..6cda5df
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/exception/HttpBadRequestException.java
@@ -0,0 +1,11 @@
+package com.exquis.app.user.exception;
+
+public class HttpBadRequestException extends RuntimeException{
+ public HttpBadRequestException(){
+ super("bad request");
+ }
+ public HttpBadRequestException(String message)
+ {
+ super(message);
+ }
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/exception/HttpForbiddenException.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/exception/HttpForbiddenException.java
new file mode 100644
index 0000000..2c57085
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/exception/HttpForbiddenException.java
@@ -0,0 +1,12 @@
+package com.exquis.app.user.exception;
+
+public class HttpForbiddenException extends RuntimeException{
+
+ public HttpForbiddenException(){
+ super("Forbidden");
+ }
+ public HttpForbiddenException(String message)
+ {
+ super(message);
+ }
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/exception/HttpNotFoundException.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/exception/HttpNotFoundException.java
new file mode 100644
index 0000000..cfd2e3c
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/exception/HttpNotFoundException.java
@@ -0,0 +1,15 @@
+package com.exquis.app.user.exception;
+
+/**
+ *
+ * @author chukwuebuka
+ */
+public class HttpNotFoundException extends RuntimeException {
+ public HttpNotFoundException(String message) {
+ super(message);
+ }
+
+ public HttpNotFoundException() {
+ super("not found");
+ }
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/repository/RecordStatusRepository.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/repository/RecordStatusRepository.java
new file mode 100644
index 0000000..841f9fe
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/repository/RecordStatusRepository.java
@@ -0,0 +1,9 @@
+package com.exquis.app.user.repository;
+
+import com.exquis.app.user.entity.RecordStatus;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface RecordStatusRepository extends JpaRepository {
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/repository/RoleRepository.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/repository/RoleRepository.java
new file mode 100644
index 0000000..e43168d
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/repository/RoleRepository.java
@@ -0,0 +1,11 @@
+package com.exquis.app.user.repository;
+
+import com.exquis.app.user.entity.Role;
+import com.exquis.app.user.enums.RoleType;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface RoleRepository extends JpaRepository {
+ Role findByRole(RoleType roleType);
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/repository/UserRepository.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/repository/UserRepository.java
new file mode 100644
index 0000000..11a7209
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/repository/UserRepository.java
@@ -0,0 +1,16 @@
+package com.exquis.app.user.repository;
+
+import com.exquis.app.user.entity.User;
+import com.exquis.app.user.enums.Gender;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+import java.util.UUID;
+
+@Repository
+public interface UserRepository extends JpaRepository {
+ User findByUsername(String username);
+ User findByEmail(String email);
+ List findByGender(Gender gender);
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/service/AuthService.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/service/AuthService.java
new file mode 100644
index 0000000..3aecbfd
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/service/AuthService.java
@@ -0,0 +1,121 @@
+package com.exquis.app.user.service;
+
+import com.exquis.app.user.constant.Generic;
+import com.exquis.app.user.dto.HttpResponseDto;
+import com.exquis.app.user.dto.LoginRequestDto;
+import com.exquis.app.user.dto.LoginResponseDto;
+import com.exquis.app.user.dto.RegisterUserRequestDto;
+import com.exquis.app.user.entity.User;
+import com.exquis.app.user.enums.StatusType;
+import com.exquis.app.user.exception.HttpBadRequestException;
+import com.exquis.app.user.exception.HttpForbiddenException;
+import com.exquis.app.user.service.contract.AuthServiceContract;
+import com.exquis.app.user.service.contract.RoleServiceContract;
+import com.exquis.app.user.utility.Helper;
+import com.exquis.app.user.utility.JwtTokenUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.DisabledException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class AuthService implements AuthServiceContract {
+ @Autowired
+ private UserService userService;
+ @Autowired
+ AuthenticationManager authenticationManager;
+ @Autowired private JwtTokenUtil jwtTokenUtil;
+ @Autowired private RoleServiceContract roleService;
+
+ static String ENTITY = "authentication";
+
+ @Override
+ public HttpResponseDto register(RegisterUserRequestDto registrationRequestDto) {
+ HttpResponseDto httpResponseDto = new HttpResponseDto();
+ httpResponseDto.setEntity("User Registration");
+
+ User user = userService.createUserAccount(registrationRequestDto);
+ if(Helper.isNotEmpty(user)) {
+ httpResponseDto.setStatusCode(HttpStatus.CREATED);
+ httpResponseDto.setMessage("Successful user registration");
+ httpResponseDto.setData(new ResponseEntity(user, HttpStatus.CREATED));
+ }
+ else{
+ httpResponseDto.setStatusCode(HttpStatus.BAD_REQUEST);
+ httpResponseDto.setMessage("Not successful");
+ }
+
+ return httpResponseDto;
+ }
+
+ @Override
+ public HttpResponseDto login(LoginRequestDto loginRequestDto) {
+ final String accessToken;
+ HttpResponseDto successResponse = new HttpResponseDto();
+ //LoginResponseDto loginResponseDto = new LoginResponseDto();
+ Authentication authentication = null;
+
+ // I am checking all entries here in case model validation does not work
+ if(Helper.isEmpty(loginRequestDto.getEmail()) || Helper.isEmpty(loginRequestDto.getPassword())) {
+ throw new HttpBadRequestException("Please fill in all fields.");
+ }
+ // validate that is an email
+ if(!loginRequestDto.getEmail().matches(Generic.EMAIL_REG_EX))
+ {
+ throw new HttpBadRequestException("Invalid Credentials.");
+ }
+
+ // confirm that password is valid
+ List validPassword = Helper.isValidPassword(loginRequestDto.getPassword());
+
+ if(Helper.isNotEmpty(validPassword) && !validPassword.isEmpty())
+ {
+ throw new HttpBadRequestException(validPassword.toString());
+ }
+
+ try{
+ authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginRequestDto.getEmail(), loginRequestDto.getPassword()));
+ }
+ catch(BadCredentialsException ex){
+ throw new HttpBadRequestException("Invalid Credentials");
+ }
+
+ if(Helper.isNotEmpty(authentication))
+ {
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ accessToken = jwtTokenUtil.generateToken(authentication);
+ // we need to get user object to set our login-response-object
+ User user = userService.findByEmail(loginRequestDto.getEmail().trim()); // get user by phone or email
+
+ if(Helper.isNotEmpty(user)) // check user object
+ {
+ // make sure role if this user is active
+ if(!roleService.checkRoleStatus(user.getRoles(), StatusType.ACTIVE))
+ {
+ throw new HttpForbiddenException("User role is not active and can't login.");
+ }
+
+ LoginResponseDto loginResponseDto = LoginResponseDto.builder()
+ .id(user.getId())
+ .email(user.getEmail())
+ .accessToken(accessToken)
+ .fullName(user.getLastName() + user.getFirstName())
+ .phone(user.getContactPhone())
+ .role(user.getRoles())
+ .build();
+
+ successResponse.setData(new ResponseEntity(loginResponseDto, HttpStatus.OK)); // set to data response with ok http status
+ }
+ }
+
+ return successResponse;
+ }
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/service/RecordStatusService.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/service/RecordStatusService.java
new file mode 100644
index 0000000..ccf302f
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/service/RecordStatusService.java
@@ -0,0 +1,95 @@
+package com.exquis.app.user.service;
+
+import com.exquis.app.user.constant.Generic;
+import com.exquis.app.user.entity.RecordStatus;
+import com.exquis.app.user.enums.StatusType;
+import com.exquis.app.user.repository.RecordStatusRepository;
+import com.exquis.app.user.service.contract.RecordStatusServiceContract;
+import com.exquis.app.user.utility.Helper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.transaction.Transactional;
+import java.time.LocalDateTime;
+
+@Service
+public class RecordStatusService implements RecordStatusServiceContract {
+
+ @Autowired
+ private RecordStatusRepository recordStatusRepository;
+
+ @Override
+ @Transactional
+ public RecordStatus create(StatusType type) {
+ //new
+ RecordStatus newRecordStatus = new RecordStatus();
+ newRecordStatus.setCreatedAt(LocalDateTime.now());
+ newRecordStatus.setCreatedBy(Generic.ISSUER); // created_by should be issuer for now
+ newRecordStatus.setStatus(type);
+
+ return recordStatusRepository.save(newRecordStatus); // call repo to save data
+ }
+
+ @Override
+ public RecordStatus create(StatusType type, String createdBy) {
+ //new
+ RecordStatus newRecordStatus = new RecordStatus();
+ newRecordStatus.setCreatedAt(LocalDateTime.now());
+ newRecordStatus.setCreatedBy(createdBy);
+ newRecordStatus.setStatus(type);
+
+ return recordStatusRepository.save(newRecordStatus); // call repo to save data
+ }
+
+ @Override
+ @Transactional
+ public RecordStatus update(long recordStatusId, StatusType type) {
+ RecordStatus recordStatus = exist(recordStatusId);
+
+ if(Helper.isNotEmpty(recordStatus))
+ {
+ recordStatus.setUpdatedAt(LocalDateTime.now());
+ recordStatus.setUpdatedBy(Generic.ISSUER);
+ recordStatus.setStatus(type);
+
+ recordStatusRepository.save(recordStatus);
+ }
+ return recordStatus;
+ }
+
+ @Override
+ @Transactional
+ public RecordStatus update(long recordStatusId, String updatedBy) {
+ RecordStatus recordStatus = exist(recordStatusId);
+
+ if(Helper.isNotEmpty(recordStatus))
+ {
+ recordStatus.setUpdatedAt(LocalDateTime.now());
+ recordStatus.setUpdatedBy(updatedBy);
+
+ recordStatusRepository.save(recordStatus);
+ }
+ return recordStatus;
+ }
+
+ @Override
+ @Transactional
+ public RecordStatus delete(long recordStatusId, String deletedBy) {
+ RecordStatus recordStatus = exist(recordStatusId);
+
+ if(Helper.isNotEmpty(recordStatus))
+ {
+ recordStatus.setDeletedAt(LocalDateTime.now());
+ recordStatus.setDeletedBy(deletedBy);
+ recordStatus.setStatus(StatusType.DELETED); // partial delete
+
+ recordStatusRepository.save(recordStatus);
+ }
+ return recordStatus;
+ }
+
+ @Override
+ public RecordStatus exist(long recordStatusId) {
+ return recordStatusRepository.findById(recordStatusId).orElse(null);
+ }
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/service/RoleService.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/service/RoleService.java
new file mode 100644
index 0000000..9fc765c
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/service/RoleService.java
@@ -0,0 +1,77 @@
+package com.exquis.app.user.service;
+
+import com.exquis.app.user.entity.Role;
+import com.exquis.app.user.enums.RoleType;
+import com.exquis.app.user.enums.StatusType;
+import com.exquis.app.user.repository.RoleRepository;
+import com.exquis.app.user.service.contract.RoleServiceContract;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.Authentication;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@Service
+public class RoleService implements RoleServiceContract {
+ @Autowired RoleRepository roleRepository;
+ @Autowired
+ private RecordStatusService recordStatusService;
+
+ /**@Override
+ public Role findByRole(RoleType roleType) {
+ return roleRepository.findByRole(roleType);
+ }***/
+
+ @Override
+ public Role findById(Long id) {
+ return roleRepository.findById(id).orElse(null);
+ }
+
+ @Override
+ public Role findByRoleName(String role) {
+ //return roleRepository.getOne(role);
+ return roleRepository.findByRole(RoleType.valueOf(role));
+ }
+
+ @Override
+ public Role addOrUpdate(Role role) {
+ return roleRepository.save(role);
+ }
+
+ @Override
+ public List findAll() {
+ return roleRepository.findAll();
+ }
+
+ @Override
+ public List findByStatus(StatusType status) {
+ List roles = roleRepository.findAll();
+ return roles.stream().filter(role -> role.getRecordStatus().getStatus().equals(status)).collect(Collectors.toList());
+ }
+
+ @Override
+ public Boolean hasRole(Authentication auth, RoleType roleType) {
+ if (auth.getAuthorities()
+ .stream()
+ .anyMatch(s -> s.getAuthority().equals(roleType.toString()))) {
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public Boolean hasRole(Set role, RoleType roleType) {
+ if(role.stream().anyMatch(s->s.getId().equals(roleType)))
+ return true;
+ return false;
+ }
+
+ @Override
+ public Boolean checkRoleStatus(Set roles, StatusType status) {
+ if(roles.stream().anyMatch(s->s.getRecordStatus().getStatus().equals(status)))
+ return true;
+ return false;
+ }
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/service/UserService.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/service/UserService.java
new file mode 100644
index 0000000..f242290
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/service/UserService.java
@@ -0,0 +1,115 @@
+package com.exquis.app.user.service;
+
+import com.exquis.app.user.dto.RegisterUserRequestDto;
+import com.exquis.app.user.dto.UserWalletResponseDto;
+import com.exquis.app.user.entity.Role;
+import com.exquis.app.user.entity.User;
+import com.exquis.app.user.enums.RoleType;
+import com.exquis.app.user.enums.StatusType;
+import com.exquis.app.user.exception.HttpBadGatewayException;
+import com.exquis.app.user.exception.HttpBadRequestException;
+import com.exquis.app.user.exception.HttpNotFoundException;
+import com.exquis.app.user.dto.Wallet;
+import com.exquis.app.user.repository.UserRepository;
+import com.exquis.app.user.service.contract.RecordStatusServiceContract;
+import com.exquis.app.user.service.contract.RoleServiceContract;
+import com.exquis.app.user.service.contract.UserServiceContract;
+import com.exquis.app.user.utility.Helper;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+
+import javax.transaction.Transactional;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+
+/**
+ *
+ * @author chukwuebuka
+ */
+
+@Slf4j
+@Service
+public class UserService implements UserServiceContract {
+ @Autowired private UserRepository userRepository;
+ @Autowired private RoleServiceContract roleService;
+ @Autowired private PasswordEncoder passwordEncoder;
+ @Autowired private RecordStatusServiceContract recordStatusService;
+ @Autowired private RestTemplate restTemplate;
+
+ @Override
+ @Transactional
+ public User saveOrUpdate(User user) {
+ return userRepository.save(user);
+ }
+
+ @Override
+ public List getAll() {
+ return userRepository.findAll();
+ }
+
+ @Override
+ public User findById(UUID id) {
+ return userRepository.findById(id).orElseThrow(()-> new HttpNotFoundException());
+ }
+
+ @Override
+ public User findByEmail(String email) {
+ return userRepository.findByEmail(email);
+ }
+
+ @Override
+ public UserWalletResponseDto findUserWithWallet(UUID userId) {
+ log.info("findUserWithWallet()");
+ User user = userRepository.findById(userId).orElseThrow(()-> new HttpNotFoundException("User not found"));
+ try{
+ Wallet wallet = restTemplate.getForObject("http://WALLET-SERVICE/wallets/" + user.getId(), Wallet.class);
+
+ UserWalletResponseDto responseDto = UserWalletResponseDto
+ .builder()
+ .userId(user.getId().toString())
+ .email(user.getEmail())
+ .contactPhone(user.getContactPhone())
+ .walletNumber(wallet.getNumber())
+ .walletAmount(wallet.getAmount())
+ .build();
+
+ return responseDto;
+ }
+ catch(Exception ex)
+ {
+ throw new HttpBadGatewayException();
+ }
+ }
+
+ @Override
+ public User createUserAccount(RegisterUserRequestDto registerUserRequestDto) {
+ //set user role
+ Set roles = new HashSet<>();
+
+ Role userRole = roleService.findByRole(RoleType.USER);
+ if(Helper.isEmpty(userRole)) { // it means user as a role is not setup in the system
+ throw new HttpBadRequestException("Make sure user roles and privileges are setup first.");
+ }
+ // we hope role is not deleted
+ if(userRole.getRecordStatus().getStatus() == StatusType.DELETED){
+ throw new HttpBadRequestException("User role is deleted and can't be added to user account. \n Suggestion: Find out why user role is not active.");
+ }
+ roles.add(userRole); // add to role set
+
+ User user = new User();
+ user.setRoles(roles);
+ user.setEmail(registerUserRequestDto.getEmail());
+ user.setLastName(registerUserRequestDto.getLastName());
+ user.setFirstName(registerUserRequestDto.getFirstName());
+ user.setContactPhone(registerUserRequestDto.getContactPhone());
+ user.setPassword(passwordEncoder.encode(registerUserRequestDto.getPassword()));
+ user.setRecordStatus(recordStatusService.create(StatusType.ACTIVE));
+
+ return saveOrUpdate(user); // create
+ }
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/service/contract/AuthServiceContract.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/service/contract/AuthServiceContract.java
new file mode 100644
index 0000000..d3062cd
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/service/contract/AuthServiceContract.java
@@ -0,0 +1,10 @@
+package com.exquis.app.user.service.contract;
+
+import com.exquis.app.user.dto.HttpResponseDto;
+import com.exquis.app.user.dto.LoginRequestDto;
+import com.exquis.app.user.dto.RegisterUserRequestDto;
+
+public interface AuthServiceContract {
+ HttpResponseDto register(RegisterUserRequestDto registerUserRequestDto);
+ HttpResponseDto login(LoginRequestDto loginRequestDto);
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/service/contract/RecordStatusServiceContract.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/service/contract/RecordStatusServiceContract.java
new file mode 100644
index 0000000..97734a7
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/service/contract/RecordStatusServiceContract.java
@@ -0,0 +1,17 @@
+package com.exquis.app.user.service.contract;
+
+import com.exquis.app.user.entity.RecordStatus;
+import com.exquis.app.user.enums.StatusType;
+
+/**
+ *
+ * @author Chukwuebuka
+ */
+public interface RecordStatusServiceContract {
+ RecordStatus create(StatusType type);
+ RecordStatus create(StatusType type, String createdBy);
+ RecordStatus update(long recordStatusId, StatusType type);
+ RecordStatus update(long recordStatusId, String updatedBy);
+ RecordStatus delete(long recordStatusId, String deletedBy);
+ RecordStatus exist(long recordStatusId);
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/service/contract/RoleServiceContract.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/service/contract/RoleServiceContract.java
new file mode 100644
index 0000000..85696e6
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/service/contract/RoleServiceContract.java
@@ -0,0 +1,28 @@
+package com.exquis.app.user.service.contract;
+
+import com.exquis.app.user.entity.Role;
+import com.exquis.app.user.enums.RoleType;
+import com.exquis.app.user.enums.StatusType;
+import org.springframework.security.core.Authentication;
+
+import java.util.List;
+import java.util.Set;
+
+public interface RoleServiceContract {
+ //Role findByRole(RoleType roleType);
+ Role findById(Long id);
+
+ Role findByRoleName(String role);
+
+ Role addOrUpdate(Role role);
+
+ List findAll();
+ // fill all roles by status
+ List findByStatus(StatusType status);
+ /** Check if a user has a certain role* */
+ Boolean hasRole(Authentication auth, RoleType roleType);
+
+ Boolean hasRole(Set role, RoleType roleType);
+
+ Boolean checkRoleStatus(Set roles, StatusType status);
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/service/contract/UserServiceContract.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/service/contract/UserServiceContract.java
new file mode 100644
index 0000000..337f566
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/service/contract/UserServiceContract.java
@@ -0,0 +1,17 @@
+package com.exquis.app.user.service.contract;
+
+import com.exquis.app.user.dto.RegisterUserRequestDto;
+import com.exquis.app.user.dto.UserWalletResponseDto;
+import com.exquis.app.user.entity.User;
+
+import java.util.List;
+import java.util.UUID;
+
+public interface UserServiceContract {
+ User saveOrUpdate(User user);
+ List getAll();
+ User findById(UUID id);
+ User findByEmail(String email);
+ UserWalletResponseDto findUserWithWallet(UUID userId);
+ User createUserAccount(RegisterUserRequestDto registerUserRequestDto);
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/utility/Dto.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/utility/Dto.java
new file mode 100644
index 0000000..5defbc9
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/utility/Dto.java
@@ -0,0 +1,6 @@
+package com.exquis.app.user.utility;
+
+import java.io.Serializable;
+
+public interface Dto extends Serializable {
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/utility/Helper.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/utility/Helper.java
new file mode 100644
index 0000000..e3a394a
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/utility/Helper.java
@@ -0,0 +1,90 @@
+package com.exquis.app.user.utility;
+
+import com.exquis.app.user.constant.Generic;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
+
+import static com.exquis.app.user.constant.Generic.ALL_ALPHANUMERIC;
+import static com.exquis.app.user.constant.Generic.ALL_NUMERIC;
+
+public class Helper {
+ public static boolean isEmpty(T value) {
+ if (value == null) return true;
+ if (value instanceof String && ((String) value).trim().isEmpty()) return true;
+ return false;
+ }
+
+ public static boolean isNotEmpty(T value) {
+ return !isEmpty(value);
+ }
+
+ public static String getAlphaNumeric(int size)
+ {
+ String stringToPickFrom = ALL_ALPHANUMERIC;
+ StringBuffer stringBuffer = new StringBuffer(size);
+ for(int i=0; i isValidPassword(String passwordhere) {
+
+ List errorList = new ArrayList();
+
+ Pattern lowerCasePatten = Pattern.compile("[a-z ]");
+ Pattern digitCasePatten = Pattern.compile("[0-9 ]");
+
+ if (passwordhere.length() <= Generic.PASSWORD_LENGTH) {
+ errorList.add("Password length must have at least " + String.valueOf(Generic.PASSWORD_LENGTH ) + " character !!");
+ }
+ if (!lowerCasePatten.matcher(passwordhere).find()) {
+ errorList.add("Password must have at least one lowercase character !!");
+ }
+ if (!digitCasePatten.matcher(passwordhere).find()) {
+ errorList.add("Password must have at least one digit character !!");
+ }
+
+ return errorList;
+
+ }
+}
diff --git a/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/utility/JwtTokenUtil.java b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/utility/JwtTokenUtil.java
new file mode 100644
index 0000000..0386533
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/java/com/exquis/app/user/utility/JwtTokenUtil.java
@@ -0,0 +1,125 @@
+package com.exquis.app.user.utility;
+
+import com.exquis.app.user.constant.Generic;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jws;
+import io.jsonwebtoken.JwtParser;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.util.*;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import static com.exquis.app.user.constant.Generic.AUTHORITIES_KEY;
+import static com.exquis.app.user.constant.Generic.SIGNING_KEY;
+
+public class JwtTokenUtil implements Serializable {
+ private static final long serialVersionUID = -2550185165626007488L;
+
+ public static final long JWT_TOKEN_VALIDITY = 5*60*60;
+
+ @Value("")
+ private String secret;
+
+ public String getUsernameFromToken(String token) {
+ return getClaimFromToken(token, Claims::getSubject);
+ }
+
+ public Date getIssuedAtDateFromToken(String token) {
+ return getClaimFromToken(token, Claims::getIssuedAt);
+ }
+
+ public Date getExpirationDateFromToken(String token) {
+ return getClaimFromToken(token, Claims::getExpiration);
+ }
+
+ public T getClaimFromToken(String token, Function claimsResolver) {
+ final Claims claims = getAllClaimsFromToken(token);
+ return claimsResolver.apply(claims);
+ }
+
+ private Claims getAllClaimsFromToken(String token) {
+ return Jwts.parser().setSigningKey(SIGNING_KEY).parseClaimsJws(token).getBody();
+ }
+
+ private Boolean isTokenExpired(String token) {
+ final Date expiration = getExpirationDateFromToken(token);
+ return expiration.before(new Date());
+ }
+
+ private Boolean ignoreTokenExpiration(String token) {
+ // here you specify tokens, for that the expiration is ignored
+ return false;
+ }
+
+ public String generateToken(UserDetails userDetails) {
+ Map claims = new HashMap<>();
+ return doGenerateToken(claims, userDetails.getUsername());
+ }
+
+ private String doGenerateToken(Map claims, String subject) {
+
+ return Jwts.builder()
+ .setClaims(claims)
+ .setSubject(subject)
+ .setIssuedAt(new Date(System.currentTimeMillis()))
+ //.setExpiration(new Date(System.currentTimeMillis() + JWT_TOKEN_VALIDITY*1000))
+ .setExpiration(Date.from(
+ LocalDateTime.now().plusHours(1).toInstant(ZoneOffset.UTC)))
+ .signWith(SignatureAlgorithm.HS512, SIGNING_KEY)
+ .compact();
+ }
+
+ public String generateToken(Authentication authentication) {
+ Date dateIssued = new Date();
+ Date dateExpiry = new Date(System.currentTimeMillis() + Helper.getDaysInMiliseconds(30));
+ final String authorities =
+ authentication
+ .getAuthorities()
+ .stream()
+ .map(GrantedAuthority::getAuthority)
+ .collect(Collectors.joining(","));
+ return Jwts.builder()
+ .setSubject(authentication.getName())
+ .claim(AUTHORITIES_KEY, authorities)
+ .signWith(SignatureAlgorithm.HS256, SIGNING_KEY)
+ .setIssuedAt(dateIssued)
+ .setExpiration(dateExpiry)
+ .compact();
+ }
+
+ public Boolean canTokenBeRefreshed(String token) {
+ return (!isTokenExpired(token) || ignoreTokenExpiration(token));
+ }
+
+ public Boolean validateToken(String token, UserDetails userDetails) {
+ final String username = getUsernameFromToken(token);
+ return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
+ }
+ UsernamePasswordAuthenticationToken getAuthentication(
+ final String token, final Authentication existingAuth, final UserDetails userDetails) {
+
+ final JwtParser jwtParser = Jwts.parser().setSigningKey(SIGNING_KEY);
+
+ final Jws claimsJws = jwtParser.parseClaimsJws(token);
+
+ final Claims claims = claimsJws.getBody();
+
+ final Collection extends GrantedAuthority> authorities =
+ Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(","))
+ .map(SimpleGrantedAuthority::new)
+ .collect(Collectors.toList());
+
+ return new UsernamePasswordAuthenticationToken(userDetails, "", authorities);
+ }
+}
diff --git a/ebuka-ngene/user-service/src/main/resources/application.properties b/ebuka-ngene/user-service/src/main/resources/application.properties
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/resources/application.properties
@@ -0,0 +1 @@
+
diff --git a/ebuka-ngene/user-service/src/main/resources/application.yml b/ebuka-ngene/user-service/src/main/resources/application.yml
new file mode 100644
index 0000000..1ce3c48
--- /dev/null
+++ b/ebuka-ngene/user-service/src/main/resources/application.yml
@@ -0,0 +1,15 @@
+server:
+ port: 8000
+
+spring:
+ application:
+ name: USER-SERVICE
+
+eureka:
+ client:
+ register-with-eureka: true
+ fetch-registry: true
+ service-url:
+ default-zone: http://localhost:8761/eureka/
+ instance:
+ hostname: localhost
\ No newline at end of file
diff --git a/ebuka-ngene/user-service/src/test/java/com/exquis/app/user/UserServiceApplicationTests.java b/ebuka-ngene/user-service/src/test/java/com/exquis/app/user/UserServiceApplicationTests.java
new file mode 100644
index 0000000..d4e0f6d
--- /dev/null
+++ b/ebuka-ngene/user-service/src/test/java/com/exquis/app/user/UserServiceApplicationTests.java
@@ -0,0 +1,13 @@
+package com.exquis.app.user;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class UserServiceApplicationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}
diff --git a/ebuka-ngene/user-service/target/classes/application.properties b/ebuka-ngene/user-service/target/classes/application.properties
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/ebuka-ngene/user-service/target/classes/application.properties
@@ -0,0 +1 @@
+
diff --git a/ebuka-ngene/user-service/target/classes/application.yml b/ebuka-ngene/user-service/target/classes/application.yml
new file mode 100644
index 0000000..1ce3c48
--- /dev/null
+++ b/ebuka-ngene/user-service/target/classes/application.yml
@@ -0,0 +1,15 @@
+server:
+ port: 8000
+
+spring:
+ application:
+ name: USER-SERVICE
+
+eureka:
+ client:
+ register-with-eureka: true
+ fetch-registry: true
+ service-url:
+ default-zone: http://localhost:8761/eureka/
+ instance:
+ hostname: localhost
\ No newline at end of file
diff --git a/ebuka-ngene/user-service/target/classes/com/exquis/app/user/UserServiceApplication.class b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/UserServiceApplication.class
new file mode 100644
index 0000000..012c0ba
Binary files /dev/null and b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/UserServiceApplication.class differ
diff --git a/ebuka-ngene/user-service/target/classes/com/exquis/app/user/controller/RegistrationController.class b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/controller/RegistrationController.class
new file mode 100644
index 0000000..e123e0e
Binary files /dev/null and b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/controller/RegistrationController.class differ
diff --git a/ebuka-ngene/user-service/target/classes/com/exquis/app/user/controller/UserController.class b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/controller/UserController.class
new file mode 100644
index 0000000..c6a5c1e
Binary files /dev/null and b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/controller/UserController.class differ
diff --git a/ebuka-ngene/user-service/target/classes/com/exquis/app/user/dto/RegisterUserRequestDto.class b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/dto/RegisterUserRequestDto.class
new file mode 100644
index 0000000..9a9176d
Binary files /dev/null and b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/dto/RegisterUserRequestDto.class differ
diff --git a/ebuka-ngene/user-service/target/classes/com/exquis/app/user/dto/UserWalletResponseDto$UserWalletResponseDtoBuilder.class b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/dto/UserWalletResponseDto$UserWalletResponseDtoBuilder.class
new file mode 100644
index 0000000..bc60dcf
Binary files /dev/null and b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/dto/UserWalletResponseDto$UserWalletResponseDtoBuilder.class differ
diff --git a/ebuka-ngene/user-service/target/classes/com/exquis/app/user/dto/UserWalletResponseDto.class b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/dto/UserWalletResponseDto.class
new file mode 100644
index 0000000..3e9b1ce
Binary files /dev/null and b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/dto/UserWalletResponseDto.class differ
diff --git a/ebuka-ngene/user-service/target/classes/com/exquis/app/user/dto/Wallet.class b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/dto/Wallet.class
new file mode 100644
index 0000000..b8f7d55
Binary files /dev/null and b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/dto/Wallet.class differ
diff --git a/ebuka-ngene/user-service/target/classes/com/exquis/app/user/entity/RecordStatus.class b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/entity/RecordStatus.class
new file mode 100644
index 0000000..9e4b8d6
Binary files /dev/null and b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/entity/RecordStatus.class differ
diff --git a/ebuka-ngene/user-service/target/classes/com/exquis/app/user/entity/Role.class b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/entity/Role.class
new file mode 100644
index 0000000..cd49058
Binary files /dev/null and b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/entity/Role.class differ
diff --git a/ebuka-ngene/user-service/target/classes/com/exquis/app/user/entity/User.class b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/entity/User.class
new file mode 100644
index 0000000..07c8919
Binary files /dev/null and b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/entity/User.class differ
diff --git a/ebuka-ngene/user-service/target/classes/com/exquis/app/user/enums/Gender.class b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/enums/Gender.class
new file mode 100644
index 0000000..2ef478b
Binary files /dev/null and b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/enums/Gender.class differ
diff --git a/ebuka-ngene/user-service/target/classes/com/exquis/app/user/enums/RoleType.class b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/enums/RoleType.class
new file mode 100644
index 0000000..8824101
Binary files /dev/null and b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/enums/RoleType.class differ
diff --git a/ebuka-ngene/user-service/target/classes/com/exquis/app/user/enums/StatusType.class b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/enums/StatusType.class
new file mode 100644
index 0000000..30556a1
Binary files /dev/null and b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/enums/StatusType.class differ
diff --git a/ebuka-ngene/user-service/target/classes/com/exquis/app/user/exception/HttpBadGatewayException.class b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/exception/HttpBadGatewayException.class
new file mode 100644
index 0000000..6a92835
Binary files /dev/null and b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/exception/HttpBadGatewayException.class differ
diff --git a/ebuka-ngene/user-service/target/classes/com/exquis/app/user/exception/HttpBadRequestException.class b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/exception/HttpBadRequestException.class
new file mode 100644
index 0000000..d26d5ea
Binary files /dev/null and b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/exception/HttpBadRequestException.class differ
diff --git a/ebuka-ngene/user-service/target/classes/com/exquis/app/user/exception/HttpNotFoundException.class b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/exception/HttpNotFoundException.class
new file mode 100644
index 0000000..228dd97
Binary files /dev/null and b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/exception/HttpNotFoundException.class differ
diff --git a/ebuka-ngene/user-service/target/classes/com/exquis/app/user/repository/UserRepository.class b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/repository/UserRepository.class
new file mode 100644
index 0000000..fe6b8c9
Binary files /dev/null and b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/repository/UserRepository.class differ
diff --git a/ebuka-ngene/user-service/target/classes/com/exquis/app/user/service/UserService.class b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/service/UserService.class
new file mode 100644
index 0000000..c5fa226
Binary files /dev/null and b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/service/UserService.class differ
diff --git a/ebuka-ngene/user-service/target/classes/com/exquis/app/user/service/contract/UserServiceContract.class b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/service/contract/UserServiceContract.class
new file mode 100644
index 0000000..53b36e7
Binary files /dev/null and b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/service/contract/UserServiceContract.class differ
diff --git a/ebuka-ngene/user-service/target/classes/com/exquis/app/user/utility/Dto.class b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/utility/Dto.class
new file mode 100644
index 0000000..c8f8d23
Binary files /dev/null and b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/utility/Dto.class differ
diff --git a/ebuka-ngene/user-service/target/classes/com/exquis/app/user/utility/Helper.class b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/utility/Helper.class
new file mode 100644
index 0000000..5b280f6
Binary files /dev/null and b/ebuka-ngene/user-service/target/classes/com/exquis/app/user/utility/Helper.class differ
diff --git a/ebuka-ngene/user-service/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/ebuka-ngene/user-service/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
new file mode 100644
index 0000000..e3ee9ca
--- /dev/null
+++ b/ebuka-ngene/user-service/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
@@ -0,0 +1,21 @@
+com/exquis/app/user/utility/Helper.class
+com/exquis/app/user/enums/Gender.class
+com/exquis/app/user/exception/HttpBadRequestException.class
+com/exquis/app/user/repository/UserRepository.class
+com/exquis/app/user/entity/RecordStatus.class
+com/exquis/app/user/exception/HttpBadGatewayException.class
+com/exquis/app/user/dto/RegisterUserRequestDto.class
+com/exquis/app/user/dto/Wallet.class
+com/exquis/app/user/entity/User.class
+com/exquis/app/user/controller/UserController.class
+com/exquis/app/user/enums/StatusType.class
+com/exquis/app/user/dto/UserWalletResponseDto$UserWalletResponseDtoBuilder.class
+com/exquis/app/user/UserServiceApplication.class
+com/exquis/app/user/utility/Dto.class
+com/exquis/app/user/enums/RoleType.class
+com/exquis/app/user/controller/RegistrationController.class
+com/exquis/app/user/exception/HttpNotFoundException.class
+com/exquis/app/user/entity/Role.class
+com/exquis/app/user/dto/UserWalletResponseDto.class
+com/exquis/app/user/service/contract/UserServiceContract.class
+com/exquis/app/user/service/UserService.class
diff --git a/ebuka-ngene/user-service/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/ebuka-ngene/user-service/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
new file mode 100644
index 0000000..e95049e
--- /dev/null
+++ b/ebuka-ngene/user-service/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
@@ -0,0 +1,14 @@
+/Users/chukwuebuka/Documents/personal/lightWeight/user-service/src/main/java/com/exquis/app/user/UserServiceApplication.java
+/Users/chukwuebuka/Documents/personal/lightWeight/user-service/src/main/java/com/exquis/app/user/enums/RoleType.java
+/Users/chukwuebuka/Documents/personal/lightWeight/user-service/src/main/java/com/exquis/app/user/enums/Gender.java
+/Users/chukwuebuka/Documents/personal/lightWeight/user-service/src/main/java/com/exquis/app/user/entity/Role.java
+/Users/chukwuebuka/Documents/personal/lightWeight/user-service/src/main/java/com/exquis/app/user/exception/HttpBadRequestException.java
+/Users/chukwuebuka/Documents/personal/lightWeight/user-service/src/main/java/com/exquis/app/user/enums/StatusType.java
+/Users/chukwuebuka/Documents/personal/lightWeight/user-service/src/main/java/com/exquis/app/user/entity/User.java
+/Users/chukwuebuka/Documents/personal/lightWeight/user-service/src/main/java/com/exquis/app/user/service/UserService.java
+/Users/chukwuebuka/Documents/personal/lightWeight/user-service/src/main/java/com/exquis/app/user/repository/UserRepository.java
+/Users/chukwuebuka/Documents/personal/lightWeight/user-service/src/main/java/com/exquis/app/user/utility/Dto.java
+/Users/chukwuebuka/Documents/personal/lightWeight/user-service/src/main/java/com/exquis/app/user/entity/RecordStatus.java
+/Users/chukwuebuka/Documents/personal/lightWeight/user-service/src/main/java/com/exquis/app/user/controller/UserController.java
+/Users/chukwuebuka/Documents/personal/lightWeight/user-service/src/main/java/com/exquis/app/user/exception/HttpNotFoundException.java
+/Users/chukwuebuka/Documents/personal/lightWeight/user-service/src/main/java/com/exquis/app/user/service/contract/UserServiceContract.java
diff --git a/ebuka-ngene/user-service/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst b/ebuka-ngene/user-service/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst
new file mode 100644
index 0000000..866f39e
--- /dev/null
+++ b/ebuka-ngene/user-service/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst
@@ -0,0 +1 @@
+com/exquis/app/user/UserServiceApplicationTests.class
diff --git a/ebuka-ngene/user-service/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst b/ebuka-ngene/user-service/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst
new file mode 100644
index 0000000..9f48df8
--- /dev/null
+++ b/ebuka-ngene/user-service/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst
@@ -0,0 +1 @@
+/Users/chukwuebuka/Documents/personal/lightWeight/user-service/src/test/java/com/exquis/app/user/UserServiceApplicationTests.java
diff --git a/ebuka-ngene/user-service/target/test-classes/com/exquis/app/user/UserServiceApplicationTests.class b/ebuka-ngene/user-service/target/test-classes/com/exquis/app/user/UserServiceApplicationTests.class
new file mode 100644
index 0000000..0ceffcd
Binary files /dev/null and b/ebuka-ngene/user-service/target/test-classes/com/exquis/app/user/UserServiceApplicationTests.class differ