diff --git a/README.md b/README.md index f809999..9e27864 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,5 @@ -# PiS-Hello -Business card holder app - -Timeline: -17.11 - 1 stage -13.12 - 2 stage -03.01 - 3 stage -24.01 - 4 stage +# Hello +Application for holding and sharing business cards ### Server @@ -110,7 +104,8 @@ npm start ``` After that, you can run the app on an android/iOS device emulator or directly on your mobile device using Expo Go app. -Links: +Useful links: * [Jira Board](https://hello-pis.atlassian.net/jira/software/projects/HPIS/boards/1) -* [CI documentation](https://circleci.com/docs/2.0/configuration-reference) -* [Documentation](https://www.overleaf.com/read/gyhnrhzrhfxw) +* [CI documentation](https://docs.github.com/en/actions) +* [ORM documentation](https://github.com/JetBrains/Exposed/wiki) +* [Project documentation](https://www.overleaf.com/read/gyhnrhzrhfxw) diff --git a/frontend/.expo-shared/assets.json b/application/.expo-shared/assets.json similarity index 100% rename from frontend/.expo-shared/assets.json rename to application/.expo-shared/assets.json diff --git a/frontend/.gitignore b/application/.gitignore similarity index 100% rename from frontend/.gitignore rename to application/.gitignore diff --git a/frontend/App.js b/application/App.js similarity index 88% rename from frontend/App.js rename to application/App.js index ecd3cc2..4152790 100644 --- a/frontend/App.js +++ b/application/App.js @@ -2,12 +2,9 @@ import React, { useState, useEffect } from 'react'; import { createStore, combineReducers, applyMiddleware } from 'redux'; import { Provider } from 'react-redux'; import * as Font from 'expo-font'; -import AppLoading from 'expo-app-loading'; import ReduxThunk from 'redux-thunk'; - -import { StyleSheet, SafeAreaView, View } from 'react-native'; +import { View } from 'react-native'; import AppNavigation from './navigation/AppNavigation'; - import authReducer from './reducers/auth'; import searchReducer from './reducers/search'; import businessCardsReducer from './reducers/businessCards'; @@ -50,7 +47,7 @@ export default function App() { if (!fontLoaded) { return ( - + ); } @@ -77,11 +74,3 @@ export default function App() { // ) // } } - -const styles = StyleSheet.create({ - root: { - flex: 1, - backgroundColor: '#F9FBFC' - } -}); - diff --git a/frontend/actions/auth.js b/application/actions/auth.js similarity index 94% rename from frontend/actions/auth.js rename to application/actions/auth.js index f4a2421..af56e76 100644 --- a/frontend/actions/auth.js +++ b/application/actions/auth.js @@ -54,11 +54,11 @@ export const signIn = (login, password) => { console.log(`response status: ${response.status}`); let token = null; - if(response.status == 200) { + if(response.status === 200) { const respData = await response.json(); token = respData.token; console.log(`Received token: ${token}`); - } else if (response.status == 403) { + } else if (response.status === 403) { console.log(`Request rejected. Wrong credentials.`); } else { console.log(`Request rejected for unknown reason.`); @@ -120,11 +120,11 @@ export const logInWithGoogle = googleToken => { console.log(`response status: ${second_response.status}`); let token = null; - if(first_response.status == 200) { + if(first_response.status === 200) { const respData = await second_response.json(); token = respData.token; console.log(`Received token: ${token}`); - } else if (first_response.status == 403) { + } else if (first_response.status === 403) { console.log(`Request rejected. Wrong credentials.`); } else { console.log(`Request rejected for unknown reason.`); @@ -138,7 +138,7 @@ export const register = (login, password, passwordRepeat) => { return async dispatch => { console.log('registering...'); - if (password != passwordRepeat) { + if (password !== passwordRepeat) { console.log('Passwords are not the same. Please try again.'); return dispatch({ type: REGISTER, outcome: null }); } @@ -172,10 +172,10 @@ export const register = (login, password, passwordRepeat) => { } console.log(`response status: ${response.status}`); - if(response.status == 201) { + if(response.status === 201) { console.log(`Registration successful!`); dispatch({ type: REGISTER, outcome: true }); - } else if (response.status == 409) { + } else if (response.status === 409) { console.log(`Request rejected. Wrong credentials. Try changing your login.`); dispatch({ type: REGISTER, outcome: false }); } else { @@ -192,10 +192,10 @@ export const checkLogin = (login) => { `http://${serverAddress.address}:8080/check?name=${login}` ); console.log(`response status: ${response.status}`); - if(response.status == 200) { + if(response.status === 200) { console.log(`Login available`); dispatch({ type: CHECK_LOGIN, outcome: true }); - } else if (response.status == 409) { + } else if (response.status === 409) { console.log(`User with this name already exists.`); dispatch({ type: CHECK_LOGIN, outcome: false }); } else { diff --git a/frontend/actions/businessCards.js b/application/actions/businessCards.js similarity index 92% rename from frontend/actions/businessCards.js rename to application/actions/businessCards.js index 542b054..8e66bb8 100644 --- a/frontend/actions/businessCards.js +++ b/application/actions/businessCards.js @@ -1,6 +1,4 @@ -import { SHA256 } from 'crypto-js'; - -import serverAddress from '../constants/serverAddress'; +import { serverAddress } from '../constants/serverAddress'; export const ADD_CARD = 'ADD_CARD'; @@ -57,7 +55,7 @@ export const addBusinessCard = (photo, ownerName) => { console.log(`response status: ${response.status}`); - const outcome = response.status === 201 ? true : false; + const outcome = response.status === 201; dispatch({ type: ADD_CARD, outcome: outcome }); } diff --git a/frontend/actions/edit.js b/application/actions/edit.js similarity index 89% rename from frontend/actions/edit.js rename to application/actions/edit.js index 06f37fd..e143021 100644 --- a/frontend/actions/edit.js +++ b/application/actions/edit.js @@ -22,7 +22,7 @@ async function fetchWithTimeout(resource, options = {}) { } }; -export const editCardData = (idU, company, name, phone, email, category, mode) => { +export const setCardData = (idU, company, name, phone, email, category, mode) => { return async dispatch => { const id = parseInt(idU); @@ -33,7 +33,7 @@ export const editCardData = (idU, company, name, phone, email, category, mode) = try { response = await fetchWithTimeout( - `http://${serverAddress.address}:8080/card/changedata`, + `http://${serverAddress.address}:8080/card/set`, { method: 'POST', headers: { @@ -60,10 +60,10 @@ export const editCardData = (idU, company, name, phone, email, category, mode) = } console.log(`Response status: ${response.status}`); - if(response.status == 200) { + if(response.status === 200) { console.log(`Update data successfully`); dispatch({ type: EDIT_DATA, outcome: true }); - } else if (response.status == 404) { + } else if (response.status === 404) { console.log(`Request rejected. Wrong credentials.`); dispatch({ type: EDIT_DATA, outcome: false }); } else { diff --git a/frontend/actions/search.js b/application/actions/search.js similarity index 94% rename from frontend/actions/search.js rename to application/actions/search.js index e77bfcd..fef5053 100644 --- a/frontend/actions/search.js +++ b/application/actions/search.js @@ -37,9 +37,9 @@ export const getMyBusinessCards = (username) => { console.log(`response status: ${response.status}`); var respData = []; - if(response.status == 200) { + if(response.status === 200) { respData = await response.json(); - } else if (response.status == 404) { + } else if (response.status === 404) { console.log(`No business cards found.`); } else { console.log(`Request rejected for unknown reason.`); @@ -80,9 +80,9 @@ export const searchBusinessCards = ({id=null, profession=null, ownername=null}) console.log(`response status: ${response.status}`); var respData = []; - if(response.status == 200) { + if(response.status === 200) { respData = await response.json(); - } else if (response.status == 404) { + } else if (response.status === 404) { console.log(`No business cards found.`); } else { console.log(`Request rejected for unknown reason.`); diff --git a/frontend/app.json b/application/app.json similarity index 95% rename from frontend/app.json rename to application/app.json index 6df1bf4..758f59d 100644 --- a/frontend/app.json +++ b/application/app.json @@ -33,7 +33,7 @@ "foregroundImage": "./assets/business-card.png", "backgroundColor": "#FFFFFF" }, - "package": "com.pishello.hellopis" + "package": "com.hello.hello" }, "web": { "favicon": "./assets/business-card.png" diff --git a/frontend/assets/adaptive-icon.png b/application/assets/adaptive-icon.png similarity index 100% rename from frontend/assets/adaptive-icon.png rename to application/assets/adaptive-icon.png diff --git a/frontend/assets/business-card.png b/application/assets/business-card.png similarity index 100% rename from frontend/assets/business-card.png rename to application/assets/business-card.png diff --git a/frontend/assets/favicon.png b/application/assets/favicon.png similarity index 100% rename from frontend/assets/favicon.png rename to application/assets/favicon.png diff --git a/frontend/assets/fonts/OpenSans-Bold.ttf b/application/assets/fonts/OpenSans-Bold.ttf similarity index 100% rename from frontend/assets/fonts/OpenSans-Bold.ttf rename to application/assets/fonts/OpenSans-Bold.ttf diff --git a/frontend/assets/fonts/OpenSans-Regular.ttf b/application/assets/fonts/OpenSans-Regular.ttf similarity index 100% rename from frontend/assets/fonts/OpenSans-Regular.ttf rename to application/assets/fonts/OpenSans-Regular.ttf diff --git a/frontend/assets/fonts/Roboto-Medium.ttf b/application/assets/fonts/Roboto-Medium.ttf similarity index 100% rename from frontend/assets/fonts/Roboto-Medium.ttf rename to application/assets/fonts/Roboto-Medium.ttf diff --git a/frontend/assets/fonts/roboto.zip b/application/assets/fonts/roboto.zip similarity index 100% rename from frontend/assets/fonts/roboto.zip rename to application/assets/fonts/roboto.zip diff --git a/frontend/assets/google-logo.png b/application/assets/google-logo.png similarity index 100% rename from frontend/assets/google-logo.png rename to application/assets/google-logo.png diff --git a/frontend/assets/gradient.png b/application/assets/gradient.png similarity index 100% rename from frontend/assets/gradient.png rename to application/assets/gradient.png diff --git a/frontend/assets/icon.png b/application/assets/icon.png similarity index 100% rename from frontend/assets/icon.png rename to application/assets/icon.png diff --git a/frontend/assets/purple-bg.jpg b/application/assets/purple-bg.jpg similarity index 100% rename from frontend/assets/purple-bg.jpg rename to application/assets/purple-bg.jpg diff --git a/frontend/assets/splash.png b/application/assets/splash.png similarity index 100% rename from frontend/assets/splash.png rename to application/assets/splash.png diff --git a/frontend/babel.config.js b/application/babel.config.js similarity index 100% rename from frontend/babel.config.js rename to application/babel.config.js diff --git a/frontend/components/Card.js b/application/components/Card.js similarity index 100% rename from frontend/components/Card.js rename to application/components/Card.js diff --git a/frontend/components/GoogleSignInButton.js b/application/components/GoogleSignInButton.js similarity index 100% rename from frontend/components/GoogleSignInButton.js rename to application/components/GoogleSignInButton.js diff --git a/frontend/components/LoadingScreenModal.js b/application/components/LoadingScreenModal.js similarity index 93% rename from frontend/components/LoadingScreenModal.js rename to application/components/LoadingScreenModal.js index 61df0ed..900acff 100644 --- a/frontend/components/LoadingScreenModal.js +++ b/application/components/LoadingScreenModal.js @@ -14,7 +14,3 @@ export default function LoadingScreenModal({amIVisible}){ ); }; - -const styles = StyleSheet.create({ - -}) \ No newline at end of file diff --git a/frontend/components/MenuItem.js b/application/components/MenuItem.js similarity index 100% rename from frontend/components/MenuItem.js rename to application/components/MenuItem.js diff --git a/frontend/components/OverscreenModal.js b/application/components/OverscreenModal.js similarity index 100% rename from frontend/components/OverscreenModal.js rename to application/components/OverscreenModal.js diff --git a/frontend/navigation/AppNavigation.js b/application/navigation/AppNavigation.js similarity index 100% rename from frontend/navigation/AppNavigation.js rename to application/navigation/AppNavigation.js diff --git a/frontend/navigation/futureAppNavigator.js b/application/navigation/futureAppNavigator.js similarity index 100% rename from frontend/navigation/futureAppNavigator.js rename to application/navigation/futureAppNavigator.js diff --git a/frontend/package.json b/application/package.json similarity index 98% rename from frontend/package.json rename to application/package.json index 305620b..f207b9e 100644 --- a/frontend/package.json +++ b/application/package.json @@ -1,5 +1,5 @@ { - "name": "pis-front", + "name": "hello", "version": "1.0.0", "main": "node_modules/expo/AppEntry.js", "scripts": { diff --git a/frontend/reducers/auth.js b/application/reducers/auth.js similarity index 100% rename from frontend/reducers/auth.js rename to application/reducers/auth.js diff --git a/frontend/reducers/businessCards.js b/application/reducers/businessCards.js similarity index 100% rename from frontend/reducers/businessCards.js rename to application/reducers/businessCards.js diff --git a/frontend/reducers/edit.js b/application/reducers/edit.js similarity index 100% rename from frontend/reducers/edit.js rename to application/reducers/edit.js diff --git a/frontend/reducers/search.js b/application/reducers/search.js similarity index 100% rename from frontend/reducers/search.js rename to application/reducers/search.js diff --git a/frontend/screens/CameraScreen.js b/application/screens/CameraScreen.js similarity index 99% rename from frontend/screens/CameraScreen.js rename to application/screens/CameraScreen.js index c6f59c3..7736ffd 100644 --- a/frontend/screens/CameraScreen.js +++ b/application/screens/CameraScreen.js @@ -2,7 +2,6 @@ import React, { useEffect, useState } from 'react'; import { View, StyleSheet, Text, Image, Alert, TouchableOpacity, Dimensions } from 'react-native'; import { Camera } from 'expo-camera'; import { AntDesign } from '@expo/vector-icons'; -import * as ScreenOrientation from 'expo-screen-orientation'; import * as businessCardsActions from '../actions/businessCards'; import LoadingScreenModal from '../components/LoadingScreenModal'; import OverscreenModal from '../components/OverscreenModal'; diff --git a/frontend/screens/EditCardScreen.js b/application/screens/EditCardScreen.js similarity index 91% rename from frontend/screens/EditCardScreen.js rename to application/screens/EditCardScreen.js index 82cac72..b7a0a3a 100644 --- a/frontend/screens/EditCardScreen.js +++ b/application/screens/EditCardScreen.js @@ -1,14 +1,10 @@ -import React, {useDebugValue, useEffect, useState} from 'react'; -import { View, StyleSheet, Text, TextInput, Image, useWindowDimensions, ScrollView, ImageBackground, Pressable, TouchableOpacity, Button } from 'react-native'; -import GoogleSignInButton from '../components/GoogleSignInButton'; -import { CommonActions, useNavigation, useRoute} from '@react-navigation/core'; +import React, {useEffect, useState} from 'react'; +import { View, StyleSheet, Text, TextInput, Image, TouchableOpacity } from 'react-native'; import Card from '../components/Card'; import OverscreenModal from '../components/OverscreenModal'; import LoadingScreenModal from '../components/LoadingScreenModal'; -import backgroundImage from '../assets/purple-bg.jpg'; import purple from '../assets/gradient.png'; import { useDispatch, useSelector } from 'react-redux'; -import { logInAsync } from 'expo-google-app-auth'; import * as authActions from '../actions/edit'; export default function EditCardScreen({ route, navigation }) { @@ -36,7 +32,7 @@ export default function EditCardScreen({ route, navigation }) { return; if (editOutcome == null) return; - if (editOutcome == true) + if (editOutcome === true) { dispatch(authActions.editFinished()); navigation.navigate('HomeScreen'); @@ -46,10 +42,10 @@ export default function EditCardScreen({ route, navigation }) { }, [editResponse]); - const onChangeDataPressed = async () => { + const onSetDataPressed = async () => { setWaitingForResponse(true); - dispatch(authActions.editCardData(photoId, company, name, phone, email, category, mode)); + dispatch(authActions.setCardData(photoId, company, name, phone, email, category, mode)); } const onReturnPressed = () => { @@ -57,7 +53,7 @@ export default function EditCardScreen({ route, navigation }) { } function onChangeModePressed () { - if (mode == 'PRIVATE') { + if (mode === 'PRIVATE') { setMode('PUBLIC') } else{ @@ -139,7 +135,7 @@ export default function EditCardScreen({ route, navigation }) { - + Wprowadź zmiany diff --git a/frontend/screens/GalleryScreen.js b/application/screens/GalleryScreen.js similarity index 97% rename from frontend/screens/GalleryScreen.js rename to application/screens/GalleryScreen.js index 1b8daf1..0ad319e 100644 --- a/frontend/screens/GalleryScreen.js +++ b/application/screens/GalleryScreen.js @@ -1,5 +1,5 @@ import React, {useEffect, useState} from 'react'; -import {Button, View, StyleSheet, Image, Dimensions, TouchableOpacity, Text, Alert} from 'react-native'; +import { View, StyleSheet, Image, TouchableOpacity, Alert } from 'react-native'; import { useNavigation } from '@react-navigation/core'; import { useDispatch, useSelector } from 'react-redux'; import * as ImagePicker from 'expo-image-picker'; @@ -7,7 +7,6 @@ import {AntDesign} from "@expo/vector-icons"; import LoadingScreenModal from "../components/LoadingScreenModal"; import OverscreenModal from "../components/OverscreenModal"; import * as businessCardsActions from "../actions/businessCards"; -import {Camera} from "expo-camera"; export default function GalleryScreen() { const navigation = useNavigation(); diff --git a/frontend/screens/HomeScreen.js b/application/screens/HomeScreen.js similarity index 94% rename from frontend/screens/HomeScreen.js rename to application/screens/HomeScreen.js index 21b5042..3e55b39 100644 --- a/frontend/screens/HomeScreen.js +++ b/application/screens/HomeScreen.js @@ -1,8 +1,8 @@ import { StatusBar } from 'expo-status-bar'; -import React, { useState, useEffect } from 'react'; +import React from 'react'; import { StyleSheet, Text, View, ScrollView } from 'react-native'; import { useNavigation } from '@react-navigation/core'; -import { useSelector, useDispatch } from 'react-redux'; +import { useSelector } from 'react-redux'; import MenuItem from '../components/MenuItem'; export default function HomeScreen() { diff --git a/frontend/screens/MyBusinessCardsScreen.js b/application/screens/MyBusinessCardsScreen.js similarity index 99% rename from frontend/screens/MyBusinessCardsScreen.js rename to application/screens/MyBusinessCardsScreen.js index d0e6532..a88fc80 100644 --- a/frontend/screens/MyBusinessCardsScreen.js +++ b/application/screens/MyBusinessCardsScreen.js @@ -23,7 +23,7 @@ const MyBusinessCardsScreen = props => { await dispatch(searchActions.getMyBusinessCards(username)); console.log(`Fetched my business cards`); setWaitingForResponse(false); - }; + } useEffect(() => { if (getMyCardsTimestamp === undefined) diff --git a/frontend/screens/SearchBusinessCardsScreen.js b/application/screens/SearchBusinessCardsScreen.js similarity index 97% rename from frontend/screens/SearchBusinessCardsScreen.js rename to application/screens/SearchBusinessCardsScreen.js index 1b375dd..805671f 100644 --- a/frontend/screens/SearchBusinessCardsScreen.js +++ b/application/screens/SearchBusinessCardsScreen.js @@ -1,9 +1,8 @@ import React, { useEffect, useState } from 'react'; -import { View, StyleSheet, Text, Image, TouchableOpacity, ImageBackground, Dimensions, FlatList, TextInput } from 'react-native'; +import { View, StyleSheet, Text, Image, TouchableOpacity, FlatList, TextInput } from 'react-native'; import { AntDesign } from '@expo/vector-icons'; import { useNavigation } from '@react-navigation/core'; import { useSelector, useDispatch } from 'react-redux'; -// import * as ScreenOrientation from 'expo-screen-orientation'; import * as searchActions from '../actions/search'; import serverAddress from '../constants/serverAddress'; import LoadingScreenModal from '../components/LoadingScreenModal'; @@ -179,10 +178,9 @@ const styles = StyleSheet.create({ }, searchBar: { flexGrow: 1, - backgroundColor: 'magenta', + backgroundColor: 'white', borderRadius: 10, marginHorizontal: 5, - backgroundColor: 'white', elevation: 3, padding: 10, fontSize: 18, diff --git a/frontend/screens/login/RegisterScreen.js b/application/screens/login/RegisterScreen.js similarity index 97% rename from frontend/screens/login/RegisterScreen.js rename to application/screens/login/RegisterScreen.js index dd43ea6..09ba355 100644 --- a/frontend/screens/login/RegisterScreen.js +++ b/application/screens/login/RegisterScreen.js @@ -1,9 +1,8 @@ import React, { useEffect, useState } from 'react'; -import { View, StyleSheet, Text, TextInput, ScrollView, Image, ImageBackground, TouchableOpacity, StatusBar } from 'react-native'; +import { View, StyleSheet, Text, TextInput, ScrollView, Image, TouchableOpacity, StatusBar } from 'react-native'; import { useSelector, useDispatch } from 'react-redux'; import { useNavigation } from '@react-navigation/core'; import gradient from '../../assets/purple-bg.jpg'; -import purple from '../../assets/gradient.png'; import Card from '../../components/Card'; import OverscreenModal from '../../components/OverscreenModal'; import LoadingScreenModal from '../../components/LoadingScreenModal'; @@ -27,7 +26,7 @@ export default function RegisterScreen() { setWaitingForResponse(false); if (registerResponse == null) return; - if (registerOutcome == true) + if (registerOutcome === true) setSuccessModalVisible(true); else setFailureModalVisible(true); diff --git a/frontend/screens/login/SignInScreen.js b/application/screens/login/SignInScreen.js similarity index 97% rename from frontend/screens/login/SignInScreen.js rename to application/screens/login/SignInScreen.js index 3774df9..ac14dc2 100644 --- a/frontend/screens/login/SignInScreen.js +++ b/application/screens/login/SignInScreen.js @@ -1,4 +1,4 @@ -import React, {useDebugValue, useEffect, useState} from 'react'; +import React, {useEffect, useState} from 'react'; import { View, StyleSheet, Text, TextInput, Image, TouchableOpacity } from 'react-native'; import { StatusBar } from 'expo-status-bar'; import GoogleSignInButton from '../../components/GoogleSignInButton'; @@ -7,9 +7,7 @@ import Card from '../../components/Card'; import OverscreenModal from '../../components/OverscreenModal'; import LoadingScreenModal from '../../components/LoadingScreenModal'; import backgroundImage from '../../assets/purple-bg.jpg'; -import purple from '../../assets/gradient.png'; import { useDispatch, useSelector } from 'react-redux'; -import { logInAsync } from 'expo-google-app-auth'; import * as authActions from '../../actions/auth'; export default function SignInScreen() { diff --git a/commit-msg b/commit-msg index fe0e6d9..64ffb62 100644 --- a/commit-msg +++ b/commit-msg @@ -2,12 +2,12 @@ # To enable this hook, copy locally this file and move to ".git/hooks/commit-msg". export MESSAGE=$(<$1) -export JIRA_ISSUE_TAG='HPIS-([0-9]*)' +export GITHUB_ISSUE_TAG='HELL-([0-9]*)' -if [[ $MESSAGE =~ $JIRA_ISSUE_TAG ]]; then - echo -e "\e[32mYes! It contains a JIRA issue!\e[0m" +if [[ $MESSAGE =~ GITHUB_ISSUE_TAG ]]; then + echo -e "\e[32mYes! It contains a GitHub issue!\e[0m" exit 0; fi -echo -e "\e[31mOh no... You forgot to add a JIRA issue number!\e[0m"; +echo -e "\e[31mOh no... You forgot to add a GitHub issue number!\e[0m"; exit 1; \ No newline at end of file diff --git a/frontend/constants/Colors.js b/frontend/constants/Colors.js deleted file mode 100644 index 0624c4e..0000000 --- a/frontend/constants/Colors.js +++ /dev/null @@ -1,4 +0,0 @@ -export default { - primary: '#C2185B', - accent: '#FFC107' -}; \ No newline at end of file diff --git a/server/build.gradle.kts b/server/build.gradle.kts index 9a6b610..93883fa 100644 --- a/server/build.gradle.kts +++ b/server/build.gradle.kts @@ -13,7 +13,7 @@ plugins { jacoco } -group = "pis-hello" +group = "hello" version = "0.0.1-SNAPSHOT" java.sourceCompatibility = JavaVersion.VERSION_11 @@ -25,11 +25,15 @@ dependencies { val springBootVersion = "2.6.2" val jacocoVersion = "0.8.7" val sqliteJDBCVersion = "3.36.0.2" + val exposedVersion = "0.37.3" implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.jetbrains.exposed:exposed-core:$exposedVersion") + implementation("org.jetbrains.exposed:exposed-dao:$exposedVersion") + implementation("org.jetbrains.exposed:exposed-jdbc:$exposedVersion") + implementation("org.jetbrains.exposed:exposed-java-time:$exposedVersion") implementation("org.springframework.boot:spring-boot-starter:$springBootVersion") - implementation("org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion") implementation("org.springframework.boot:spring-boot-starter-web:$springBootVersion") implementation("org.xerial:sqlite-jdbc:$sqliteJDBCVersion") implementation("org.jacoco:org.jacoco.core:$jacocoVersion") diff --git a/server/src/main/kotlin/pishello/hello/HelloApplication.kt b/server/src/main/kotlin/hello/hello/HelloApplication.kt similarity index 55% rename from server/src/main/kotlin/pishello/hello/HelloApplication.kt rename to server/src/main/kotlin/hello/hello/HelloApplication.kt index 68d1205..0272139 100644 --- a/server/src/main/kotlin/pishello/hello/HelloApplication.kt +++ b/server/src/main/kotlin/hello/hello/HelloApplication.kt @@ -1,5 +1,6 @@ -package pishello.hello +package hello.hello +import hello.hello.adapters.persistence.database.init import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.runApplication @@ -7,5 +8,6 @@ import org.springframework.boot.runApplication class HelloApplication fun main(args: Array) { - runApplication(*args) + val context = runApplication(*args) + init(context.environment) } diff --git a/server/src/main/kotlin/pishello/hello/api/AuthEndpoint.kt b/server/src/main/kotlin/hello/hello/adapters/api/AuthEndpoint.kt similarity index 68% rename from server/src/main/kotlin/pishello/hello/api/AuthEndpoint.kt rename to server/src/main/kotlin/hello/hello/adapters/api/AuthEndpoint.kt index 578a103..abaf0cb 100644 --- a/server/src/main/kotlin/pishello/hello/api/AuthEndpoint.kt +++ b/server/src/main/kotlin/hello/hello/adapters/api/AuthEndpoint.kt @@ -1,16 +1,21 @@ -package pishello.hello.api +package hello.hello.adapters.api import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.* -import pishello.hello.persistence.database.entities.Token -import pishello.hello.persistence.database.ports.TokenPort -import pishello.hello.persistence.database.ports.UserPort +import hello.hello.adapters.persistence.database.adapters.TokenAdapter +import hello.hello.adapters.persistence.database.adapters.UserAdapter +import hello.hello.domain.models.Token +import hello.hello.domain.ports.TokenPort +import hello.hello.domain.ports.UserPort data class LoginRequest(val name: String, val password: String) @RestController -class AuthEndpoint(val userPort: UserPort, val tokenPort: TokenPort) { +class AuthEndpoint { + val userPort: UserPort = UserAdapter() + val tokenPort: TokenPort = TokenAdapter() + @GetMapping("/check") fun check(@RequestParam name: String): ResponseEntity { return if (userPort.checkIfUserExists(name)) { @@ -22,7 +27,7 @@ class AuthEndpoint(val userPort: UserPort, val tokenPort: TokenPort) { @PostMapping("/register", consumes = ["application/json"]) fun register(@RequestBody request: LoginRequest): ResponseEntity { return if (!userPort.checkIfUserExists(request.name)) { - userPort.createNewUser(request.name, request.password) + userPort.create(request.name, request.password) ResponseEntity(HttpStatus.CREATED) } else ResponseEntity(HttpStatus.CONFLICT) @@ -32,7 +37,7 @@ class AuthEndpoint(val userPort: UserPort, val tokenPort: TokenPort) { fun login(@RequestBody request: LoginRequest): ResponseEntity { val user = userPort.checkLogin(request.name, request.password) return if (user != null) { - val token = tokenPort.createNewToken(user) + val token = tokenPort.create(user) ResponseEntity(token, HttpStatus.OK) } else ResponseEntity(HttpStatus.FORBIDDEN) @@ -41,12 +46,12 @@ class AuthEndpoint(val userPort: UserPort, val tokenPort: TokenPort) { @PostMapping("/loginWithGoogle", consumes = ["application/json"]) fun google(@RequestBody request: LoginRequest): ResponseEntity { return if (!userPort.checkIfUserExists(request.name)) { - val user = userPort.createNewUser(request.name, request.password) - ResponseEntity(tokenPort.createNewToken(user), HttpStatus.OK) + val user = userPort.create(request.name, request.password) + ResponseEntity(tokenPort.create(user), HttpStatus.OK) } else { val user = userPort.checkLogin(request.name, request.password) if (user != null) { - ResponseEntity(tokenPort.createNewToken(user), HttpStatus.OK) + ResponseEntity(tokenPort.create(user), HttpStatus.OK) } else ResponseEntity(HttpStatus.FORBIDDEN) } diff --git a/server/src/main/kotlin/hello/hello/adapters/api/CardEndpoint.kt b/server/src/main/kotlin/hello/hello/adapters/api/CardEndpoint.kt new file mode 100644 index 0000000..3685bc3 --- /dev/null +++ b/server/src/main/kotlin/hello/hello/adapters/api/CardEndpoint.kt @@ -0,0 +1,61 @@ +package hello.hello.adapters.api + +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.* +import org.springframework.web.multipart.MultipartFile +import hello.hello.adapters.persistence.cloudStorage.PhotosStorage +import hello.hello.adapters.persistence.database.adapters.CardAdapter +import hello.hello.domain.ports.CardPort + +data class SetCardRequest(val id: Int, val company: String?, val name: String?, val phone: String?, val email: String?, val category: String?, val mode: String?) + +@RestController +@RequestMapping("/card") +class CardEndpoint(val photosStorage: PhotosStorage) { + val cardPort: CardPort = CardAdapter() + + @PostMapping + fun putCard(@RequestParam image: MultipartFile, @RequestParam ownerName: String): ResponseEntity { + val card = cardPort.create(ownerName, "PRIVATE", null) + return if (card != null) { + photosStorage.writeImage("cards/${card.id}.jpg", image.bytes) + cardPort.updatePath(card, "cards/${card.id}.jpg") + ResponseEntity(HttpStatus.CREATED) + } else { + ResponseEntity(HttpStatus.NOT_FOUND) + } + } + + @GetMapping("/image", produces = [MediaType.IMAGE_JPEG_VALUE]) + fun getImage(@RequestParam id: Int): ResponseEntity { + val result = cardPort.read(id) + return if (result?.path != null) { + val image = photosStorage.readImage(result.path!!) + return if (image != null) { + ResponseEntity(image, HttpStatus.OK) + } else { + ResponseEntity(HttpStatus.NOT_FOUND) + } + } else { + ResponseEntity(HttpStatus.NOT_FOUND) + } + } + + @PostMapping("/set", consumes = ["application/json"]) + fun setCard(@RequestBody request: SetCardRequest): ResponseEntity { + val company: String? = request.company?.ifBlank { null } + val name: String? = request.name?.ifBlank { null } + val phone: String? = request.phone?.ifBlank { null } + val email: String? = request.email?.ifBlank { null } + val category: String? = request.category?.ifBlank { null } + val mode: String? = request.mode?.ifBlank { null } + + return if (cardPort.update(request.id, company, name, phone, email, category, mode) != null) { + ResponseEntity(HttpStatus.OK) + } else { + ResponseEntity(HttpStatus.NOT_FOUND) + } + } +} \ No newline at end of file diff --git a/server/src/main/kotlin/pishello/hello/api/RootEndpoint.kt b/server/src/main/kotlin/hello/hello/adapters/api/RootEndpoint.kt similarity index 86% rename from server/src/main/kotlin/pishello/hello/api/RootEndpoint.kt rename to server/src/main/kotlin/hello/hello/adapters/api/RootEndpoint.kt index a6e5f12..3ca3d5b 100644 --- a/server/src/main/kotlin/pishello/hello/api/RootEndpoint.kt +++ b/server/src/main/kotlin/hello/hello/adapters/api/RootEndpoint.kt @@ -1,4 +1,4 @@ -package pishello.hello.api +package hello.hello.adapters.api import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RestController diff --git a/server/src/main/kotlin/pishello/hello/api/SearchEndpoint.kt b/server/src/main/kotlin/hello/hello/adapters/api/SearchEndpoint.kt similarity index 58% rename from server/src/main/kotlin/pishello/hello/api/SearchEndpoint.kt rename to server/src/main/kotlin/hello/hello/adapters/api/SearchEndpoint.kt index 27fefdc..4bb5a78 100644 --- a/server/src/main/kotlin/pishello/hello/api/SearchEndpoint.kt +++ b/server/src/main/kotlin/hello/hello/adapters/api/SearchEndpoint.kt @@ -1,17 +1,19 @@ -package pishello.hello.api +package hello.hello.adapters.api import org.springframework.http.HttpStatus -import org.springframework.http.MediaType import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.* -import pishello.hello.persistence.database.entities.Card -import pishello.hello.persistence.database.ports.CardPort +import hello.hello.adapters.persistence.database.adapters.CardAdapter +import hello.hello.domain.models.Card +import hello.hello.domain.ports.CardPort @RestController -class SearchEndpoint(val searchPort: CardPort) { +class SearchEndpoint { + val cardPort: CardPort = CardAdapter() + @GetMapping("/search") - fun search(@RequestParam id: Int?, @RequestParam profession: String?, @RequestParam ownername: String?): ResponseEntity> { - val result = searchPort.searchCards(id, profession, ownername) + fun search(@RequestParam id: Int?, @RequestParam profession: String?, @RequestParam ownername: String?): ResponseEntity> { + val result = cardPort.search(id, profession, ownername) return if (result != null) { ResponseEntity(result, HttpStatus.OK) } else @@ -19,8 +21,8 @@ class SearchEndpoint(val searchPort: CardPort) { } @GetMapping("/{user}/cards") - fun getUserCards(@PathVariable user: String?): ResponseEntity> { - val result = searchPort.searchOwnerCards(ownerName = user) + fun getUserCards(@PathVariable user: String?): ResponseEntity> { + val result = cardPort.read(ownerName = user) return if (result != null) { ResponseEntity(result, HttpStatus.OK) } else diff --git a/server/src/main/kotlin/pishello/hello/persistence/cloudStorage/PhotosStorage.kt b/server/src/main/kotlin/hello/hello/adapters/persistence/cloudStorage/PhotosStorage.kt similarity index 97% rename from server/src/main/kotlin/pishello/hello/persistence/cloudStorage/PhotosStorage.kt rename to server/src/main/kotlin/hello/hello/adapters/persistence/cloudStorage/PhotosStorage.kt index eef1f05..8fb85fd 100644 --- a/server/src/main/kotlin/pishello/hello/persistence/cloudStorage/PhotosStorage.kt +++ b/server/src/main/kotlin/hello/hello/adapters/persistence/cloudStorage/PhotosStorage.kt @@ -1,4 +1,4 @@ -package pishello.hello.persistence.cloudStorage +package hello.hello.adapters.persistence.cloudStorage import com.google.auth.Credentials import com.google.auth.oauth2.GoogleCredentials diff --git a/server/src/main/kotlin/hello/hello/adapters/persistence/database/DatabaseUtilities.kt b/server/src/main/kotlin/hello/hello/adapters/persistence/database/DatabaseUtilities.kt new file mode 100644 index 0000000..c297f5b --- /dev/null +++ b/server/src/main/kotlin/hello/hello/adapters/persistence/database/DatabaseUtilities.kt @@ -0,0 +1,35 @@ +package hello.hello.adapters.persistence.database + +import hello.hello.adapters.persistence.database.entities.CardTable +import hello.hello.adapters.persistence.database.entities.TokenTable +import hello.hello.adapters.persistence.database.entities.UserTable +import org.jetbrains.exposed.sql.Database +import org.jetbrains.exposed.sql.SchemaUtils +import org.jetbrains.exposed.sql.transactions.TransactionManager +import org.jetbrains.exposed.sql.transactions.transaction +import org.springframework.core.env.Environment +import java.sql.Connection + +fun init(env: Environment) { + TransactionManager.defaultDatabase = Database.connect( + env.getRequiredProperty("spring.datasource.url"), + env.getRequiredProperty("spring.datasource.driver-class-name") + ) + TransactionManager.manager.defaultIsolationLevel = Connection.TRANSACTION_SERIALIZABLE +} + +fun create() { + transaction { + SchemaUtils.create(UserTable) + SchemaUtils.create(TokenTable) + SchemaUtils.create(CardTable) + } +} + +fun drop() { + transaction { + SchemaUtils.drop(UserTable) + SchemaUtils.drop(TokenTable) + SchemaUtils.drop(CardTable) + } +} \ No newline at end of file diff --git a/server/src/main/kotlin/hello/hello/adapters/persistence/database/adapters/CardAdapter.kt b/server/src/main/kotlin/hello/hello/adapters/persistence/database/adapters/CardAdapter.kt new file mode 100644 index 0000000..b03efc0 --- /dev/null +++ b/server/src/main/kotlin/hello/hello/adapters/persistence/database/adapters/CardAdapter.kt @@ -0,0 +1,72 @@ +package hello.hello.adapters.persistence.database.adapters + +import hello.hello.adapters.persistence.database.adapters.UserAdapter.Companion.findByName +import hello.hello.adapters.persistence.database.entities.CardEntity +import hello.hello.adapters.persistence.database.entities.CardTable +import hello.hello.adapters.persistence.database.entities.toCard +import hello.hello.adapters.persistence.database.entities.toCardEntity +import hello.hello.domain.models.Card +import hello.hello.domain.ports.CardPort +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.and +import org.jetbrains.exposed.sql.transactions.transaction + +class CardAdapter: CardPort() { + + private fun search(cardId: Int): List = + CardEntity.find { (CardTable.id eq cardId) and (CardTable.mode eq "PUBLIC") }.toList().map { it.toCard() } + + private fun search(profession: String): List = + CardEntity.find { (CardTable.category eq profession) and (CardTable.mode eq "PUBLIC") }.toList().map { it.toCard() } + + private fun search(ownerId: EntityID): List = + CardEntity.find { (CardTable.owner eq ownerId) and (CardTable.mode eq "PUBLIC") }.toList().map { it.toCard() } + + private fun find(ownerId: EntityID): List = + CardEntity.find { CardTable.owner eq ownerId }.toList().map { it.toCard() } + + override fun create(userName: String, mode: String, category: String?): Card? = + transaction { + val owner = findByName(userName) ?: return@transaction null + CardEntity.new { + this.mode = mode + this.category = category + this.owner = owner + }.toCard() + } + + override fun read(cardId: Int): Card? = + transaction { CardEntity.findById(cardId)?.toCard() } + + override fun read(ownerName: String?): List? = + transaction { ownerName?.let { findByName(ownerName)?.let { find(it.id) } } } + + override fun search(id: Int?, profession: String?, ownerName: String?): List? = + transaction { + when { + id != null -> search(id) + profession != null -> search(profession) + ownerName != null -> findByName(ownerName)?.let { search(it.id) } ?: emptyList() + else -> null + } + } + + override fun update(id: Int, company: String?, name: String?, phone: String?, email: String?, category: String?, mode: String?): Card? = + transaction { + val cardEntity = CardEntity.findById(id) ?: return@transaction null + mode?.let { cardEntity.mode = it } + company?.let { cardEntity.company = it } + name?.let { cardEntity.name = it } + phone?.let { cardEntity.phone = it } + email?.let { cardEntity.email = it } + category?.let { cardEntity.category = it } + cardEntity.toCard() + } + + override fun updatePath(card: Card, path: String): Card = + transaction { + val cardEntity = card.toCardEntity() + cardEntity.path = path + cardEntity.toCard() + } +} \ No newline at end of file diff --git a/server/src/main/kotlin/hello/hello/adapters/persistence/database/adapters/TokenAdapter.kt b/server/src/main/kotlin/hello/hello/adapters/persistence/database/adapters/TokenAdapter.kt new file mode 100644 index 0000000..ba47692 --- /dev/null +++ b/server/src/main/kotlin/hello/hello/adapters/persistence/database/adapters/TokenAdapter.kt @@ -0,0 +1,24 @@ +package hello.hello.adapters.persistence.database.adapters + +import hello.hello.adapters.persistence.database.entities.TokenEntity +import hello.hello.adapters.persistence.database.entities.TokenTable +import hello.hello.adapters.persistence.database.entities.toToken +import hello.hello.adapters.persistence.database.entities.toUserEntity +import hello.hello.domain.models.Token +import hello.hello.domain.models.User +import hello.hello.domain.ports.TokenPort +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.sql.transactions.transaction +import java.time.Instant +import java.util.* + +class TokenAdapter: TokenPort() { + override fun create(user: User): Token = + transaction { + TokenEntity.new { + this.token = EntityID(UUID.randomUUID().toString(), TokenTable) + this.name = user.toUserEntity() + this.creationDate = Instant.now() + }.toToken() + } +} \ No newline at end of file diff --git a/server/src/main/kotlin/hello/hello/adapters/persistence/database/adapters/UserAdapter.kt b/server/src/main/kotlin/hello/hello/adapters/persistence/database/adapters/UserAdapter.kt new file mode 100644 index 0000000..94269a0 --- /dev/null +++ b/server/src/main/kotlin/hello/hello/adapters/persistence/database/adapters/UserAdapter.kt @@ -0,0 +1,29 @@ +package hello.hello.adapters.persistence.database.adapters + +import hello.hello.adapters.persistence.database.entities.UserEntity +import hello.hello.adapters.persistence.database.entities.UserTable +import hello.hello.adapters.persistence.database.entities.toUser +import hello.hello.domain.models.User +import hello.hello.domain.ports.UserPort +import org.jetbrains.exposed.sql.and +import org.jetbrains.exposed.sql.transactions.transaction + +class UserAdapter: UserPort() { + override fun checkIfUserExists(name: String): Boolean = + transaction { findByName(name) != null } + + override fun checkLogin(name: String, password: String): User? = + transaction { UserEntity.find { (UserTable.name eq name) and (UserTable.password eq password) }.firstOrNull()?.toUser() } + + override fun create(argName: String, argPassword: String): User = + transaction { + UserEntity.new { + name = argName + password = argPassword + }.toUser() + } + + companion object { + internal fun findByName(name: String) = UserEntity.find { UserTable.name eq name }.firstOrNull() + } +} \ No newline at end of file diff --git a/server/src/main/kotlin/hello/hello/adapters/persistence/database/entities/CardEntity.kt b/server/src/main/kotlin/hello/hello/adapters/persistence/database/entities/CardEntity.kt new file mode 100644 index 0000000..692c93d --- /dev/null +++ b/server/src/main/kotlin/hello/hello/adapters/persistence/database/entities/CardEntity.kt @@ -0,0 +1,37 @@ +package hello.hello.adapters.persistence.database.entities + +import hello.hello.domain.models.Card +import org.jetbrains.exposed.dao.IntEntity +import org.jetbrains.exposed.dao.IntEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.dao.id.IntIdTable + + +object CardTable: IntIdTable(name = "cards") { + var mode = varchar("mode", 7) + var path = varchar("path", 120).nullable() + var category = varchar("category", 40).nullable() + var company = varchar("company", 40).nullable() + var name = varchar("name", 40).nullable() + var phone = varchar("phone", 12).nullable() + var email = varchar("email", 40).nullable() + var owner = reference("owner", UserTable) +} + +class CardEntity(id: EntityID): IntEntity(id) { + companion object : IntEntityClass(CardTable) + var mode by CardTable.mode + var path by CardTable.path + var category by CardTable.category + var company by CardTable.company + var name by CardTable.name + var phone by CardTable.phone + var email by CardTable.email + var owner by UserEntity referencedOn CardTable.owner +} + +fun CardEntity.toCard(): Card = + Card(id.value, mode, path, category, company, name, phone, email, owner.name) + +fun Card.toCardEntity(): CardEntity = + CardEntity.findById(id)!! diff --git a/server/src/main/kotlin/hello/hello/adapters/persistence/database/entities/TokenEntity.kt b/server/src/main/kotlin/hello/hello/adapters/persistence/database/entities/TokenEntity.kt new file mode 100644 index 0000000..a6e1dc1 --- /dev/null +++ b/server/src/main/kotlin/hello/hello/adapters/persistence/database/entities/TokenEntity.kt @@ -0,0 +1,31 @@ +package hello.hello.adapters.persistence.database.entities + +import hello.hello.domain.models.Token +import org.jetbrains.exposed.dao.Entity +import org.jetbrains.exposed.dao.EntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.dao.id.IdTable +import org.jetbrains.exposed.sql.javatime.timestamp +import java.util.* + +// TODO: this should be a UUIDTable +object TokenTable: IdTable(name = "tokens") { + val token = varchar("token", 40).entityId() + val name = reference("name", UserTable) + val creationDate = timestamp("creation_date") + + override val id = token +} + +class TokenEntity(id: EntityID): Entity(id) { + companion object : EntityClass(TokenTable) + var token by TokenTable.token + var name by UserEntity referencedOn TokenTable.name + var creationDate by TokenTable.creationDate +} + +fun TokenEntity.toToken(): Token = + Token(UUID.fromString(token.value), name.toUser(), creationDate) + +fun Token.toTokenEntity(): TokenEntity = + TokenEntity.findById(token.toString())!! diff --git a/server/src/main/kotlin/hello/hello/adapters/persistence/database/entities/UserEntity.kt b/server/src/main/kotlin/hello/hello/adapters/persistence/database/entities/UserEntity.kt new file mode 100644 index 0000000..2c79174 --- /dev/null +++ b/server/src/main/kotlin/hello/hello/adapters/persistence/database/entities/UserEntity.kt @@ -0,0 +1,25 @@ +package hello.hello.adapters.persistence.database.entities + +import hello.hello.domain.models.User +import org.jetbrains.exposed.dao.IntEntity +import org.jetbrains.exposed.dao.IntEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.dao.id.IntIdTable +import org.jetbrains.exposed.sql.and + +object UserTable: IntIdTable(name = "users") { + val name = varchar("name", 40).uniqueIndex() + val password = varchar("password", 40) +} + +class UserEntity(id: EntityID): IntEntity(id) { + companion object : IntEntityClass(UserTable) + var name by UserTable.name + var password by UserTable.password +} + +fun UserEntity.toUser(): User = + User(this.name, this.password) + +fun User.toUserEntity(): UserEntity = + UserEntity.find { (UserTable.name eq name) and (UserTable.password eq password) }.first() diff --git a/server/src/main/kotlin/hello/hello/domain/models/Card.kt b/server/src/main/kotlin/hello/hello/domain/models/Card.kt new file mode 100644 index 0000000..35da49c --- /dev/null +++ b/server/src/main/kotlin/hello/hello/domain/models/Card.kt @@ -0,0 +1,13 @@ +package hello.hello.domain.models + +data class Card( + var id: Int, + var mode: String, + var path: String?, + var category: String?, + var company: String?, + var name: String?, + var phone: String?, + var email: String?, + var owner: String +) diff --git a/server/src/main/kotlin/hello/hello/domain/models/Token.kt b/server/src/main/kotlin/hello/hello/domain/models/Token.kt new file mode 100644 index 0000000..21f2a34 --- /dev/null +++ b/server/src/main/kotlin/hello/hello/domain/models/Token.kt @@ -0,0 +1,10 @@ +package hello.hello.domain.models + +import java.time.Instant +import java.util.UUID + +data class Token( + var token: UUID, + val name: User, + var creationDate: Instant +) \ No newline at end of file diff --git a/server/src/main/kotlin/hello/hello/domain/models/User.kt b/server/src/main/kotlin/hello/hello/domain/models/User.kt new file mode 100644 index 0000000..b8a8371 --- /dev/null +++ b/server/src/main/kotlin/hello/hello/domain/models/User.kt @@ -0,0 +1,6 @@ +package hello.hello.domain.models + +data class User( + var name: String, + var password: String +) diff --git a/server/src/main/kotlin/hello/hello/domain/ports/CardPort.kt b/server/src/main/kotlin/hello/hello/domain/ports/CardPort.kt new file mode 100644 index 0000000..07b9f5c --- /dev/null +++ b/server/src/main/kotlin/hello/hello/domain/ports/CardPort.kt @@ -0,0 +1,17 @@ +package hello.hello.domain.ports + +import hello.hello.domain.models.Card + +abstract class CardPort { + abstract fun create(userName: String, mode: String, category: String?): Card? + + abstract fun read(cardId: Int): Card? + + abstract fun read(ownerName: String?): List? + + abstract fun search(id: Int?, profession: String?, ownerName: String?): List? + + abstract fun update(id: Int, company: String?, name: String?, phone: String?, email: String?, category: String?, mode: String?): Card? + + abstract fun updatePath(card: Card, path: String): Card +} \ No newline at end of file diff --git a/server/src/main/kotlin/hello/hello/domain/ports/TokenPort.kt b/server/src/main/kotlin/hello/hello/domain/ports/TokenPort.kt new file mode 100644 index 0000000..25685d3 --- /dev/null +++ b/server/src/main/kotlin/hello/hello/domain/ports/TokenPort.kt @@ -0,0 +1,8 @@ +package hello.hello.domain.ports + +import hello.hello.domain.models.Token +import hello.hello.domain.models.User + +abstract class TokenPort { + abstract fun create(user: User): Token +} \ No newline at end of file diff --git a/server/src/main/kotlin/hello/hello/domain/ports/UserPort.kt b/server/src/main/kotlin/hello/hello/domain/ports/UserPort.kt new file mode 100644 index 0000000..27dfcb4 --- /dev/null +++ b/server/src/main/kotlin/hello/hello/domain/ports/UserPort.kt @@ -0,0 +1,11 @@ +package hello.hello.domain.ports + +import hello.hello.domain.models.User + +abstract class UserPort { + abstract fun create(argName: String, argPassword: String): User + + abstract fun checkIfUserExists(name: String): Boolean + + abstract fun checkLogin(name: String, password: String): User? +} \ No newline at end of file diff --git a/server/src/main/kotlin/pishello/hello/api/CardEndpoint.kt b/server/src/main/kotlin/pishello/hello/api/CardEndpoint.kt deleted file mode 100644 index 28bae1c..0000000 --- a/server/src/main/kotlin/pishello/hello/api/CardEndpoint.kt +++ /dev/null @@ -1,105 +0,0 @@ -package pishello.hello.api - -import org.springframework.http.HttpStatus -import org.springframework.http.MediaType -import org.springframework.http.ResponseEntity -import org.springframework.web.bind.annotation.* -import org.springframework.web.multipart.MultipartFile -import pishello.hello.persistence.cloudStorage.PhotosStorage -import pishello.hello.persistence.database.ports.CardPort - -data class CardRequest(val id: Int, val mode: String?, val category: String?) -data class CardData(val id: Int, val company: String?, val name: String?, val phone: String?, val email: String?, val category: String?, val mode: String?) - -@RestController -@RequestMapping("/card") -class CardEndpoint(val cardPort: CardPort, val photosStorage: PhotosStorage) { - - @PostMapping - fun addCard(@RequestParam image: MultipartFile, @RequestParam ownerName: String): ResponseEntity { - val card = cardPort.createNewCard(ownerName, "PRIVATE", null) - return if (card != null) { - photosStorage.writeImage("cards/${card.id}.jpg", image.bytes) - cardPort.setPath(card, "cards/${card.id}.jpg") - ResponseEntity(HttpStatus.CREATED) - } else { - ResponseEntity(HttpStatus.NOT_FOUND) - } - } - - @PostMapping("/set") - fun setCard(@RequestBody request: CardRequest): ResponseEntity { - return if (cardPort.updateCard(request.id, request.mode, request.category) != null) { - ResponseEntity(HttpStatus.OK) - } else { - ResponseEntity(HttpStatus.NOT_FOUND) - } - } - - @GetMapping("/image", produces = [MediaType.IMAGE_JPEG_VALUE]) - fun getImage(@RequestParam id: Int): ResponseEntity { - val result = cardPort.findById(id) - return if (result?.path != null) { - val image = photosStorage.readImage(result.path!!) - return if (image != null) { - ResponseEntity(image, HttpStatus.OK) - } else { - ResponseEntity(HttpStatus.NOT_FOUND) - } - } else { - ResponseEntity(HttpStatus.NOT_FOUND) - } - } - - @PostMapping("/changedata", consumes = ["application/json"]) - fun editCard(@RequestBody request: CardData): ResponseEntity { - var company: String? - var name: String? - var phone: String? - var email: String? - var category: String? - var mode: String? - - if (request.company ==""){ - company = null - } - else{ - company = request.company - } - if (request.name ==""){ - name = null - } - else{ - name = request.name - } - if (request.phone ==""){ - phone = null - } - else{ - phone = request.phone - } - if (request.email ==""){ - email = null - } - else{ - email = request.email - } - if (request.category ==""){ - category = null - } - else{ - category = request.category - } - if (request.mode ==""){ - mode = null - } - else{ - mode = request.mode - } - return if (cardPort.updateData(request.id, company, name, phone, email, category, mode) != null) { - ResponseEntity(HttpStatus.OK) - } else { - ResponseEntity(HttpStatus.NOT_FOUND) - } - } -} \ No newline at end of file diff --git a/server/src/main/kotlin/pishello/hello/persistence/database/DataSource.kt b/server/src/main/kotlin/pishello/hello/persistence/database/DataSource.kt deleted file mode 100644 index a459a02..0000000 --- a/server/src/main/kotlin/pishello/hello/persistence/database/DataSource.kt +++ /dev/null @@ -1,21 +0,0 @@ -package pishello.hello.persistence.database - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.context.annotation.Bean -import org.springframework.core.env.Environment -import org.springframework.jdbc.datasource.DriverManagerDataSource -import javax.sql.DataSource - - -@Autowired -var env: Environment? = null - -@Bean -fun dataSource(): DataSource { - val dataSource = DriverManagerDataSource() - dataSource.setDriverClassName(env!!.getProperty("spring.jpa.database-platform")!!) - dataSource.url = env!!.getProperty("spring.datasource.url")!! -// dataSource.username = env!!.getProperty("user") -// dataSource.password = env!!.getProperty("password") - return dataSource -} \ No newline at end of file diff --git a/server/src/main/kotlin/pishello/hello/persistence/database/SQLDialect.kt b/server/src/main/kotlin/pishello/hello/persistence/database/SQLDialect.kt deleted file mode 100644 index 3da0e70..0000000 --- a/server/src/main/kotlin/pishello/hello/persistence/database/SQLDialect.kt +++ /dev/null @@ -1,136 +0,0 @@ -package pishello.hello.persistence.database - -import org.hibernate.dialect.Dialect -import org.hibernate.dialect.function.SQLFunctionTemplate -import org.hibernate.dialect.function.StandardSQLFunction -import org.hibernate.dialect.function.VarArgsSQLFunction -import org.hibernate.type.StringType -import java.sql.Types - - -class SQLDialect: Dialect() { - init { - registerColumnType(Types.BIT, "integer") - registerColumnType(Types.TINYINT, "tinyint") - registerColumnType(Types.SMALLINT, "smallint") - registerColumnType(Types.INTEGER, "integer") - registerColumnType(Types.BIGINT, "bigint") - registerColumnType(Types.FLOAT, "float") - registerColumnType(Types.REAL, "real") - registerColumnType(Types.DOUBLE, "double") - registerColumnType(Types.NUMERIC, "numeric") - registerColumnType(Types.DECIMAL, "decimal") - registerColumnType(Types.CHAR, "char") - registerColumnType(Types.VARCHAR, "varchar") - registerColumnType(Types.LONGVARCHAR, "longvarchar") - registerColumnType(Types.DATE, "date") - registerColumnType(Types.TIME, "time") - registerColumnType(Types.TIMESTAMP, "timestamp") - registerColumnType(Types.BINARY, "blob") - registerColumnType(Types.VARBINARY, "blob") - registerColumnType(Types.LONGVARBINARY, "blob") - // registerColumnType(Types.NULL, "null"); - registerColumnType(Types.BLOB, "blob") - registerColumnType(Types.CLOB, "clob") - registerColumnType(Types.BOOLEAN, "integer") - registerFunction("concat", VarArgsSQLFunction(StringType.INSTANCE, "", "||", "")) - registerFunction("mod", SQLFunctionTemplate(StringType.INSTANCE, "?1 % ?2")) - registerFunction("substr", StandardSQLFunction("substr", StringType.INSTANCE)) - registerFunction("substring", StandardSQLFunction("substr", StringType.INSTANCE)) - } - - fun supportsIdentityColumns(): Boolean { - return true - } - - fun hasDataTypeInIdentityColumn(): Boolean { - return false // As specify in NHibernate dialect - } - - // return "integer primary key autoincrement"; - val identityColumnString: String - get() =// return "integer primary key autoincrement"; - "integer" - - val identitySelectString: String - get() = "select last_insert_rowid()" - - override fun supportsLimit(): Boolean { - return true - } - - override fun getLimitString(query: String, hasOffset: Boolean): String { - return StringBuffer(query.length + 20).append(query).append(if (hasOffset) " limit ? offset ?" else " limit ?") - .toString() - } - - fun supportsTemporaryTables(): Boolean { - return true - } - - val createTemporaryTableString: String - get() = "create temporary table if not exists" - - fun dropTemporaryTableAfterUse(): Boolean { - return false - } - - override fun supportsCurrentTimestampSelection(): Boolean { - return true - } - - override fun isCurrentTimestampSelectStringCallable(): Boolean { - return false - } - - override fun getCurrentTimestampSelectString(): String { - return "select current_timestamp" - } - - override fun supportsUnionAll(): Boolean { - return true - } - - override fun hasAlterTable(): Boolean { - return false // As specify in NHibernate dialect - } - - override fun dropConstraints(): Boolean { - return false - } - - override fun getAddColumnString(): String { - return "add column" - } - - override fun getForUpdateString(): String { - return "" - } - - override fun supportsOuterJoinForUpdate(): Boolean { - return false - } - - override fun getDropForeignKeyString(): String { - throw UnsupportedOperationException("No drop foreign key syntax supported by SQLiteDialect") - } - - override fun getAddForeignKeyConstraintString( - constraintName: String, foreignKey: Array, referencedTable: String, - primaryKey: Array, referencesPrimaryKey: Boolean - ): String { - throw UnsupportedOperationException("No add foreign key syntax supported by SQLiteDialect") - } - - override fun getAddPrimaryKeyConstraintString(constraintName: String): String { - throw UnsupportedOperationException("No add primary key syntax supported by SQLiteDialect") - } - - override fun supportsIfExistsBeforeTableName(): Boolean { - return true - } - - override fun supportsCascadeDelete(): Boolean { - return false - } -} \ No newline at end of file diff --git a/server/src/main/kotlin/pishello/hello/persistence/database/entities/Card.kt b/server/src/main/kotlin/pishello/hello/persistence/database/entities/Card.kt deleted file mode 100644 index 731ce21..0000000 --- a/server/src/main/kotlin/pishello/hello/persistence/database/entities/Card.kt +++ /dev/null @@ -1,32 +0,0 @@ -package pishello.hello.persistence.database.entities - -import org.hibernate.Hibernate -import javax.persistence.* - -@Entity(name = "cards") -data class Card( - @Id - @GeneratedValue(strategy = GenerationType.TABLE) - val id: Int, - var mode: String, - var path: String?, - var category: String?, - var company: String?, - var name: String?, - var phone: String?, - var email: String?, - val owner: String // "FK" -) { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false - other as Card - - return id == other.id - } - - override fun hashCode(): Int = javaClass.hashCode() - - @Override - override fun toString(): String = this::class.simpleName + "(id = $id )" -} \ No newline at end of file diff --git a/server/src/main/kotlin/pishello/hello/persistence/database/entities/Token.kt b/server/src/main/kotlin/pishello/hello/persistence/database/entities/Token.kt deleted file mode 100644 index 5f870ec..0000000 --- a/server/src/main/kotlin/pishello/hello/persistence/database/entities/Token.kt +++ /dev/null @@ -1,31 +0,0 @@ -package pishello.hello.persistence.database.entities - -import org.hibernate.Hibernate -import java.sql.Timestamp -import javax.persistence.Entity -import javax.persistence.Id -import javax.persistence.JoinColumn -import javax.persistence.ManyToOne - -@Entity(name = "tokens") -data class Token( - @Id - val token: String, - @ManyToOne - @JoinColumn(name = "name") - val name: User, - val creationDate: Timestamp -) { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false - other as Token - - return token == other.token - } - - override fun hashCode(): Int = javaClass.hashCode() - - @Override - override fun toString(): String = this::class.simpleName + "(token = $token )" -} \ No newline at end of file diff --git a/server/src/main/kotlin/pishello/hello/persistence/database/entities/User.kt b/server/src/main/kotlin/pishello/hello/persistence/database/entities/User.kt deleted file mode 100644 index e88699f..0000000 --- a/server/src/main/kotlin/pishello/hello/persistence/database/entities/User.kt +++ /dev/null @@ -1,22 +0,0 @@ -package pishello.hello.persistence.database.entities - -import org.hibernate.Hibernate -import javax.persistence.Entity -import javax.persistence.Id - -@Entity(name = "users") -data class User( - @Id val name: String, - val password: String -) { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false - other as User - return name == other.name - } - - override fun hashCode(): Int = javaClass.hashCode() - - override fun toString(): String = this::class.simpleName + "(name = $name )" -} \ No newline at end of file diff --git a/server/src/main/kotlin/pishello/hello/persistence/database/ports/CardPort.kt b/server/src/main/kotlin/pishello/hello/persistence/database/ports/CardPort.kt deleted file mode 100644 index 5e78082..0000000 --- a/server/src/main/kotlin/pishello/hello/persistence/database/ports/CardPort.kt +++ /dev/null @@ -1,63 +0,0 @@ -package pishello.hello.persistence.database.ports - -import org.springframework.stereotype.Component -import pishello.hello.persistence.database.entities.Card -import pishello.hello.persistence.database.repositories.CardRepository -import pishello.hello.persistence.database.repositories.UserRepository - -@Component -class CardPort(val repository: CardRepository, val userRepository: UserRepository) { - fun searchCards(id: Int?, profession: String?, ownerName: String?): List? { - return when { - id != null -> repository.searchById(id) - profession != null -> repository.searchByProfession(profession) - ownerName != null -> repository.searchByOwnerName(ownerName) - else -> null - } - } - - fun searchOwnerCards(ownerName: String?): List? { - return ownerName?.let { repository.findByOwner(it) } - } - - fun findById(cardId: Int): Card? { - return repository.findById(cardId) - } - - fun createNewCard(userName: String, mode: String, category: String?): Card? { - userRepository.findByName(userName) ?: return null - val card = Card(0, mode, null, category, null, null, null, null, userName) - return repository.save(card) - } - - fun updateCard(id: Int, mode: String?, category: String?): Card? { - val card = repository.findById(id) ?: return null - if (mode != null) - card.mode = mode - if (category != null) - card.category = category - return repository.save(card) - } - - fun setPath(card: Card, path: String): Card? { - card.path = path - return repository.save(card) - } - - fun updateData(id: Int, company: String?, name: String?, phone: String?, email: String?, category: String?, mode: String?): Card? { - val card = repository.findById(id) ?: return null - if (company != null) - card.company = company - if (name != null) - card.name = name - if (phone != null) - card.phone = phone - if (email != null) - card.email = email - if (category != null) - card.category = category - if (mode != null) - card.mode = mode - return repository.save(card) - } -} \ No newline at end of file diff --git a/server/src/main/kotlin/pishello/hello/persistence/database/ports/TokenPort.kt b/server/src/main/kotlin/pishello/hello/persistence/database/ports/TokenPort.kt deleted file mode 100644 index 21c8422..0000000 --- a/server/src/main/kotlin/pishello/hello/persistence/database/ports/TokenPort.kt +++ /dev/null @@ -1,18 +0,0 @@ -package pishello.hello.persistence.database.ports - -import org.springframework.stereotype.Component -import pishello.hello.persistence.database.entities.Token -import pishello.hello.persistence.database.entities.User -import pishello.hello.persistence.database.repositories.TokenRepository -import java.sql.Timestamp -import java.time.Instant -import java.util.* - -@Component -class TokenPort(val repository: TokenRepository) { - fun createNewToken(userId: User): Token { - val token = Token(UUID.randomUUID().toString(), userId, Timestamp.from(Instant.now())) - repository.save(token) - return token - } -} \ No newline at end of file diff --git a/server/src/main/kotlin/pishello/hello/persistence/database/ports/UserPort.kt b/server/src/main/kotlin/pishello/hello/persistence/database/ports/UserPort.kt deleted file mode 100644 index d14289d..0000000 --- a/server/src/main/kotlin/pishello/hello/persistence/database/ports/UserPort.kt +++ /dev/null @@ -1,22 +0,0 @@ -package pishello.hello.persistence.database.ports - -import org.springframework.stereotype.Component -import pishello.hello.persistence.database.entities.User -import pishello.hello.persistence.database.repositories.UserRepository - -@Component -class UserPort(val repository: UserRepository) { - fun checkIfUserExists(username: String): Boolean { - return repository.findByName(username) != null - } - - fun checkLogin(username: String, password: String): User? { - return repository.findByNameAndPassword(username, password) - } - - fun createNewUser(username: String, password: String): User { - val user = User(username, password) - repository.save(user) - return user - } -} \ No newline at end of file diff --git a/server/src/main/kotlin/pishello/hello/persistence/database/repositories/CardRepository.kt b/server/src/main/kotlin/pishello/hello/persistence/database/repositories/CardRepository.kt deleted file mode 100644 index 23b499b..0000000 --- a/server/src/main/kotlin/pishello/hello/persistence/database/repositories/CardRepository.kt +++ /dev/null @@ -1,22 +0,0 @@ -package pishello.hello.persistence.database.repositories - -import org.springframework.data.jpa.repository.JpaRepository -import org.springframework.data.jpa.repository.Query -import org.springframework.data.repository.query.Param -import pishello.hello.persistence.database.entities.Card - -interface CardRepository: JpaRepository { - - @Query("SELECT * FROM CARDS C WHERE C.ID = :id AND C.MODE = :mode", nativeQuery = true) - fun searchById(@Param("id") id: Int?, @Param("mode") mode: String? = "PUBLIC"): List? - - @Query("SELECT * FROM CARDS C WHERE C.CATEGORY= :profession AND C.MODE = :mode", nativeQuery = true) - fun searchByProfession(@Param("profession") profession: String?, @Param("mode") mode: String? = "PUBLIC"): List? - - @Query("SELECT * FROM CARDS C WHERE C.OWNER= :ownerName AND C.MODE = :mode", nativeQuery = true) - fun searchByOwnerName(@Param("ownerName") ownerName: String?, @Param("mode") mode: String? = "PUBLIC"): List? - - fun findByOwner(@Param("ownerName") ownerName: String):List? - - fun findById(id: Int): Card? -} \ No newline at end of file diff --git a/server/src/main/kotlin/pishello/hello/persistence/database/repositories/TokenRepository.kt b/server/src/main/kotlin/pishello/hello/persistence/database/repositories/TokenRepository.kt deleted file mode 100644 index be88a28..0000000 --- a/server/src/main/kotlin/pishello/hello/persistence/database/repositories/TokenRepository.kt +++ /dev/null @@ -1,10 +0,0 @@ -package pishello.hello.persistence.database.repositories - -import org.springframework.data.repository.CrudRepository -import pishello.hello.persistence.database.entities.Token -import pishello.hello.persistence.database.entities.User - - -interface TokenRepository: CrudRepository { - fun findByName(name: User): Token? -} \ No newline at end of file diff --git a/server/src/main/kotlin/pishello/hello/persistence/database/repositories/UserRepository.kt b/server/src/main/kotlin/pishello/hello/persistence/database/repositories/UserRepository.kt deleted file mode 100644 index 0546ac6..0000000 --- a/server/src/main/kotlin/pishello/hello/persistence/database/repositories/UserRepository.kt +++ /dev/null @@ -1,10 +0,0 @@ -package pishello.hello.persistence.database.repositories - -import org.springframework.data.repository.CrudRepository -import pishello.hello.persistence.database.entities.User - - -interface UserRepository: CrudRepository { - fun findByName(name: String): User? - fun findByNameAndPassword(name: String, password: String): User? -} \ No newline at end of file diff --git a/server/src/main/resources/application-test.properties b/server/src/main/resources/application-test.properties index cf20c1f..4b94c30 100644 --- a/server/src/main/resources/application-test.properties +++ b/server/src/main/resources/application-test.properties @@ -1,2 +1 @@ -spring.jpa.hibernate.ddl-auto = create-drop spring.datasource.url = jdbc:sqlite:src/main/resources/test.db \ No newline at end of file diff --git a/server/src/main/resources/application.properties b/server/src/main/resources/application.properties index 4102ed4..eadb8c7 100644 --- a/server/src/main/resources/application.properties +++ b/server/src/main/resources/application.properties @@ -1,6 +1,3 @@ -spring.jpa.database-platform = pishello.hello.persistence.database.SQLDialect -spring.jpa.hibernate.ddl-auto = none - spring.datasource.url = jdbc:sqlite:src/main/resources/main.db spring.datasource.driver-class-name = org.sqlite.JDBC spring.servlet.multipart.max-file-size=128MB diff --git a/server/src/main/resources/main.db b/server/src/main/resources/main.db new file mode 100644 index 0000000..e7eab26 Binary files /dev/null and b/server/src/main/resources/main.db differ diff --git a/server/src/main/resources/test.db b/server/src/main/resources/test.db new file mode 100644 index 0000000..2795803 Binary files /dev/null and b/server/src/main/resources/test.db differ diff --git a/server/src/main/sql/create.sql b/server/src/main/sql/create.sql deleted file mode 100644 index 6de5999..0000000 --- a/server/src/main/sql/create.sql +++ /dev/null @@ -1,28 +0,0 @@ -create table users -( - name text not null constraint users_pk primary key, - password text not null -); - -create table tokens -( - token text not null constraint token_pk primary key, - name text constraint name references users on update cascade, - creationDate timestamp not null -); - -create table cards -( - id integer not null constraint card_pk primary key autoincrement, - mode text not null, - path text, - category text, - company text, - name text, - phone text, - email text, - owner integer not null references users -); - -create unique index users_name_uindex on users (name); -create unique index token_token_uindex on tokens (token); \ No newline at end of file diff --git a/server/src/main/sql/insert.sql b/server/src/main/sql/insert.sql deleted file mode 100644 index 3ec0b4d..0000000 --- a/server/src/main/sql/insert.sql +++ /dev/null @@ -1,4 +0,0 @@ -INSERT INTO cards(mode, path) VALUES('PRIVATE', 'test/photo1'); -INSERT INTO cards(mode, path, category) VALUES('PUBLIC', 'test/photo2', 'lawyer'); -INSERT INTO cards(mode, path, category) VALUES('PUBLIC', 'test/photo3', 'lawyer'); -INSERT INTO cards(mode, path, category) VALUES('PUBLIC', 'test/photo4', 'cook'); diff --git a/server/src/test/kotlin/pishello/hello/TestUtilities.kt b/server/src/test/kotlin/hello/hello/TestUtilities.kt similarity index 56% rename from server/src/test/kotlin/pishello/hello/TestUtilities.kt rename to server/src/test/kotlin/hello/hello/TestUtilities.kt index f07f758..ce367db 100644 --- a/server/src/test/kotlin/pishello/hello/TestUtilities.kt +++ b/server/src/test/kotlin/hello/hello/TestUtilities.kt @@ -1,11 +1,24 @@ -package pishello.hello +package hello.hello +import hello.hello.adapters.persistence.database.create +import hello.hello.adapters.persistence.database.drop +import hello.hello.adapters.persistence.database.init +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.core.env.Environment import org.springframework.core.io.ClassPathResource import org.springframework.mock.web.MockMultipartFile +import org.springframework.test.context.ActiveProfiles import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders -open class TestUtilities { +@SpringBootTest +@AutoConfigureMockMvc +@ActiveProfiles("test") +class TestUtilities { fun correctUserName() = "test_user" @@ -18,10 +31,7 @@ open class TestUtilities { fun incorrectAuthRequestData(): String = """{ "name": "test_user", "password": "no, this is not a hash" }""" - fun correctSetRequestData(id: Int, mode: String?, category: String?): String = - """{ "id": $id, "mode": "$mode", "category": "$category" }""" - - fun correctEditRequestData(id: Int, company: String?, name: String?, phone: String?, email: String?, category: String?, mode: String?): String = + fun correctSetRequestData(id: Int, company: String?, name: String?, phone: String?, email: String?, category: String?, mode: String?): String = """{ "id": $id, "company": "$company", "name": "$name", "phone": "$phone", "email": "$email", "category": "$category", "mode": "$mode"}""" @@ -43,15 +53,23 @@ open class TestUtilities { .param("ownerName", correctUserName())) } - fun setCard(mockMvc: MockMvc, id: Int, mode: String?, category: String?) { + fun setCard(mockMvc: MockMvc, id: Int, company: String? = null, name: String? = null, phone: String? = null, email: String? = null, category: String? = null, mode: String? = null) { mockMvc.perform(MockMvcRequestBuilders.post("/card/set") .header("Content-Type", "application/json") - .content(correctSetRequestData(id, mode, category))) + .content(correctSetRequestData(id, company, name, phone, email, category, mode))) } - fun editCard(mockMvc: MockMvc, id: Int, company: String?, name: String?, phone: String?, email: String?, category: String?, mode: String?) { - mockMvc.perform(MockMvcRequestBuilders.post("/card/changedata") - .header("Content-Type", "application/json") - .content(correctEditRequestData(id, company, name, phone, email, category, mode))) + @Autowired + var env: Environment? = null + + @BeforeEach + fun setup() { + init(env!!) + create() + } + + @AfterEach + fun cleanUp() { + drop() } } \ No newline at end of file diff --git a/server/src/test/kotlin/pishello/hello/api/AuthEndpointTests.kt b/server/src/test/kotlin/hello/hello/api/AuthEndpointTests.kt similarity index 61% rename from server/src/test/kotlin/pishello/hello/api/AuthEndpointTests.kt rename to server/src/test/kotlin/hello/hello/api/AuthEndpointTests.kt index d4eacf4..69b7aa2 100644 --- a/server/src/test/kotlin/pishello/hello/api/AuthEndpointTests.kt +++ b/server/src/test/kotlin/hello/hello/api/AuthEndpointTests.kt @@ -1,27 +1,16 @@ -package pishello.hello.api +package hello.hello.api import org.hamcrest.Matchers.containsString import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.test.annotation.DirtiesContext -import org.springframework.test.context.ActiveProfiles import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status -import pishello.hello.TestUtilities +import hello.hello.TestUtilities - -@SpringBootTest -@AutoConfigureMockMvc -@ActiveProfiles("test") -@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) -class AuthEndpointTests(@Autowired val mockMvc: MockMvc) { - - val util = TestUtilities() +class AuthEndpointTests(@Autowired val mockMvc: MockMvc): TestUtilities() { @Test fun contextLoads() { } @@ -29,7 +18,7 @@ class AuthEndpointTests(@Autowired val mockMvc: MockMvc) { @Test fun shouldAcknowledgeThatThereIsNoSuchUser() { mockMvc.perform(get("/check") - .param("name", util.correctUserName())) + .param("name", correctUserName())) .andExpect(status().isOk) } @@ -37,43 +26,43 @@ class AuthEndpointTests(@Autowired val mockMvc: MockMvc) { fun shouldRegisterUser() { mockMvc.perform(post("/register") .header("Content-Type", "application/json") - .content(util.correctAuthRequestData())) + .content(correctAuthRequestData())) .andExpect(status().isCreated) } @Test fun shouldAcknowledgeThatSuchUserAlreadyExists() { - util.createUser(mockMvc) + createUser(mockMvc) mockMvc.perform(get("/check") - .param("name", util.correctUserName())) + .param("name", correctUserName())) .andExpect(status().isConflict) } @Test fun shouldFailToRegisterTheSameUser() { - util.createUser(mockMvc) + createUser(mockMvc) mockMvc.perform(post("/register") .header("Content-Type", "application/json") - .content(util.correctAuthRequestData())) + .content(correctAuthRequestData())) .andExpect(status().isConflict) } @Test fun shouldLoginProperly() { - util.createUser(mockMvc) + createUser(mockMvc) mockMvc.perform(post("/login") .header("Content-Type", "application/json") - .content(util.correctAuthRequestData())) + .content(correctAuthRequestData())) .andExpect(status().isOk) .andExpect(content().string(containsString("token"))) } @Test fun shouldFailToLogin() { - util.createUser(mockMvc) + createUser(mockMvc) mockMvc.perform(post("/login") .header("Content-Type", "application/json") - .content(util.incorrectAuthRequestData())) + .content(incorrectAuthRequestData())) .andExpect(status().isForbidden) } } diff --git a/server/src/test/kotlin/pishello/hello/api/CardEndpointTests.kt b/server/src/test/kotlin/hello/hello/api/CardEndpointTests.kt similarity index 68% rename from server/src/test/kotlin/pishello/hello/api/CardEndpointTests.kt rename to server/src/test/kotlin/hello/hello/api/CardEndpointTests.kt index c8ebb43..e1e0078 100644 --- a/server/src/test/kotlin/pishello/hello/api/CardEndpointTests.kt +++ b/server/src/test/kotlin/hello/hello/api/CardEndpointTests.kt @@ -1,22 +1,14 @@ -package pishello.hello.api +package hello.hello.api import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.test.annotation.DirtiesContext -import org.springframework.test.context.ActiveProfiles import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders import org.springframework.test.web.servlet.result.MockMvcResultMatchers -import pishello.hello.TestUtilities +import hello.hello.TestUtilities // TODO: change the bucket in GCS to not use the same as PROD -@SpringBootTest -@AutoConfigureMockMvc -@ActiveProfiles("test") -@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) class CardEndpointTests(@Autowired val mockMvc: MockMvc): TestUtilities() { @Test @@ -29,6 +21,15 @@ class CardEndpointTests(@Autowired val mockMvc: MockMvc): TestUtilities() { .andExpect(MockMvcResultMatchers.status().isCreated) } + @Test + fun shouldNotCreateCardForNonExistingUser() { + mockMvc + .perform(MockMvcRequestBuilders.multipart("/card") + .file(correctPutCardImageData()) + .param("ownerName", correctUserName())) + .andExpect(MockMvcResultMatchers.status().isNotFound) + } + @Test fun shouldSetCard() { createUser(mockMvc) @@ -36,16 +37,17 @@ class CardEndpointTests(@Autowired val mockMvc: MockMvc): TestUtilities() { mockMvc .perform(MockMvcRequestBuilders.post("/card/set") .header("Content-Type", "application/json") - .content(correctSetRequestData(1, null, null))) + .content(correctSetRequestData(1, "company", "name", null, null, null, null))) .andExpect(MockMvcResultMatchers.status().isOk) } @Test - fun shouldNotCreateCardForNonExistingUser() { + fun shouldNotSetCardForNonExistingCard() { + createUser(mockMvc) mockMvc - .perform(MockMvcRequestBuilders.multipart("/card") - .file(correctPutCardImageData()) - .param("ownerName", correctUserName())) + .perform(MockMvcRequestBuilders.post("/card/set") + .header("Content-Type", "application/json") + .content(correctSetRequestData(1, "company", "name", null, null, null, null))) .andExpect(MockMvcResultMatchers.status().isNotFound) } @@ -60,13 +62,11 @@ class CardEndpointTests(@Autowired val mockMvc: MockMvc): TestUtilities() { } @Test - fun shouldEditCard() { + fun shouldNotGetCardImageForNonExistingCard() { createUser(mockMvc) - createCard(mockMvc) mockMvc - .perform(MockMvcRequestBuilders.post("/card/changedata") - .header("Content-Type", "application/json") - .content(correctEditRequestData(1, "company", "name",null ,null, null, null))) - .andExpect(MockMvcResultMatchers.status().isOk) + .perform(MockMvcRequestBuilders.get("/card/image") + .param("id", "1")) + .andExpect(MockMvcResultMatchers.status().isNotFound) } } \ No newline at end of file diff --git a/server/src/test/kotlin/pishello/hello/api/RootEndpointTests.kt b/server/src/test/kotlin/hello/hello/api/RootEndpointTests.kt similarity index 62% rename from server/src/test/kotlin/pishello/hello/api/RootEndpointTests.kt rename to server/src/test/kotlin/hello/hello/api/RootEndpointTests.kt index a0fc77a..63537cf 100644 --- a/server/src/test/kotlin/pishello/hello/api/RootEndpointTests.kt +++ b/server/src/test/kotlin/hello/hello/api/RootEndpointTests.kt @@ -1,20 +1,14 @@ -package pishello.hello.api +package hello.hello.api +import hello.hello.TestUtilities import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.test.context.ActiveProfiles import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status - -@SpringBootTest -@AutoConfigureMockMvc -@ActiveProfiles("test") -class RootEndpointTests(@Autowired val mockMvc: MockMvc) { +class RootEndpointTests(@Autowired val mockMvc: MockMvc): TestUtilities() { @Test fun contextLoads() { } diff --git a/server/src/test/kotlin/pishello/hello/api/SearchEndpointTests.kt b/server/src/test/kotlin/hello/hello/api/SearchEndpointTests.kt similarity index 55% rename from server/src/test/kotlin/pishello/hello/api/SearchEndpointTests.kt rename to server/src/test/kotlin/hello/hello/api/SearchEndpointTests.kt index ff866f5..32f2acd 100644 --- a/server/src/test/kotlin/pishello/hello/api/SearchEndpointTests.kt +++ b/server/src/test/kotlin/hello/hello/api/SearchEndpointTests.kt @@ -1,47 +1,37 @@ -package pishello.hello.api +package hello.hello.api import org.junit.jupiter.api.Test import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.CsvSource import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.test.annotation.DirtiesContext -import org.springframework.test.context.ActiveProfiles import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders import org.springframework.test.web.servlet.result.MockMvcResultMatchers -import pishello.hello.TestUtilities +import hello.hello.TestUtilities -@SpringBootTest -@AutoConfigureMockMvc -@ActiveProfiles("test") -@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) -class SearchEndpointTests(@Autowired val mockMvc: MockMvc) { - - val util = TestUtilities() +class SearchEndpointTests(@Autowired val mockMvc: MockMvc): TestUtilities() { @ParameterizedTest @CsvSource("id,1", "profession,lawyer", "ownername,test_user") fun shouldSearchCardsByParam(paramName: String, paramValue: String) { - util.createUser(mockMvc) - util.createCard(mockMvc) - util.setCard(mockMvc, 1, "PUBLIC", "lawyer") + createUser(mockMvc) + createCard(mockMvc) + setCard(mockMvc, 1, mode = "PUBLIC", category = "lawyer") mockMvc .perform(MockMvcRequestBuilders.get("/search") .param(paramName, paramValue)) .andExpect(MockMvcResultMatchers.status().isOk) - .andExpect(MockMvcResultMatchers.content().json(util.correctSearchByIdRequestData())) + .andExpect(MockMvcResultMatchers.content().json(correctSearchByIdRequestData())) } @Test fun shouldReturnUserCards() { - util.createUser(mockMvc) - util.createCard(mockMvc) - util.setCard(mockMvc, 1, "PUBLIC", "lawyer") + createUser(mockMvc) + createCard(mockMvc) + setCard(mockMvc, 1, mode = "PUBLIC", category = "lawyer") mockMvc .perform(MockMvcRequestBuilders.get("/test_user/cards")) .andExpect(MockMvcResultMatchers.status().isOk) - .andExpect(MockMvcResultMatchers.content().json(util.correctSearchByIdRequestData())) + .andExpect(MockMvcResultMatchers.content().json(correctSearchByIdRequestData())) } } \ No newline at end of file